diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caf97abf78d9e..26e589c092eda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,7 @@ name: CI - "**" permissions: contents: read + packages: write defaults: run: shell: bash @@ -42,6 +43,7 @@ jobs: CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" + DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" CACHE_DOMAIN: ci-caches.rust-lang.org @@ -172,6 +174,7 @@ jobs: CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" + DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 DEPLOY_BUCKET: rust-lang-ci2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" @@ -291,7 +294,7 @@ jobs: - name: x86_64-gnu-integration env: CI_ONLY_WHEN_CHANNEL: nightly - os: ubuntu-20.04-16core-64gb + os: ubuntu-20.04-8core-32gb - name: x86_64-gnu-debug os: ubuntu-20.04-8core-32gb env: {} @@ -316,7 +319,7 @@ jobs: - name: dist-x86_64-apple env: SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin" - RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin" + RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 SELECT_XCODE: /Applications/Xcode_13.4.1.app @@ -329,7 +332,7 @@ jobs: - name: dist-apple-various env: SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim" - RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 SELECT_XCODE: /Applications/Xcode_13.4.1.app @@ -340,7 +343,7 @@ jobs: - name: x86_64-apple-1 env: SCRIPT: "./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 @@ -351,7 +354,7 @@ jobs: - name: x86_64-apple-2 env: SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 @@ -361,8 +364,8 @@ jobs: os: macos-13 - name: dist-aarch64-apple env: - SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false" + SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin" + RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_13.4.1.app USE_XCODE_CLANG: 1 @@ -372,8 +375,20 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - JEMALLOC_SYS_WITH_LG_PAGE: 14 - os: macos-13 + os: macos-14 + - 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_13.4.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + os: macos-14 - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -554,6 +569,7 @@ jobs: CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" + DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 DEPLOY_BUCKET: rust-lang-ci2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" diff --git a/.mailmap b/.mailmap index d70a9f2aed684..f37ac7609e00c 100644 --- a/.mailmap +++ b/.mailmap @@ -129,7 +129,7 @@ Clement Miao Clément Renault Cliff Dyer Clinton Ryan -Corey Richardson Elaine "See More" Nemo +ember arlynx Crazycolorz5 csmoe <35686186+csmoe@users.noreply.github.com> Cyryl Płotnicki diff --git a/Cargo.lock b/Cargo.lock index f5ce875ccd428..29c8c7ef00404 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "once_cell", @@ -212,9 +212,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "askama" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" dependencies = [ "askama_derive", "askama_escape", @@ -222,14 +222,14 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.12.1" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" dependencies = [ + "askama_parser", "basic-toml", "mime", "mime_guess", - "nom", "proc-macro2", "quote", "serde", @@ -242,6 +242,15 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -373,9 +382,9 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -587,11 +596,11 @@ dependencies = [ name = "clippy_dev" version = "0.0.1" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick 1.0.2", "clap", "indoc", "itertools", - "opener 0.5.2", + "opener", "shell-escape", "walkdir", ] @@ -601,7 +610,7 @@ name = "clippy_lints" version = "0.1.77" dependencies = [ "arrayvec", - "cargo_metadata 0.15.4", + "cargo_metadata 0.18.0", "clippy_config", "clippy_utils", "declare_clippy_lint", @@ -878,12 +887,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1259,7 +1268,6 @@ name = "error_index_generator" version = "0.0.0" dependencies = [ "mdbook", - "rustc_error_codes", ] [[package]] @@ -2161,9 +2169,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" dependencies = [ "rustc-std-workspace-core", ] @@ -2187,16 +2195,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.1" @@ -2352,7 +2350,7 @@ dependencies = [ "log", "memchr", "once_cell", - "opener 0.6.1", + "opener", "pathdiff", "pulldown-cmark", "regex", @@ -2479,7 +2477,7 @@ dependencies = [ "lazy_static", "libc", "libffi", - "libloading 0.8.1", + "libloading", "log", "measureme", "rand", @@ -2522,14 +2520,13 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nix" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "libc", - "static_assertions", ] [[package]] @@ -2598,9 +2595,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "compiler_builtins", "crc32fast", @@ -2628,16 +2625,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "opener" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" -dependencies = [ - "bstr", - "winapi", -] - [[package]] name = "opener" version = "0.6.1" @@ -2651,11 +2638,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -2683,9 +2670,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -3016,11 +3003,11 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "memchr", "unicase", ] @@ -3665,10 +3652,10 @@ version = "0.0.0" dependencies = [ "arrayvec", "bitflags 2.4.1", + "either", "elsa", "ena", "indexmap", - "itertools", "jobserver", "libc", "measureme", @@ -3713,7 +3700,6 @@ dependencies = [ "rustc_codegen_ssa", "rustc_const_eval", "rustc_data_structures", - "rustc_error_codes", "rustc_errors", "rustc_expand", "rustc_feature", @@ -3786,9 +3772,11 @@ dependencies = [ "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", + "rustc_error_codes", "rustc_error_messages", "rustc_fluent_macro", "rustc_hir", + "rustc_index", "rustc_lint_defs", "rustc_macros", "rustc_serialize", @@ -4005,7 +3993,7 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ - "libloading 0.7.4", + "libloading", "rustc-rayon", "rustc-rayon-core", "rustc_ast", @@ -4135,7 +4123,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "bitflags 2.4.1", - "libloading 0.7.4", + "libloading", "odht", "rustc_ast", "rustc_attr", @@ -4354,7 +4342,6 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "derivative", "rustc-hash", "rustc_apfloat", "rustc_arena", @@ -4799,12 +4786,12 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ruzstd" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" dependencies = [ "byteorder", - "thiserror-core", + "derive_more", "twox-hash", ] @@ -5334,6 +5321,7 @@ version = "0.0.0" dependencies = [ "core", "getopts", + "libc", "panic_abort", "panic_unwind", "std", @@ -5354,9 +5342,9 @@ dependencies = [ [[package]] name = "thin-vec" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" @@ -5367,26 +5355,6 @@ dependencies = [ "thiserror-impl", ] -[[package]] -name = "thiserror-core" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" -dependencies = [ - "thiserror-core-impl", -] - -[[package]] -name = "thiserror-core-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "thiserror-impl" version = "1.0.47" @@ -5759,9 +5727,9 @@ dependencies = [ [[package]] name = "unic-langid" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" +checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516" dependencies = [ "unic-langid-impl", "unic-langid-macros", @@ -5769,18 +5737,18 @@ dependencies = [ [[package]] name = "unic-langid-impl" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" +checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6" dependencies = [ "tinystr", ] [[package]] name = "unic-langid-macros" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe" +checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec" dependencies = [ "proc-macro-hack", "tinystr", @@ -5790,13 +5758,13 @@ dependencies = [ [[package]] name = "unic-langid-macros-impl" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8" +checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" dependencies = [ "proc-macro-hack", "quote", - "syn 1.0.109", + "syn 2.0.32", "unic-langid-impl", ] @@ -6153,6 +6121,15 @@ dependencies = [ "windows-targets 0.48.1", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -6183,6 +6160,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6195,6 +6187,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -6207,6 +6205,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -6219,6 +6223,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -6231,6 +6241,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -6243,6 +6259,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -6255,6 +6277,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -6267,6 +6295,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.4.7" @@ -6373,18 +6407,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.28" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6f15f7ade05d2a4935e34a457b936c23dc70a05cc1d97133dc99e7a3fe0f0e" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.28" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbbad221e3f78500350ecbd7dfa4e63ef945c05f4c61cb7f4d3f84cd0bba649b" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", diff --git a/README.md b/README.md index da9e3556b4cac..6d6383351caf7 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ If you wish to _contribute_ to the compiler, you should read Table of Contents - [Quick Start](#quick-start) +- [Installing from Source](#installing-from-source) - [Getting Help](#getting-help) - [Contributing](#contributing) - [License](#license) @@ -29,9 +30,10 @@ Read ["Installation"] from [The Book]. ["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html [The Book]: https://doc.rust-lang.org/book/index.html -## Installing from source +## Installing from Source -If you really want to install from source (though this is not recommended), see [INSTALL.md](INSTALL.md). +If you really want to install from source (though this is not recommended), see +[INSTALL.md](INSTALL.md). ## Getting Help diff --git a/RELEASES.md b/RELEASES.md index 3fb74b52292c1..038a83cde84d6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,96 @@ +Version 1.76.0 (2024-02-08) +========================== + + + +Language +-------- +- [Document Rust ABI compatibility between various types](https://github.com/rust-lang/rust/pull/115476/) +- [Also: guarantee that char and u32 are ABI-compatible](https://github.com/rust-lang/rust/pull/118032/) +- [Warn against ambiguous wide pointer comparisons](https://github.com/rust-lang/rust/pull/117758/) + + + +Compiler +-------- +- [Lint pinned `#[must_use]` pointers (in particular, `Box` where `T` is `#[must_use]`) in `unused_must_use`.](https://github.com/rust-lang/rust/pull/118054/) +- [Soundness fix: fix computing the offset of an unsized field in a packed struct](https://github.com/rust-lang/rust/pull/118540/) +- [Soundness fix: fix dynamic size/align computation logic for packed types with dyn Trait tail](https://github.com/rust-lang/rust/pull/118538/) +- [Add `$message_type` field to distinguish json diagnostic outputs](https://github.com/rust-lang/rust/pull/115691/) +- [Enable Rust to use the EHCont security feature of Windows](https://github.com/rust-lang/rust/pull/118013/) +- [Add tier 3 {x86_64,i686}-win7-windows-msvc targets](https://github.com/rust-lang/rust/pull/118150/) +- [Add tier 3 aarch64-apple-watchos target](https://github.com/rust-lang/rust/pull/119074/) +- [Add tier 3 arm64e-apple-ios & arm64e-apple-darwin targets](https://github.com/rust-lang/rust/pull/115526/) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- +- [Add a column number to `dbg!()`](https://github.com/rust-lang/rust/pull/114962/) +- [Add `std::hash::{DefaultHasher, RandomState}` exports](https://github.com/rust-lang/rust/pull/115694/) +- [Fix rounding issue with exponents in fmt](https://github.com/rust-lang/rust/pull/116301/) +- [Add T: ?Sized to `RwLockReadGuard` and `RwLockWriteGuard`'s Debug impls.](https://github.com/rust-lang/rust/pull/117138/) +- [Windows: Allow `File::create` to work on hidden files](https://github.com/rust-lang/rust/pull/116438/) + + + +Stabilized APIs +--------------- + +- [`Arc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.unwrap_or_clone) +- [`Rc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.unwrap_or_clone) +- [`Result::inspect`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect) +- [`Result::inspect_err`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect_err) +- [`Option::inspect`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.inspect) +- [`type_name_of_val`](https://doc.rust-lang.org/stable/std/any/fn.type_name_of_val.html) +- [`std::hash::{DefaultHasher, RandomState}`](https://doc.rust-lang.org/stable/std/hash/index.html#structs) + These were previously available only through `std::collections::hash_map`. +- [`ptr::{from_ref, from_mut}`](https://doc.rust-lang.org/stable/std/ptr/fn.from_ref.html) +- [`ptr::addr_eq`](https://doc.rust-lang.org/stable/std/ptr/fn.addr_eq.html) + + + +Cargo +----- + +See [Cargo release notes](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-176-2024-02-08). + + + +Rustdoc +------- + +- [Don't merge cfg and doc(cfg) attributes for re-exports](https://github.com/rust-lang/rust/pull/113091/) +- [rustdoc: allow resizing the sidebar / hiding the top bar](https://github.com/rust-lang/rust/pull/115660/) +- [rustdoc-search: add support for traits and associated types](https://github.com/rust-lang/rust/pull/116085/) +- [rustdoc: Add highlighting for comments in items declaration](https://github.com/rust-lang/rust/pull/117869/) + + + +Compatibility Notes +------------------- +- [Add allow-by-default lint for unit bindings](https://github.com/rust-lang/rust/pull/112380/) + This is expected to be upgraded to a warning by default in a future Rust + release. Some macros emit bindings with type `()` with user-provided spans, + which means that this lint will warn for user code. +- [Remove x86_64-sun-solaris target.](https://github.com/rust-lang/rust/pull/118091/) +- [Remove asmjs-unknown-emscripten target](https://github.com/rust-lang/rust/pull/117338/) +- [Report errors in jobserver inherited through environment variables](https://github.com/rust-lang/rust/pull/113730/) + This [may warn](https://github.com/rust-lang/rust/issues/120515) on benign problems too. +- [Update the minimum external LLVM to 16.](https://github.com/rust-lang/rust/pull/117947/) +- [Improve `print_tts`](https://github.com/rust-lang/rust/pull/114571/) + This change can break some naive manual parsing of token trees in proc macro + code which expect a particular structure after `.to_string()`, rather than just arbitrary Rust code. +- [Make `IMPLIED_BOUNDS_ENTAILMENT` into a hard error from a lint](https://github.com/rust-lang/rust/pull/117984/) +- [Vec's allocation behavior was changed when collecting some iterators](https://github.com/rust-lang/rust/pull/110353) + Allocation behavior is currently not specified, nevertheless changes can be surprising. + See [`impl FromIterator for Vec`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#impl-FromIterator%3CT%3E-for-Vec%3CT%3E) + for more details. +- [Properly reject `default` on free const items](https://github.com/rust-lang/rust/pull/117818/) + Version 1.75.0 (2023-12-28) ========================== diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 621516af9c053..90ddeec4bc7a4 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -484,6 +484,19 @@ impl DroplessArena { } } + /// Used by `Lift` to check whether this slice is allocated + /// in this arena. + #[inline] + pub fn contains_slice(&self, slice: &[T]) -> bool { + for chunk in self.chunks.borrow_mut().iter_mut() { + let ptr = slice.as_ptr().cast::().cast_mut(); + if chunk.start() <= ptr && chunk.end() >= ptr { + return true; + } + } + false + } + /// Allocates a string slice that is copied into the `DroplessArena`, returning a /// reference to it. Will panic if passed an empty string. /// diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d0d98eb3d62d1..296a570de6b33 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -27,6 +27,7 @@ pub use UnsafeSource::*; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; +use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; @@ -290,12 +291,16 @@ pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] pub struct TraitBoundModifiers { pub constness: BoundConstness, + pub asyncness: BoundAsyncness, pub polarity: BoundPolarity, } impl TraitBoundModifiers { - pub const NONE: Self = - Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; + pub const NONE: Self = Self { + constness: BoundConstness::Never, + asyncness: BoundAsyncness::Normal, + polarity: BoundPolarity::Positive, + }; } /// The AST represents all type param bounds as types. @@ -1833,7 +1838,7 @@ pub enum LitKind { /// A character literal (`'a'`). Char(char), /// An integer literal (`1`). - Int(u128, LitIntType), + Int(Pu128, LitIntType), /// A float literal (`1.0`, `1f64` or `1E10f64`). The pre-suffix part is /// stored as a symbol rather than `f64` so that `LitKind` can impl `Eq` /// and `Hash`. @@ -2561,6 +2566,25 @@ impl BoundConstness { } } +/// The asyncness of a trait bound. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(HashStable_Generic)] +pub enum BoundAsyncness { + /// `Type: Trait` + Normal, + /// `Type: async Trait` + Async(Span), +} + +impl BoundAsyncness { + pub fn as_str(self) -> &'static str { + match self { + Self::Normal => "", + Self::Async(_) => "async", + } + } +} + #[derive(Clone, Encodable, Decodable, Debug)] pub enum FnRetTy { /// Returns type is not specified. @@ -3299,7 +3323,7 @@ mod size_asserts { static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItemKind, 24); static_assert_size!(GenericArg, 24); - static_assert_size!(GenericBound, 72); + static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 136); static_assert_size!(Item, 136); diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 7e713a49a8cfa..76d838308b461 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -13,13 +13,11 @@ #![feature(rustdoc_internals)] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(const_trait_impl)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(stmt_expr_attributes)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index fbae496458813..aaeb1bb9bff82 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -3,8 +3,7 @@ use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; use crate::token::{self, Token}; use rustc_lexer::unescape::{ - byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, - Mode, + byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode, }; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -48,6 +47,9 @@ impl LitKind { return Err(LitError::InvalidSuffix); } + // For byte/char/string literals, chars and escapes have already been + // checked in the lexer (in `cook_lexer_literal`). So we can assume all + // chars and escapes are valid here. Ok(match kind { token::Bool => { assert!(symbol.is_bool_lit()); @@ -56,12 +58,12 @@ impl LitKind { token::Byte => { return unescape_byte(symbol.as_str()) .map(LitKind::Byte) - .map_err(|_| LitError::LexerError); + .map_err(|_| panic!("failed to unescape byte literal")); } token::Char => { return unescape_char(symbol.as_str()) .map(LitKind::Char) - .map_err(|_| LitError::LexerError); + .map_err(|_| panic!("failed to unescape char literal")); } // There are some valid suffixes for integer and float literals, @@ -77,26 +79,22 @@ impl LitKind { let s = symbol.as_str(); // Vanilla strings are so common we optimize for the common case where no chars // requiring special behaviour are present. - let symbol = if s.contains(['\\', '\r']) { + let symbol = if s.contains('\\') { let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); // Force-inlining here is aggressive but the closure is - // called on every char in the string, so it can be - // hot in programs with many long strings. - unescape_literal( + // called on every char in the string, so it can be hot in + // programs with many long strings containing escapes. + unescape_unicode( s, Mode::Str, &mut #[inline(always)] - |_, unescaped_char| match unescaped_char { + |_, c| match c { Ok(c) => buf.push(c), Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + assert!(!err.is_fatal(), "failed to unescape string literal") } }, ); - error?; Symbol::intern(&buf) } else { symbol @@ -104,86 +102,46 @@ impl LitKind { LitKind::Str(symbol, ast::StrStyle::Cooked) } token::StrRaw(n) => { - // Raw strings have no escapes, so we only need to check for invalid chars, and we - // can reuse the symbol on success. - let mut error = Ok(()); - unescape_literal(symbol.as_str(), Mode::RawStr, &mut |_, unescaped_char| { - match unescaped_char { - Ok(_) => {} - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } - } - }); - error?; + // Raw strings have no escapes so no work is needed here. LitKind::Str(symbol, ast::StrStyle::Raw(n)) } token::ByteStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_literal(s, Mode::ByteStr, &mut |_, c| match c { + unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c { Ok(c) => buf.push(byte_from_char(c)), Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + assert!(!err.is_fatal(), "failed to unescape string literal") } }); - error?; LitKind::ByteStr(buf.into(), StrStyle::Cooked) } token::ByteStrRaw(n) => { - // Raw strings have no escapes, so we only need to check for invalid chars, and we - // can convert the symbol directly to a `Lrc` on success. - let s = symbol.as_str(); - let mut error = Ok(()); - unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c { - Ok(_) => {} - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } - }); - LitKind::ByteStr(s.to_owned().into_bytes().into(), StrStyle::Raw(n)) + // Raw strings have no escapes so we can convert the symbol + // directly to a `Lrc`. + let buf = symbol.as_str().to_owned().into_bytes(); + LitKind::ByteStr(buf.into(), StrStyle::Raw(n)) } token::CStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_c_string(s, Mode::CStr, &mut |_span, c| match c { - Ok(CStrUnit::Byte(b)) => buf.push(b), - Ok(CStrUnit::Char(c)) => { + unescape_mixed(s, Mode::CStr, &mut |_span, c| match c { + Ok(MixedUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) } + Ok(MixedUnit::HighByte(b)) => buf.push(b), Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + assert!(!err.is_fatal(), "failed to unescape C string literal") } }); - error?; buf.push(0); LitKind::CStr(buf.into(), StrStyle::Cooked) } token::CStrRaw(n) => { - // Raw strings have no escapes, so we only need to check for invalid chars, and we - // can convert the symbol directly to a `Lrc` on success. - let s = symbol.as_str(); - let mut error = Ok(()); - unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c { - Ok(_) => {} - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } - }); - error?; - let mut buf = s.to_owned().into_bytes(); + // Raw strings have no escapes so we can convert the symbol + // directly to a `Lrc` after appending the terminating NUL + // char. + let mut buf = symbol.as_str().to_owned().into_bytes(); buf.push(0); LitKind::CStr(buf.into(), StrStyle::Raw(n)) } @@ -366,7 +324,7 @@ fn integer_lit(symbol: Symbol, suffix: Option) -> Result>(visitor: &mut V, item: &'a Item) { } ItemKind::MacCall(mac) => visitor.visit_mac_call(mac), ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id), - ItemKind::Delegation(box Delegation { id: _, qself, path, body }) => { + ItemKind::Delegation(box Delegation { id, qself, path, body }) => { if let Some(qself) = qself { visitor.visit_ty(&qself.ty); } - walk_path(visitor, path); + visitor.visit_path(path, *id); if let Some(body) = body { visitor.visit_block(body); } @@ -502,7 +502,7 @@ where } GenericArgs::Parenthesized(data) => { walk_list!(visitor, visit_ty, &data.inputs); - walk_fn_ret_ty(visitor, &data.output); + visitor.visit_fn_ret_ty(&data.output); } } } @@ -713,11 +713,11 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, AssocItemKind::MacCall(mac) => { visitor.visit_mac_call(mac); } - AssocItemKind::Delegation(box Delegation { id: _, qself, path, body }) => { + AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { if let Some(qself) = qself { visitor.visit_ty(&qself.ty); } - walk_path(visitor, path); + visitor.visit_path(path, *id); if let Some(body) = body { visitor.visit_block(body); } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 8615016cda599..37e45379ba9a2 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -11,6 +11,12 @@ ast_lowering_argument = argument ast_lowering_assoc_ty_parentheses = parenthesized generic arguments cannot be used in associated type constraints +ast_lowering_async_bound_not_on_trait = + `async` bound modifier only allowed on trait, not `{$descr}` + +ast_lowering_async_bound_only_for_fn_traits = + `async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits + ast_lowering_async_coroutines_not_supported = `async` coroutines are not yet supported @@ -117,9 +123,6 @@ ast_lowering_never_pattern_with_guard = a guard on a never pattern will never be run .suggestion = remove this guard -ast_lowering_not_supported_for_lifetime_binder_async_closure = - `for<...>` binders on `async` closures are not currently supported - ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 4843d36372dcc..ec92afee47a6b 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,9 +1,9 @@ -use rustc_errors::DiagnosticArgFromDisplay; +use rustc_errors::{codes::*, DiagnosticArgFromDisplay}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")] +#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)] pub struct GenericTypeWithParentheses { #[primary_span] #[label] @@ -22,7 +22,7 @@ pub struct UseAngleBrackets { } #[derive(Diagnostic)] -#[diag(ast_lowering_invalid_abi, code = "E0703")] +#[diag(ast_lowering_invalid_abi, code = E0703)] #[note] pub struct InvalidAbi { #[primary_span] @@ -89,7 +89,7 @@ pub enum AssocTyParenthesesSub { } #[derive(Diagnostic)] -#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] +#[diag(ast_lowering_misplaced_impl_trait, code = E0562)] #[note] pub struct MisplacedImplTrait<'a> { #[primary_span] @@ -114,7 +114,7 @@ pub struct UnderscoreExprLhsAssign { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_base_expression_double_dot, code = "E0797")] +#[diag(ast_lowering_base_expression_double_dot, code = E0797)] pub struct BaseExpressionDoubleDot { #[primary_span] #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] @@ -122,7 +122,7 @@ pub struct BaseExpressionDoubleDot { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")] +#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)] pub struct AwaitOnlyInAsyncFnAndBlocks { #[primary_span] #[label] @@ -132,14 +132,14 @@ pub struct AwaitOnlyInAsyncFnAndBlocks { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_coroutine_too_many_parameters, code = "E0628")] +#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)] pub struct CoroutineTooManyParameters { #[primary_span] pub fn_decl_span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")] +#[diag(ast_lowering_closure_cannot_be_static, code = E0697)] pub struct ClosureCannotBeStatic { #[primary_span] pub fn_decl_span: Span, @@ -154,14 +154,14 @@ pub struct FunctionalRecordUpdateDestructuringAssignment { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_async_coroutines_not_supported, code = "E0727")] +#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)] pub struct AsyncCoroutinesNotSupported { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")] +#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)] pub struct InlineAsmUnsupportedTarget { #[primary_span] pub span: Span, @@ -326,13 +326,6 @@ pub struct MisplacedRelaxTraitBound { pub span: Span, } -#[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)] -pub struct NotSupportedForLifetimeBinderAsyncClosure { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_match_arm_with_no_body)] pub struct MatchArmWithNoBody { @@ -395,3 +388,18 @@ pub(crate) struct GenericParamDefaultInBinder { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_async_bound_not_on_trait)] +pub(crate) struct AsyncBoundNotOnTrait { + #[primary_span] + pub span: Span, + pub descr: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_lowering_async_bound_only_for_fn_traits)] +pub(crate) struct AsyncBoundOnlyForFnTraits { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0920de48eb87e..c4798887637f8 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,9 +1,10 @@ +use std::assert_matches::assert_matches; + use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, - UnderscoreExprLhsAssign, + NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; @@ -100,6 +101,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ParenthesizedGenericArgs::Err, &ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, + // Method calls can't have bound modifiers + None, )); let receiver = self.lower_expr(receiver); let args = @@ -153,7 +156,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Let(pat, scrutinee, span, is_recovered) => { hir::ExprKind::Let(self.arena.alloc(hir::Let { - hir_id: self.next_id(), span: self.lower_span(*span), pat: self.lower_pat(pat), ty: None, @@ -1027,30 +1029,27 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, fn_arg_span: Span, ) -> hir::ExprKind<'hir> { - if let &ClosureBinder::For { span, .. } = binder { - self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); - } - let (binder_clause, generic_params) = self.lower_closure_binder(binder); + assert_matches!( + coroutine_kind, + CoroutineKind::Async { .. }, + "only async closures are supported currently" + ); + let body = self.with_new_scopes(fn_decl_span, |this| { + let inner_decl = + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + // Transform `async |x: u8| -> X { ... }` into // `|x: u8| || -> X { ... }`. let body_id = this.lower_body(|this| { - let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output { - let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); - Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx))) - } else { - None - }; - let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( - decl, + &inner_decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), body.span, coroutine_kind, hir::CoroutineSource::Closure, - async_ret_ty, ); let hir_id = this.lower_node_id(coroutine_kind.closure_id()); @@ -1061,15 +1060,12 @@ impl<'hir> LoweringContext<'_, 'hir> { body_id }); - let outer_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. let fn_decl = - self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); + self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); let c = self.arena.alloc(hir::Closure { def_id: self.local_def_id(closure_id), @@ -1080,7 +1076,10 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), - kind: hir::ClosureKind::Closure, + // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck + // knows that a `FnDecl` output type like `-> &str` actually means + // "coroutine that returns &str", rather than directly returning a `&str`. + kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async), constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) @@ -1899,7 +1898,10 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, - node: ast::LitKind::Int(value as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)), + node: ast::LitKind::Int( + (value as u128).into(), + ast::LitIntType::Unsigned(ast::UintTy::Usize), + ), }); self.expr(sp, hir::ExprKind::Lit(lit)) } @@ -1907,7 +1909,10 @@ impl<'hir> LoweringContext<'_, 'hir> { 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(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)), + node: ast::LitKind::Int( + u128::from(value).into(), + ast::LitIntType::Unsigned(ast::UintTy::U32), + ), }); self.expr(sp, hir::ExprKind::Lit(lit)) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index dd3f7289a60b2..7b81ed4875c64 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -25,7 +25,7 @@ pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, pub(super) resolver: &'a mut ResolverAstLowering, pub(super) ast_index: &'a IndexSlice>, - pub(super) owners: &'a mut IndexVec>>, + pub(super) owners: &'a mut IndexVec>, } /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span @@ -64,10 +64,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } } - pub(super) fn lower_node( - &mut self, - def_id: LocalDefId, - ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> { + pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); if let hir::MaybeOwner::Phantom = owner { let node = self.ast_index[def_id]; @@ -343,14 +340,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = self.lower_generics(ast_generics, *constness, id, &itctx, |this| { - let constness = match *constness { - Const::Yes(span) => BoundConstness::Maybe(span), - Const::No => BoundConstness::Never, + let modifiers = TraitBoundModifiers { + constness: match *constness { + Const::Yes(span) => BoundConstness::Maybe(span), + Const::No => BoundConstness::Never, + }, + asyncness: BoundAsyncness::Normal, + // we don't use this in bound lowering + polarity: BoundPolarity::Positive, }; let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( - constness, + modifiers, trait_ref, &ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) @@ -496,8 +498,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - let res = - self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect(); + let res = self.lower_import_res(id, path.span); let path = self.lower_use_path(res, &path, ParamMode::Explicit); hir::ItemKind::Use(path, hir::UseKind::Single) } @@ -533,7 +534,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // for that we return the `{}` import (called the // `ListStem`). - let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None }; + let span = prefix.span.to(path.span); + let prefix = Path { segments, span, tokens: None }; // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { @@ -567,9 +569,16 @@ impl<'hir> LoweringContext<'_, 'hir> { }); } - let res = - self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect(); - let path = self.lower_use_path(res, &prefix, ParamMode::Explicit); + let path = if trees.is_empty() && !prefix.segments.is_empty() { + // For empty lists we need to lower the prefix so it is checked for things + // like stability later. + let res = self.lower_import_res(id, span); + self.lower_use_path(res, &prefix, ParamMode::Explicit) + } else { + // For non-empty lists we can just drop all the data, the prefix is already + // present in HIR as a part of nested imports. + self.arena.alloc(hir::UsePath { res: smallvec![], segments: &[], span }) + }; hir::ItemKind::Use(path, hir::UseKind::ListStem) } } @@ -1089,7 +1098,6 @@ impl<'hir> LoweringContext<'_, 'hir> { body.span, coroutine_kind, hir::CoroutineSource::Fn, - None, ); // FIXME(async_fn_track_caller): Can this be moved above? @@ -1111,7 +1119,6 @@ impl<'hir> LoweringContext<'_, 'hir> { body_span: Span, coroutine_kind: CoroutineKind, coroutine_source: hir::CoroutineSource, - return_type_hint: Option>, ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { let mut parameters: Vec> = Vec::new(); let mut statements: Vec> = Vec::new(); @@ -1281,12 +1288,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let closure_id = coroutine_kind.closure_id(); let coroutine_expr = self.make_desugared_coroutine_expr( - // FIXME(async_closures): This should only move locals, - // and not upvars. Capturing closure upvars by ref doesn't - // work right now anyways, so whatever. - CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + // The default capture mode here is by-ref. Later on during upvar analysis, + // we will force the captured arguments to by-move, but for async closures, + // we want to make sure that we avoid unnecessarily moving captures, or else + // all async closures would default to `FnOnce` as their calling mode. + CaptureBy::Ref, closure_id, - return_type_hint, + None, body_span, desugaring_kind, coroutine_source, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 057fe65d0afad..063b6627050bc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -33,10 +33,9 @@ #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] -#![feature(if_let_guard)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(let_chains)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -65,7 +64,7 @@ use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{DesugaringKind, Span, DUMMY_SP}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use thin_vec::ThinVec; @@ -101,7 +100,7 @@ struct LoweringContext<'a, 'hir> { /// Attributes inside the owner being lowered. attrs: SortedMap, /// Collect items that were created by lowering the current owner. - children: Vec<(LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>)>, + children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>, coroutine_kind: Option, @@ -133,6 +132,7 @@ struct LoweringContext<'a, 'hir> { allow_gen_future: Lrc<[Symbol]>, allow_async_iterator: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>, + allow_async_fn_traits: Lrc<[Symbol]>, /// Mapping from generics `def_id`s to TAIT generics `def_id`s. /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic @@ -178,6 +178,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { [sym::gen_future].into() }, allow_for_await: [sym::async_iterator].into(), + allow_async_fn_traits: [sym::async_fn_traits].into(), // 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(), @@ -298,7 +299,6 @@ enum ImplTraitPosition { Path, Variable, Trait, - AsyncBlock, Bound, Generic, ExternFnParam, @@ -325,7 +325,6 @@ impl std::fmt::Display for ImplTraitPosition { ImplTraitPosition::Path => "paths", ImplTraitPosition::Variable => "the type of variable bindings", ImplTraitPosition::Trait => "traits", - ImplTraitPosition::AsyncBlock => "async blocks", ImplTraitPosition::Bound => "bounds", ImplTraitPosition::Generic => "generics", ImplTraitPosition::ExternFnParam => "`extern fn` parameters", @@ -417,7 +416,7 @@ fn index_crate<'a>( /// This hash will then be part of the crate_hash which is stored in the metadata. fn compute_hir_hash( tcx: TyCtxt<'_>, - owners: &IndexSlice>>, + owners: &IndexSlice>, ) -> Fingerprint { let mut hir_body_nodes: Vec<_> = owners .iter_enumerated() @@ -751,8 +750,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res()) } - fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator> { - self.resolver.get_import_res(id).present_items() + fn lower_import_res(&mut self, id: NodeId, span: Span) -> SmallVec<[Res; 3]> { + let res = self.resolver.get_import_res(id).present_items(); + let res: SmallVec<_> = res.map(|res| self.lower_res(res)).collect(); + if res.is_empty() { + self.dcx().span_delayed_bug(span, "no resolution for an import"); + return smallvec![Res::Err]; + } + res } fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> { @@ -1313,7 +1318,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: t.span, }, itctx, - ast::BoundConstness::Never, + TraitBoundModifiers::NONE, ); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); @@ -1428,7 +1433,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx, // Still, don't pass along the constness here; we don't want to // synthesize any host effect args, it'd only cause problems. - ast::BoundConstness::Never, + TraitBoundModifiers { + constness: BoundConstness::Never, + ..*modifiers + }, )) } BoundPolarity::Maybe(_) => None, @@ -2021,7 +2029,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait( - self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()), + self.lower_poly_trait_ref(p, itctx, *modifiers), self.lower_trait_bound_modifiers(*modifiers), ), GenericBound::Outlives(lifetime) => { @@ -2194,7 +2202,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_ref( &mut self, - constness: ast::BoundConstness, + modifiers: ast::TraitBoundModifiers, p: &TraitRef, itctx: &ImplTraitContext, ) -> hir::TraitRef<'hir> { @@ -2204,7 +2212,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &p.path, ParamMode::Explicit, itctx, - Some(constness), + Some(modifiers), ) { hir::QPath::Resolved(None, path) => path, qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"), @@ -2217,11 +2225,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, p: &PolyTraitRef, itctx: &ImplTraitContext, - constness: ast::BoundConstness, + modifiers: ast::TraitBoundModifiers, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); - let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx); + let trait_ref = self.lower_trait_ref(modifiers, &p.trait_ref, itctx); hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } } @@ -2307,7 +2315,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match c.value.kind { ExprKind::Underscore => { if self.tcx.features().generic_arg_infer { - hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span)) + hir::ArrayLen::Infer(hir::InferArg { + hir_id: self.lower_node_id(c.id), + span: self.lower_span(c.value.span), + }) } else { feature_err( &self.tcx.sess, diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c679ee56fcd8b..76c7e530a6bb7 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,17 +1,21 @@ use crate::ImplTraitPosition; -use super::errors::{GenericTypeWithParentheses, UseAngleBrackets}; +use super::errors::{ + AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, GenericTypeWithParentheses, UseAngleBrackets, +}; use super::ResolverAstLoweringExt; use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::{self as ast, *}; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_middle::span_bug; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; @@ -24,8 +28,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &Path, param_mode: ParamMode, itctx: &ImplTraitContext, - // constness of the impl/bound if this is a trait path - constness: Option, + // modifiers of the impl/bound if this is a trait path + modifiers: Option, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); @@ -35,10 +39,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let base_res = partial_res.base_res(); let unresolved_segments = partial_res.unresolved_segments(); + let mut res = self.lower_res(base_res); + + // When we have an `async` kw on a bound, map the trait it resolves to. + let mut bound_modifier_allowed_features = None; + if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers { + match res { + Res::Def(DefKind::Trait, def_id) => { + if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) { + res = Res::Def(DefKind::Trait, async_def_id); + bound_modifier_allowed_features = Some(features); + } else { + self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span }); + } + } + Res::Err => { + // No additional error. + } + _ => { + // This error isn't actually emitted AFAICT, but it's best to keep + // it around in case the resolver doesn't always check the defkind + // of an item or something. + self.dcx().emit_err(AsyncBoundNotOnTrait { span: p.span, descr: res.descr() }); + } + } + } + let path_span_lo = p.span.shrink_to_lo(); let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { - res: self.lower_res(base_res), + res, segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( |(i, segment)| { let param_mode = match (qself_position, param_mode) { @@ -77,7 +107,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parenthesized_generic_args, itctx, // if this is the last segment, add constness to the trait path - if i == proj_start - 1 { constness } else { None }, + if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None }, + bound_modifier_allowed_features.clone(), ) }, )), @@ -88,6 +119,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ), }); + if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features { + path.span = self.mark_span_with_reason( + DesugaringKind::BoundModifier, + path.span, + Some(bound_modifier_allowed_features), + ); + } + // Simple case, either no projections, or only fully-qualified. // E.g., `std::mem::size_of` or `::Item`. if unresolved_segments == 0 { @@ -125,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Err, itctx, None, + None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -156,6 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &Path, param_mode: ParamMode, ) -> &'hir hir::UsePath<'hir> { + assert!((1..=3).contains(&res.len())); self.arena.alloc(hir::UsePath { res, segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| { @@ -166,6 +207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Err, &ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, + None, ) })), span: self.lower_span(p.span), @@ -180,6 +222,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parenthesized_generic_args: ParenthesizedGenericArgs, itctx: &ImplTraitContext, constness: Option, + // Additional features ungated with a bound modifier like `async`. + // This is passed down to the implicit associated type binding in + // parenthesized bounds. + bound_modifier_allowed_features: Option>, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() { @@ -188,9 +234,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(data) => match parenthesized_generic_args { - ParenthesizedGenericArgs::ParenSugar => { - self.lower_parenthesized_parameter_data(data, itctx) - } + ParenthesizedGenericArgs::ParenSugar => self + .lower_parenthesized_parameter_data( + data, + itctx, + bound_modifier_allowed_features, + ), ParenthesizedGenericArgs::Err => { // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` let sub = if !data.inputs.is_empty() { @@ -357,6 +406,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, data: &ParenthesizedArgs, itctx: &ImplTraitContext, + bound_modifier_allowed_features: Option>, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this // means that we permit things like `&Ref`, where `Ref` has @@ -392,7 +442,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))]; - let binding = self.assoc_ty_binding(sym::Output, output_ty.span, output_ty); + + // If we have a bound like `async Fn() -> T`, make sure that we mark the + // `Output = T` associated type bound with the right feature gates. + let mut output_span = output_ty.span; + if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features { + output_span = self.mark_span_with_reason( + DesugaringKind::BoundModifier, + output_span, + Some(bound_modifier_allowed_features), + ); + } + let binding = self.assoc_ty_binding(sym::Output, output_span, output_ty); + ( GenericArgsCtor { args, @@ -429,4 +491,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { kind, } } + + /// When a bound is annotated with `async`, it signals to lowering that the trait + /// that the bound refers to should be mapped to the "async" flavor of the trait. + /// + /// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one + /// that is generic over `async`ness, if that's ever possible, or modify the + /// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`. + fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> { + let lang_items = self.tcx.lang_items(); + if Some(def_id) == lang_items.fn_trait() { + Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone())) + } else if Some(def_id) == lang_items.fn_mut_trait() { + Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone())) + } else if Some(def_id) == lang_items.fn_once_trait() { + Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone())) + } else { + None + } + } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index e2b8e64b115e5..5f54a0ddf8c38 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::{AddToDiagnostic, Applicability}; +use rustc_errors::{codes::*, AddToDiagnostic, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -23,7 +23,7 @@ pub struct InvalidLabel { } #[derive(Diagnostic)] -#[diag(ast_passes_visibility_not_permitted, code = "E0449")] +#[diag(ast_passes_visibility_not_permitted, code = E0449)] pub struct VisibilityNotPermitted { #[primary_span] pub span: Span, @@ -44,7 +44,7 @@ pub enum VisibilityNotPermittedNote { } #[derive(Diagnostic)] -#[diag(ast_passes_trait_fn_const, code = "E0379")] +#[diag(ast_passes_trait_fn_const, code = E0379)] pub struct TraitFnConst { #[primary_span] #[label] @@ -302,14 +302,14 @@ pub struct ItemUnderscore<'a> { } #[derive(Diagnostic)] -#[diag(ast_passes_nomangle_ascii, code = "E0754")] +#[diag(ast_passes_nomangle_ascii, code = E0754)] pub struct NoMangleAscii { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_module_nonascii, code = "E0754")] +#[diag(ast_passes_module_nonascii, code = E0754)] #[help] pub struct ModuleNonAscii { #[primary_span] @@ -318,7 +318,7 @@ pub struct ModuleNonAscii { } #[derive(Diagnostic)] -#[diag(ast_passes_auto_generic, code = "E0567")] +#[diag(ast_passes_auto_generic, code = E0567)] pub struct AutoTraitGeneric { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -328,7 +328,7 @@ pub struct AutoTraitGeneric { } #[derive(Diagnostic)] -#[diag(ast_passes_auto_super_lifetime, code = "E0568")] +#[diag(ast_passes_auto_super_lifetime, code = E0568)] pub struct AutoTraitBounds { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -338,7 +338,7 @@ pub struct AutoTraitBounds { } #[derive(Diagnostic)] -#[diag(ast_passes_auto_items, code = "E0380")] +#[diag(ast_passes_auto_items, code = E0380)] pub struct AutoTraitItems { #[primary_span] pub spans: Vec, @@ -384,28 +384,28 @@ impl AddToDiagnostic for EmptyLabelManySpans { } #[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")] +#[diag(ast_passes_pattern_in_fn_pointer, code = E0561)] pub struct PatternFnPointer { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_trait_object_single_bound, code = "E0226")] +#[diag(ast_passes_trait_object_single_bound, code = E0226)] pub struct TraitObjectBound { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = "E0667")] +#[diag(ast_passes_impl_trait_path, code = E0667)] pub struct ImplTraitPath { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_nested_impl_trait, code = "E0666")] +#[diag(ast_passes_nested_impl_trait, code = E0666)] pub struct NestedImplTrait { #[primary_span] pub span: Span, @@ -443,7 +443,7 @@ pub struct ObsoleteAuto { } #[derive(Diagnostic)] -#[diag(ast_passes_unsafe_negative_impl, code = "E0198")] +#[diag(ast_passes_unsafe_negative_impl, code = E0198)] pub struct UnsafeNegativeImpl { #[primary_span] pub span: Span, @@ -468,7 +468,7 @@ pub struct InherentImplCannot<'a> { } #[derive(Diagnostic)] -#[diag(ast_passes_inherent_cannot_be, code = "E0197")] +#[diag(ast_passes_inherent_cannot_be, code = E0197)] pub struct InherentImplCannotUnsafe<'a> { #[primary_span] pub span: Span, @@ -536,7 +536,7 @@ pub struct GenericDefaultTrailing { } #[derive(Diagnostic)] -#[diag(ast_passes_nested_lifetimes, code = "E0316")] +#[diag(ast_passes_nested_lifetimes, code = E0316)] pub struct NestedLifetimes { #[primary_span] pub span: Span, @@ -655,7 +655,7 @@ pub struct ConstAndCVariadic { } #[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_foreign, code = "E0130")] +#[diag(ast_passes_pattern_in_foreign, code = E0130)] pub struct PatternInForeign { #[primary_span] #[label] @@ -663,7 +663,7 @@ pub struct PatternInForeign { } #[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_bodiless, code = "E0642")] +#[diag(ast_passes_pattern_in_bodiless, code = E0642)] pub struct PatternInBodiless { #[primary_span] #[label] @@ -711,14 +711,14 @@ pub struct AssociatedSuggestion2 { } #[derive(Diagnostic)] -#[diag(ast_passes_stability_outside_std, code = "E0734")] +#[diag(ast_passes_stability_outside_std, code = E0734)] pub struct StabilityOutsideStd { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_feature_on_non_nightly, code = "E0554")] +#[diag(ast_passes_feature_on_non_nightly, code = E0554)] pub struct FeatureOnNonNightly { #[primary_span] pub span: Span, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 192e458775a93..409aef9185d92 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -362,6 +362,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } + fn visit_generic_args(&mut self, args: &'a ast::GenericArgs) { + // This check needs to happen here because the never type can be returned from a function, + // but cannot be used in any other context. If this check was in `visit_fn_ret_ty`, it + // include both functions and generics like `impl Fn() -> !`. + if let ast::GenericArgs::Parenthesized(generic_args) = args + && let ast::FnRetTy::Ty(ref ty) = generic_args.output + && matches!(ty.kind, ast::TyKind::Never) + { + gate!(&self, never_type, ty.span, "the `!` type is experimental"); + } + visit::walk_generic_args(self, args); + } + fn visit_expr(&mut self, e: &'a ast::Expr) { match e.kind { ast::ExprKind::TryBlock(_) => { @@ -398,7 +411,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { &self, exclusive_range_pattern, pattern.span, - "exclusive range pattern syntax is experimental" + "exclusive range pattern syntax is experimental", + "use an inclusive range pattern, like N..=M" ); } _ => {} diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index ba09183374e10..fa6cdd55c3dcb 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -11,7 +11,6 @@ #![feature(if_let_guard)] #![feature(iter_is_partitioned)] #![feature(let_chains)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 100b298898224..61617beb86b5a 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -4,8 +4,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![feature(box_patterns)] -#![feature(let_chains)] -#![recursion_limit = "256"] mod helpers; pub mod pp; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c2fd4558fd76e..731232bce65cb 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -8,6 +8,7 @@ mod item; use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, Breaks}; use crate::pprust::state::expr::FixupContext; +use ast::TraitBoundModifiers; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; @@ -160,6 +161,10 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { use TokenTree::Delimited as Del; use TokenTree::Token as Tok; + fn is_punct(tt: &TokenTree) -> bool { + matches!(tt, TokenTree::Token(tok, _) if tok.is_punct()) + } + // Each match arm has one or more examples in comments. The default is to // insert space between adjacent tokens, except for the cases listed in // this match. @@ -167,24 +172,35 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { // No space after line doc comments. (Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false, - // `.` + ANYTHING: `x.y`, `tup.0` - // `$` + ANYTHING: `$e` - (Tok(Token { kind: Dot | Dollar, .. }, _), _) => false, - - // ANYTHING + `,`: `foo,` - // ANYTHING + `.`: `x.y`, `tup.0` - // ANYTHING + `!`: `foo! { ... }` - // - // FIXME: Incorrect cases: - // - Logical not: `x =! y`, `if! x { f(); }` - // - Never type: `Fn() ->!` - (_, Tok(Token { kind: Comma | Dot | Not, .. }, _)) => false, - - // IDENT + `(`: `f(3)` - // - // FIXME: Incorrect cases: - // - Let: `let(a, b) = (1, 2)` - (Tok(Token { kind: Ident(..), .. }, _), Del(_, _, Parenthesis, _)) => false, + // `.` + NON-PUNCT: `x.y`, `tup.0` + (Tok(Token { kind: Dot, .. }, _), tt2) if !is_punct(tt2) => false, + + // `$` + IDENT: `$e` + (Tok(Token { kind: Dollar, .. }, _), Tok(Token { kind: Ident(..), .. }, _)) => false, + + // NON-PUNCT + `,`: `foo,` + // NON-PUNCT + `;`: `x = 3;`, `[T; 3]` + // NON-PUNCT + `.`: `x.y`, `tup.0` + (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, .. }, _)) + if !Ident::new(*sym, *span).is_reserved() || *is_raw => + { + false + } + + // IDENT|`fn`|`Self`|`pub` + `(`: `f(3)`, `fn(x: u8)`, `Self()`, `pub(crate)`, + // but `let (a, b) = (1, 2)` needs a space after the `let` + (Tok(Token { kind: Ident(sym, is_raw), span }, _), Del(_, _, Parenthesis, _)) + if !Ident::new(*sym, *span).is_reserved() + || *sym == kw::Fn + || *sym == kw::SelfUpper + || *sym == kw::Pub + || *is_raw => + { + false + } // `#` + `[`: `#[attr]` (Tok(Token { kind: Pound, .. }, _), Del(_, _, Bracket, _)) => false, @@ -1575,18 +1591,28 @@ impl<'a> State<'a> { } match bound { - GenericBound::Trait(tref, modifier) => { - match modifier.constness { + GenericBound::Trait( + tref, + TraitBoundModifiers { constness, asyncness, polarity }, + ) => { + match constness { ast::BoundConstness::Never => {} ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => { - self.word_space(modifier.constness.as_str()); + self.word_space(constness.as_str()); + } + } + + match asyncness { + ast::BoundAsyncness::Normal => {} + ast::BoundAsyncness::Async(_) => { + self.word_space(asyncness.as_str()); } } - match modifier.polarity { + match polarity { ast::BoundPolarity::Positive => {} ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => { - self.word(modifier.polarity.as_str()); + self.word(polarity.as_str()); } } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 6b903be6e5eec..a3783db5f80d6 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1185,9 +1185,9 @@ fn allow_unstable<'a>( pub fn parse_alignment(node: &ast::LitKind) -> Result { if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { - if literal.is_power_of_two() { + if literal.get().is_power_of_two() { // rustc_middle::ty::layout::Align restricts align to <= 2^29 - if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") } + if *literal <= 1 << 29 { Ok(literal.get() as u32) } else { Err("larger than 2^29") } } else { Err("not a power of two") } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 89606b81a9946..79370602842b0 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -2,8 +2,7 @@ use std::num::IntErrorKind; use rustc_ast as ast; use rustc_errors::{ - error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - Level, + codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -12,14 +11,14 @@ use crate::fluent_generated as fluent; use crate::UnsupportedLiteralReason; #[derive(Diagnostic)] -#[diag(attr_expected_one_cfg_pattern, code = "E0536")] +#[diag(attr_expected_one_cfg_pattern, code = E0536)] pub(crate) struct ExpectedOneCfgPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_invalid_predicate, code = "E0537")] +#[diag(attr_invalid_predicate, code = E0537)] pub(crate) struct InvalidPredicate { #[primary_span] pub span: Span, @@ -28,7 +27,7 @@ pub(crate) struct InvalidPredicate { } #[derive(Diagnostic)] -#[diag(attr_multiple_item, code = "E0538")] +#[diag(attr_multiple_item, code = E0538)] pub(crate) struct MultipleItem { #[primary_span] pub span: Span, @@ -37,7 +36,7 @@ pub(crate) struct MultipleItem { } #[derive(Diagnostic)] -#[diag(attr_incorrect_meta_item, code = "E0539")] +#[diag(attr_incorrect_meta_item, code = E0539)] pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, @@ -56,7 +55,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::>(); DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item) .with_span(self.span) - .with_code(error_code!(E0541)) + .with_code(E0541) .with_arg("item", self.item) .with_arg("expected", expected.join(", ")) .with_span_label(self.span, fluent::attr_label) @@ -64,28 +63,28 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { } #[derive(Diagnostic)] -#[diag(attr_missing_since, code = "E0542")] +#[diag(attr_missing_since, code = E0542)] pub(crate) struct MissingSince { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_missing_note, code = "E0543")] +#[diag(attr_missing_note, code = E0543)] pub(crate) struct MissingNote { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_multiple_stability_levels, code = "E0544")] +#[diag(attr_multiple_stability_levels, code = E0544)] pub(crate) struct MultipleStabilityLevels { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_invalid_issue_string, code = "E0545")] +#[diag(attr_invalid_issue_string, code = E0545)] pub(crate) struct InvalidIssueString { #[primary_span] pub span: Span, @@ -143,21 +142,21 @@ impl InvalidIssueStringCause { } #[derive(Diagnostic)] -#[diag(attr_missing_feature, code = "E0546")] +#[diag(attr_missing_feature, code = E0546)] pub(crate) struct MissingFeature { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_non_ident_feature, code = "E0546")] +#[diag(attr_non_ident_feature, code = E0546)] pub(crate) struct NonIdentFeature { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_missing_issue, code = "E0547")] +#[diag(attr_missing_issue, code = E0547)] pub(crate) struct MissingIssue { #[primary_span] pub span: Span, @@ -166,14 +165,14 @@ pub(crate) struct MissingIssue { // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? // It is more similar to `IncorrectReprFormatGeneric`. #[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")] +#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)] pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")] +#[diag(attr_invalid_repr_hint_no_paren, code = E0552)] pub(crate) struct InvalidReprHintNoParen { #[primary_span] pub span: Span, @@ -182,7 +181,7 @@ pub(crate) struct InvalidReprHintNoParen { } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_hint_no_value, code = "E0552")] +#[diag(attr_invalid_repr_hint_no_value, code = E0552)] pub(crate) struct InvalidReprHintNoValue { #[primary_span] pub span: Span, @@ -215,7 +214,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral { }, ); diag.span(self.span); - diag.code(error_code!(E0565)); + diag.code(E0565); if self.is_bytestr { diag.span_suggestion( self.start_point_span, @@ -229,7 +228,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral { } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_align_need_arg, code = "E0589")] +#[diag(attr_invalid_repr_align_need_arg, code = E0589)] pub(crate) struct InvalidReprAlignNeedArg { #[primary_span] #[suggestion(code = "align(...)", applicability = "has-placeholders")] @@ -237,7 +236,7 @@ pub(crate) struct InvalidReprAlignNeedArg { } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_generic, code = "E0589")] +#[diag(attr_invalid_repr_generic, code = E0589)] pub(crate) struct InvalidReprGeneric<'a> { #[primary_span] pub span: Span, @@ -247,14 +246,14 @@ pub(crate) struct InvalidReprGeneric<'a> { } #[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")] +#[diag(attr_incorrect_repr_format_align_one_arg, code = E0693)] pub(crate) struct IncorrectReprFormatAlignOneArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_generic, code = "E0693")] +#[diag(attr_incorrect_repr_format_generic, code = E0693)] pub(crate) struct IncorrectReprFormatGeneric<'a> { #[primary_span] pub span: Span, @@ -296,7 +295,7 @@ impl<'a> IncorrectReprFormatGenericCause<'a> { pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option { match kind { ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - Some(Self::Int { span, name, int: *int }) + Some(Self::Int { span, name, int: int.get() }) } ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }), _ => None, @@ -305,14 +304,14 @@ impl<'a> IncorrectReprFormatGenericCause<'a> { } #[derive(Diagnostic)] -#[diag(attr_rustc_promotable_pairing, code = "E0717")] +#[diag(attr_rustc_promotable_pairing, code = E0717)] pub(crate) struct RustcPromotablePairing { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")] +#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { #[primary_span] pub span: Span, diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 351976cdaea6b..6cbcda37f50b8 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{struct_span_code_err, DiagCtxt, DiagnosticBuilder}; +use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -130,7 +130,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { noun_old: &str, old_opt_via: &str, previous_end_span: Option, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -162,7 +162,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, previous_end_span: Option, second_borrow_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -194,7 +194,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { kind_old: &str, msg_old: &str, old_load_end_span: Option, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_code_err!( self.dcx(), @@ -235,7 +235,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, borrow_span: Span, desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { struct_span_code_err!( self.dcx(), span, @@ -252,7 +252,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, desc: &str, is_arg: bool, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) } @@ -265,7 +265,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, move_from_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { struct_span_code_err!( self.dcx(), move_from_span, @@ -283,7 +283,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, ty: Ty<'_>, is_index: Option, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let type_name = match (&ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", @@ -304,7 +304,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, container_ty: Ty<'_>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { struct_span_code_err!( self.dcx(), move_from_span, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8909f47af2d8b..6debb3362b04c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3,7 +3,9 @@ use either::Either; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -26,6 +28,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::FindExprBySpan; use rustc_trait_selection::traits::ObligationCtxt; use std::iter; @@ -324,7 +327,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, mpi: MovePathIndex, move_span: Span, - err: &mut DiagnosticBuilder<'_>, + err: &mut DiagnosticBuilder<'tcx>, in_pattern: &mut bool, move_spans: UseSpans<'_>, ) { @@ -483,7 +486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desired_action: InitializationRequiringAction, span: Span, use_spans: UseSpans<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { // We need all statements in the body where the binding was assigned to later find all // the branching code paths where the binding *wasn't* assigned to. let inits = &self.move_data.init_path_map[mpi]; @@ -855,7 +858,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span }, - hir::ClosureKind::Closure => MoveUseInClosure { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + MoveUseInClosure { var_span } + } } }); @@ -877,7 +882,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, (place, _span): (Place<'tcx>, Span), borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); @@ -902,7 +907,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true } } } @@ -927,7 +932,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (place, span): (Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); @@ -1053,7 +1058,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { var_span, is_single_var: true, }, - hir::ClosureKind::Closure => BorrowUsePlaceClosure { + hir::ClosureKind::Closure + | hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true, @@ -1137,7 +1143,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { var_span, is_single_var: false, }, - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } } } @@ -1155,7 +1161,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } } } @@ -1172,7 +1178,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { SecondBorrowUsePlaceClosure { place: desc_place, var_span } } } @@ -1304,14 +1310,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place: Place<'tcx>, borrowed_place: Place<'tcx>, ) { - if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) = - (&place.projection[..], &borrowed_place.projection[..]) + let tcx = self.infcx.tcx; + let hir = tcx.hir(); + + if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)]) + | ( + [ProjectionElem::Deref, ProjectionElem::Index(index1)], + [ProjectionElem::Deref, ProjectionElem::Index(index2)], + ) = (&place.projection[..], &borrowed_place.projection[..]) { - err.help( - "consider using `.split_at_mut(position)` or similar method to obtain \ - two mutable non-overlapping sub-slices", - ) - .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices"); + let mut note_default_suggestion = || { + err.help( + "consider using `.split_at_mut(position)` or similar method to obtain \ + two mutable non-overlapping sub-slices", + ) + .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices"); + }; + + let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { + note_default_suggestion(); + return; + }; + + let mut expr_finder = + FindExprBySpan::new(self.body.local_decls[*index1].source_info.span); + expr_finder.visit_expr(hir.body(body_id).value); + let Some(index1) = expr_finder.result else { + note_default_suggestion(); + return; + }; + + expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span); + expr_finder.visit_expr(hir.body(body_id).value); + let Some(index2) = expr_finder.result else { + note_default_suggestion(); + return; + }; + + let sm = tcx.sess.source_map(); + + let Ok(index1_str) = sm.span_to_snippet(index1.span) else { + note_default_suggestion(); + return; + }; + + let Ok(index2_str) = sm.span_to_snippet(index2.span) else { + note_default_suggestion(); + return; + }; + + let Some(object) = hir.parent_id_iter(index1.hir_id).find_map(|id| { + if let hir::Node::Expr(expr) = tcx.hir_node(id) + && let hir::ExprKind::Index(obj, ..) = expr.kind + { + Some(obj) + } else { + None + } + }) else { + note_default_suggestion(); + return; + }; + + let Ok(obj_str) = sm.span_to_snippet(object.span) else { + note_default_suggestion(); + return; + }; + + let Some(swap_call) = hir.parent_id_iter(object.hir_id).find_map(|id| { + if let hir::Node::Expr(call) = tcx.hir_node(id) + && let hir::ExprKind::Call(callee, ..) = call.kind + && let hir::ExprKind::Path(qpath) = callee.kind + && let hir::QPath::Resolved(None, res) = qpath + && let hir::def::Res::Def(_, did) = res.res + && tcx.is_diagnostic_item(sym::mem_swap, did) + { + Some(call) + } else { + None + } + }) else { + note_default_suggestion(); + return; + }; + + err.span_suggestion( + swap_call.span, + "use `.swap()` to swap elements at the specified indices instead", + format!("{obj_str}.swap({index1_str}, {index2_str})"), + Applicability::MachineApplicable, + ); } } @@ -2044,7 +2132,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { debug!( "report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ @@ -2219,7 +2307,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, drop_span: Span, borrow_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { debug!( "report_thread_local_value_does_not_live_long_enough(\ {:?}, {:?}\ @@ -2244,7 +2332,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { @@ -2355,7 +2443,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "consider consuming the `{ty}` when turning it into an \ `Iterator`", ), - "into_iter".to_string(), + "into_iter", Applicability::MaybeIncorrect, ); } @@ -2411,7 +2499,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return_span: Span, category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, - ) -> Option> { + ) -> Option> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", @@ -2506,7 +2594,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { constraint_span: Span, captured_var: &str, scope: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.infcx.tcx; let args_span = use_span.args_or_use(); @@ -2614,7 +2702,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { upvar_span: Span, upvar_name: Symbol, escape_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.infcx.tcx; let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); @@ -2857,7 +2945,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure => BorrowUseInClosure { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUseInClosure { var_span } + } } }); @@ -2873,7 +2963,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure => BorrowUseInClosure { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUseInClosure { var_span } + } } }); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index b35d4e16eccb0..59f3aa706edea 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -614,7 +614,7 @@ impl UseSpans<'_> { PartialAssignment => AssignPartInCoroutine { path_span }, }); } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { err.subdiagnostic(match action { Borrow => BorrowInClosure { path_span }, MatchOn | Use => UseInClosure { path_span }, @@ -1253,7 +1253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial } } }) diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index fb3525e8998c0..0a0bb75a2a3a6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &mut self, place: Place<'tcx>, span: Span, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'tcx> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) } else { @@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'tcx> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 0a6b758efa564..55649ec2f1645 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -198,12 +198,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { let span = self.body.local_decls[local].source_info.span; mut_error = Some(span); - if let Some((buffer, c)) = self.get_buffered_mut_error(span) { + if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) { // We've encountered a second (or more) attempt to mutably borrow an // immutable binding, so the likely problem is with the binding // declaration, not the use. We collect these in a single diagnostic // and make the binding the primary span of the error. - err = buffer; + err = buffered_err; count = c + 1; if count == 2 { err.replace_span_with(span, false); @@ -924,7 +924,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_suggestion_verbose( expr.span.shrink_to_lo(), "use a mutable iterator instead", - "mut ".to_string(), + "mut ", Applicability::MachineApplicable, ); } @@ -1472,7 +1472,7 @@ fn suggest_ampmut<'tcx>( } fn is_closure_or_coroutine(ty: Ty<'_>) -> bool { - ty.is_closure() || ty.is_coroutine() + ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() } /// Given a field that needs to be mutable, returns a span where the " mut " could go. diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index ad66c677c78f5..bac1d9dd57f6b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -251,6 +251,6 @@ impl OutlivesSuggestionBuilder { diag.sort_span = mir_span.shrink_to_hi(); // Buffer the diagnostic - mbcx.buffer_non_error_diag(diag); + mbcx.buffer_non_error(diag); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4cb49362863fc..c91b8eaab055f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -188,7 +188,7 @@ impl Display for RegionName { } impl rustc_errors::IntoDiagnosticArg for RegionName { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -324,9 +324,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::BoundRegionKind::BrEnv => { let def_ty = self.regioncx.universal_regions().defining_ty; - let DefiningTy::Closure(_, args) = def_ty else { - // Can't have BrEnv in functions, constants or coroutines. - bug!("BrEnv outside of closure."); + let closure_kind = match def_ty { + DefiningTy::Closure(_, args) => args.as_closure().kind(), + DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().kind(), + _ => { + // Can't have BrEnv in functions, constants or coroutines. + bug!("BrEnv outside of closure."); + } }; let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) = tcx.hir().expect_expr(self.mir_hir_id()).kind @@ -334,21 +338,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { bug!("Closure is not defined by a closure expr"); }; let region_name = self.synthesize_region_name(); - - let closure_kind_ty = args.as_closure().kind_ty(); - let note = match closure_kind_ty.to_opt_closure_kind() { - Some(ty::ClosureKind::Fn) => { + let note = match closure_kind { + ty::ClosureKind::Fn => { "closure implements `Fn`, so references to captured variables \ can't escape the closure" } - Some(ty::ClosureKind::FnMut) => { + ty::ClosureKind::FnMut => { "closure implements `FnMut`, so references to captured variables \ can't escape the closure" } - Some(ty::ClosureKind::FnOnce) => { + ty::ClosureKind::FnOnce => { bug!("BrEnv in a `FnOnce` closure"); } - None => bug!("Closure kind not inferred in borrow check"), }; Some(RegionName { @@ -692,7 +693,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure, - )) => " of async closure", + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { + " of async closure" + } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, @@ -719,7 +723,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure, - )) => " of gen closure", + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => { + " of gen closure" + } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Gen, @@ -743,7 +750,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure, - )) => " of async gen closure", + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => { + " of async gen closure" + } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::AsyncGen, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5ba901b9d4f7f..d8b2595047dd9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,17 +3,15 @@ #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] +#![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(let_chains)] #![feature(min_specialization)] #![feature(never_type)] -#![feature(lazy_cell)] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] -#![feature(trusted_step)] #![feature(try_blocks)] -#![recursion_limit = "256"] #[macro_use] extern crate rustc_middle; @@ -22,7 +20,7 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{Diagnostic, DiagnosticBuilder}; +use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::{BitSet, ChunkedBitSet}; @@ -176,12 +174,11 @@ fn do_mir_borrowck<'tcx>( } } - let mut errors = error::BorrowckErrors::new(infcx.tcx); + let mut diags = diags::BorrowckDiags::new(); // Gather the upvars of a closure, if any. if let Some(e) = input_body.tainted_by_errors { infcx.set_tainted_by_errors(e); - errors.set_tainted_by_errors(e); } // Replace all regions with fresh inference variables. This @@ -247,7 +244,7 @@ fn do_mir_borrowck<'tcx>( ®ioncx, &opt_closure_req, &opaque_type_values, - &mut errors, + &mut diags, ); // The various `flow_*` structures can be large. We drop `flow_inits` here @@ -308,11 +305,11 @@ fn do_mir_borrowck<'tcx>( next_region_name: RefCell::new(1), polonius_output: None, move_errors: Vec::new(), - errors, + diags, }; MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body); promoted_mbcx.report_move_errors(); - errors = promoted_mbcx.errors; + diags = promoted_mbcx.diags; struct MoveVisitor<'a, 'cx, 'tcx> { ctxt: &'a mut MirBorrowckCtxt<'cx, 'tcx>, @@ -349,7 +346,7 @@ fn do_mir_borrowck<'tcx>( next_region_name: RefCell::new(1), polonius_output, move_errors: Vec::new(), - errors, + diags, }; // Compute and report region errors, if any. @@ -415,7 +412,7 @@ fn do_mir_borrowck<'tcx>( let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) + tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) } let tainted_by_errors = mbcx.emit_errors(); @@ -577,7 +574,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> { /// Results of Polonius analysis. polonius_output: Option>, - errors: error::BorrowckErrors<'tcx>, + diags: diags::BorrowckDiags<'tcx>, move_errors: Vec>, } @@ -1310,7 +1307,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // moved into the closure and subsequently used by the closure, // in order to populate our used_mut set. match **aggregate_kind { - AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => { + AggregateKind::Closure(def_id, _) + | AggregateKind::CoroutineClosure(def_id, _) + | AggregateKind::Coroutine(def_id, _) => { let def_id = def_id.expect_local(); let BorrowCheckResult { used_mut_upvars, .. } = self.infcx.tcx.mir_borrowck(def_id); @@ -1616,6 +1615,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -1640,7 +1640,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; } } - ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (), + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(_, _) + | ty::Tuple(_) => (), ty::Bool | ty::Char | ty::Int(_) @@ -2131,7 +2134,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | WriteKind::MutableBorrow(BorrowKind::Fake), ) => { if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err() - && !self.has_buffered_errors() + && !self.has_buffered_diags() { // rust-lang/rust#46908: In pure NLL mode this code path should be // unreachable, but we use `span_delayed_bug` because we can hit this when @@ -2389,17 +2392,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } -mod error { +mod diags { use rustc_errors::ErrorGuaranteed; use super::*; - pub struct BorrowckErrors<'tcx> { - tcx: TyCtxt<'tcx>, + enum BufferedDiag<'tcx> { + Error(DiagnosticBuilder<'tcx>), + NonError(DiagnosticBuilder<'tcx, ()>), + } + + impl<'tcx> BufferedDiag<'tcx> { + fn sort_span(&self) -> Span { + match self { + BufferedDiag::Error(diag) => diag.sort_span, + BufferedDiag::NonError(diag) => diag.sort_span, + } + } + } + + pub struct BorrowckDiags<'tcx> { /// This field keeps track of move errors that are to be reported for given move indices. /// - /// There are situations where many errors can be reported for a single move out (see #53807) - /// and we want only the best of those errors. + /// There are situations where many errors can be reported for a single move out (see + /// #53807) and we want only the best of those errors. /// /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of @@ -2412,51 +2428,38 @@ mod error { /// same primary span come out in a consistent order. buffered_move_errors: BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>, + buffered_mut_errors: FxIndexMap, usize)>, - /// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder` - /// because it has a mixture of error diagnostics and non-error diagnostics. - buffered: Vec, - /// Set to Some if we emit an error during borrowck - tainted_by_errors: Option, + + /// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics. + buffered_diags: Vec>, } - impl<'tcx> BorrowckErrors<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - BorrowckErrors { - tcx, + impl<'tcx> BorrowckDiags<'tcx> { + pub fn new() -> Self { + BorrowckDiags { buffered_move_errors: BTreeMap::new(), buffered_mut_errors: Default::default(), - buffered: Default::default(), - tainted_by_errors: None, - } - } - - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { - if let None = self.tainted_by_errors { - self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug( - t.span.clone_ignoring_labels(), - "diagnostic buffered but not emitted", - )) + buffered_diags: Default::default(), } - self.buffered.push(t.into_diagnostic()); } - pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) { - self.buffered.push(t.into_diagnostic()); + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) { + self.buffered_diags.push(BufferedDiag::Error(t)); } - pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) { - self.tainted_by_errors = Some(e); + pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) { + self.buffered_diags.push(BufferedDiag::NonError(t)); } } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { - self.errors.buffer_error(t); + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) { + self.diags.buffer_error(t); } - pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) { - self.errors.buffer_non_error_diag(t); + pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) { + self.diags.buffer_non_error(t); } pub fn buffer_move_error( @@ -2465,7 +2468,7 @@ mod error { place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>), ) -> bool { if let Some((_, diag)) = - self.errors.buffered_move_errors.insert(move_out_indices, place_and_err) + self.diags.buffered_move_errors.insert(move_out_indices, place_and_err) { // Cancel the old diagnostic so we don't ICE diag.cancel(); @@ -2479,47 +2482,50 @@ mod error { &mut self, span: Span, ) -> Option<(DiagnosticBuilder<'tcx>, usize)> { - self.errors.buffered_mut_errors.remove(&span) + self.diags.buffered_mut_errors.remove(&span) } pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) { - self.errors.buffered_mut_errors.insert(span, (t, count)); + self.diags.buffered_mut_errors.insert(span, (t, count)); } pub fn emit_errors(&mut self) -> Option { + let mut res = None; + // Buffer any move errors that we collected and de-duplicated. - for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) { + for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) { // We have already set tainted for this error, so just buffer it. - self.errors.buffered.push(diag.into_diagnostic()); + self.diags.buffered_diags.push(BufferedDiag::Error(diag)); } - for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) { + for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) { if count > 10 { diag.note(format!("...and {} other attempted mutable borrows", count - 10)); } - self.errors.buffered.push(diag.into_diagnostic()); + self.diags.buffered_diags.push(BufferedDiag::Error(diag)); } - if !self.errors.buffered.is_empty() { - self.errors.buffered.sort_by_key(|diag| diag.sort_span); - - let dcx = self.dcx(); - for diag in self.errors.buffered.drain(..) { - dcx.emit_diagnostic(diag); + if !self.diags.buffered_diags.is_empty() { + self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span()); + for buffered_diag in self.diags.buffered_diags.drain(..) { + match buffered_diag { + BufferedDiag::Error(diag) => res = Some(diag.emit()), + BufferedDiag::NonError(diag) => diag.emit(), + } } } - self.errors.tainted_by_errors + res } - pub fn has_buffered_errors(&self) -> bool { - self.errors.buffered.is_empty() + pub(crate) fn has_buffered_diags(&self) -> bool { + self.diags.buffered_diags.is_empty() } pub fn has_move_error( &self, move_out_indices: &[MoveOutIndex], - ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> { - self.errors.buffered_move_errors.get(move_out_indices) + ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)> { + self.diags.buffered_move_errors.get(move_out_indices) } } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index cc8208e9dc306..7ace013975e1b 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -264,7 +264,7 @@ pub(super) fn dump_annotation<'tcx>( regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, opaque_type_values: &FxIndexMap>, - errors: &mut crate::error::BorrowckErrors<'tcx>, + diags: &mut crate::diags::BorrowckDiags<'tcx>, ) { let tcx = infcx.tcx; let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); @@ -310,7 +310,7 @@ pub(super) fn dump_annotation<'tcx>( err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}")); } - errors.buffer_non_error_diag(err); + diags.buffer_non_error(err); } fn for_each_region_constraint<'tcx>( diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 2d997dfadf004..4cfde47664eee 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -164,7 +164,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>( match place_ref.last_projection() { Some((place_base, ProjectionElem::Field(field, _ty))) => { let base_ty = place_base.ty(body, tcx).ty; - if (base_ty.is_closure() || base_ty.is_coroutine()) + if (base_ty.is_closure() || base_ty.is_coroutine() || base_ty.is_coroutine_closure()) && (!by_ref || upvars[field.index()].is_by_ref()) { Some(field) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index cbf01feae06a0..89b203f80a435 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; @@ -1145,6 +1145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let ty = ty.fold_with(&mut OpaqueFolder { tcx }); + let mut failed = false; let ty = tcx.fold_regions(ty, |r, _depth| { let r_vid = self.to_region_vid(r); @@ -1160,15 +1161,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) .find(|&u_r| self.eval_equal(u_r, r_vid)) .map(|u_r| ty::Region::new_var(tcx, u_r)) - // In the case of a failure, use `ReErased`. We will eventually - // return `None` in this case. - .unwrap_or(tcx.lifetimes.re_erased) + // In case we could not find a named region to map to, + // we will return `None` below. + .unwrap_or_else(|| { + failed = true; + r + }) }); debug!("try_promote_type_test_subject: folded ty = {:?}", ty); // This will be true if we failed to promote some region. - if ty.has_erased_regions() { + if failed { return None; } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 01f7bfcadb6f5..e147f62011db9 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,5 +1,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxIndexSet; use rustc_index::bit_set::SparseBitMatrix; use rustc_index::interval::IntervalSet; @@ -41,8 +42,15 @@ pub(crate) struct LivenessValues { /// The map from locations to points. elements: Rc, + /// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and + /// currently only used for validating promoteds (which don't care about more precise tracking). + live_regions: Option>, + /// For each region: the points where it is live. - points: SparseIntervalMatrix, + /// + /// This is not initialized for promoteds, because we don't care *where* within a promoted a + /// region is live, only that it is. + points: Option>, /// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at /// that point. @@ -71,24 +79,52 @@ impl LiveLoans { impl LivenessValues { /// Create an empty map of regions to locations where they're live. - pub(crate) fn new(elements: Rc) -> Self { + pub(crate) fn with_specific_points(elements: Rc) -> Self { LivenessValues { - points: SparseIntervalMatrix::new(elements.num_points()), + live_regions: None, + points: Some(SparseIntervalMatrix::new(elements.num_points())), + elements, + loans: None, + } + } + + /// Create an empty map of regions to locations where they're live. + /// + /// Unlike `with_specific_points`, does not track exact locations where something is live, only + /// which regions are live. + pub(crate) fn without_specific_points(elements: Rc) -> Self { + LivenessValues { + live_regions: Some(Default::default()), + points: None, elements, loans: None, } } /// Iterate through each region that has a value in this set. - pub(crate) fn regions(&self) -> impl Iterator { - self.points.rows() + pub(crate) fn regions(&self) -> impl Iterator + '_ { + self.points.as_ref().expect("use with_specific_points").rows() + } + + /// Iterate through each region that has a value in this set. + // 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 + '_ { + self.live_regions.as_ref().unwrap().iter().copied() } /// Records `region` as being live at the given `location`. pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) { - debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); let point = self.elements.point_from_location(location); - self.points.insert(region, point); + debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); + if let Some(points) = &mut self.points { + points.insert(region, point); + } else { + if self.elements.point_in_range(point) { + self.live_regions.as_mut().unwrap().insert(region); + } + } // When available, record the loans flowing into this region as live at the given point. if let Some(loans) = self.loans.as_mut() { @@ -101,7 +137,13 @@ impl LivenessValues { /// Records `region` as being live at all the given `points`. pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet) { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); - self.points.union_row(region, points); + if let Some(this) = &mut self.points { + this.union_row(region, points); + } else { + if points.iter().any(|point| self.elements.point_in_range(point)) { + self.live_regions.as_mut().unwrap().insert(region); + } + } // When available, record the loans flowing into this region as live at the given points. if let Some(loans) = self.loans.as_mut() { @@ -117,23 +159,33 @@ impl LivenessValues { /// Records `region` as being live at all the control-flow points. pub(crate) fn add_all_points(&mut self, region: RegionVid) { - self.points.insert_all_into_row(region); + if let Some(points) = &mut self.points { + points.insert_all_into_row(region); + } else { + self.live_regions.as_mut().unwrap().insert(region); + } } /// Returns whether `region` is marked live at the given `location`. pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool { let point = self.elements.point_from_location(location); - self.points.row(region).is_some_and(|r| r.contains(point)) - } - - /// Returns whether `region` is marked live at any location. - pub(crate) fn is_live_anywhere(&self, region: RegionVid) -> bool { - self.live_points(region).next().is_some() + if let Some(points) = &self.points { + points.row(region).is_some_and(|r| r.contains(point)) + } else { + unreachable!( + "Should be using LivenessValues::with_specific_points to ask whether live at a location" + ) + } } /// Returns an iterator of all the points where `region` is live. fn live_points(&self, region: RegionVid) -> impl Iterator + '_ { - self.points + let Some(points) = &self.points else { + unreachable!( + "Should be using LivenessValues::with_specific_points to ask whether live at a location" + ) + }; + points .row(region) .into_iter() .flat_map(|set| set.iter()) @@ -288,7 +340,10 @@ impl RegionValues { /// elements for the region `from` from `values` and add them to /// the region `to` in `self`. pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) { - if let Some(set) = values.points.row(from) { + let Some(value_points) = &values.points else { + panic!("LivenessValues must track specific points for use in merge_liveness"); + }; + if let Some(set) = value_points.row(from) { self.points.union_row(to, set); } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index e321b92603d38..1685624f24772 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,4 +1,4 @@ -use rustc_errors::MultiSpan; +use rustc_errors::{codes::*, MultiSpan}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; @@ -6,7 +6,7 @@ use rustc_span::Span; use crate::diagnostics::RegionName; #[derive(Diagnostic)] -#[diag(borrowck_move_unsized, code = "E0161")] +#[diag(borrowck_move_unsized, code = E0161)] pub(crate) struct MoveUnsized<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -281,7 +281,7 @@ pub(crate) enum CaptureVarCause { } #[derive(Diagnostic)] -#[diag(borrowck_cannot_move_when_borrowed, code = "E0505")] +#[diag(borrowck_cannot_move_when_borrowed, code = E0505)] pub(crate) struct MoveBorrow<'a> { pub place: &'a str, pub borrow_place: &'a str, @@ -294,7 +294,7 @@ pub(crate) struct MoveBorrow<'a> { } #[derive(Diagnostic)] -#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")] +#[diag(borrowck_opaque_type_non_generic_param, code = E0792)] pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { pub ty: GenericArg<'tcx>, pub kind: &'a str, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 21d8026e17089..c97e31701669c 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -5,10 +5,13 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; -use rustc_middle::ty::GenericArgKind; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::solve::deeply_normalize; +use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; +use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use crate::{ constraints::OutlivesConstraint, @@ -34,6 +37,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, + known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, category: ConstraintCategory<'tcx>, @@ -48,6 +52,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, + known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, category: ConstraintCategory<'tcx>, @@ -60,6 +65,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { region_bound_pairs, implicit_region_bound, param_env, + known_type_outlives_obligations, locations, span, category, @@ -136,33 +142,69 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // Extract out various useful fields we'll need below. let ConstraintConversion { - tcx, region_bound_pairs, implicit_region_bound, param_env, .. + tcx, + infcx, + region_bound_pairs, + implicit_region_bound, + known_type_outlives_obligations, + .. } = *self; - let ty::OutlivesPredicate(k1, r2) = predicate; - match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - let r1_vid = self.to_region_vid(r1); - let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid, constraint_category); + let mut outlives_predicates = vec![(predicate, constraint_category)]; + for iteration in 0.. { + if outlives_predicates.is_empty() { + break; } - GenericArgKind::Type(t1) => { - // we don't actually use this for anything, but - // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + if !self.tcx.recursion_limit().value_within_limit(iteration) { + bug!( + "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" + ); + } - TypeOutlives::new( - &mut *self, - tcx, - region_bound_pairs, - Some(implicit_region_bound), - param_env, - ) - .type_must_outlive(origin, t1, r2, constraint_category); + let mut next_outlives_predicates = vec![]; + for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates { + match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + let r1_vid = self.to_region_vid(r1); + let r2_vid = self.to_region_vid(r2); + self.add_outlives(r1_vid, r2_vid, constraint_category); + } + + GenericArgKind::Type(mut t1) => { + // Normalize the type we receive from a `TypeOutlives` obligation + // in the new trait solver. + if infcx.next_trait_solver() { + t1 = self.normalize_and_add_type_outlives_constraints( + t1, + &mut next_outlives_predicates, + ); + } + + // we don't actually use this for anything, but + // the `TypeOutlives` code needs an origin. + let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + + TypeOutlives::new( + &mut *self, + tcx, + region_bound_pairs, + Some(implicit_region_bound), + known_type_outlives_obligations, + ) + .type_must_outlive( + origin, + t1, + r2, + constraint_category, + ); + } + + GenericArgKind::Const(_) => unreachable!(), + } } - GenericArgKind::Const(_) => unreachable!(), + outlives_predicates = next_outlives_predicates; } } @@ -228,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { debug!("add_type_test(type_test={:?})", type_test); self.constraints.type_tests.push(type_test); } + + fn normalize_and_add_type_outlives_constraints( + &self, + ty: Ty<'tcx>, + next_outlives_predicates: &mut Vec<( + ty::OutlivesPredicate, ty::Region<'tcx>>, + ConstraintCategory<'tcx>, + )>, + ) -> Ty<'tcx> { + let result = CustomTypeOp::new( + |ocx| { + deeply_normalize( + ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), + ty, + ) + .map_err(|_| NoSolution) + }, + "normalize type outlives obligation", + ) + .fully_perform(self.infcx, self.span); + + match result { + Ok(TypeOpOutput { output: ty, constraints, .. }) => { + if let Some(constraints) = constraints { + assert!( + constraints.member_constraints.is_empty(), + "no member constraints expected from normalizing: {:#?}", + constraints.member_constraints + ); + next_outlives_predicates.extend(constraints.outlives.iter().copied()); + } + ty + } + Err(_) => ty, + } + } } impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { 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 011b5b760c23a..2e0caf4481902 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_trait_selection::solve::deeply_normalize; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; @@ -45,6 +48,7 @@ type NormalizedInputsAndOutput<'tcx> = Vec>; pub(crate) struct CreateResult<'tcx> { pub(crate) universal_region_relations: Frozen>, pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, + pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } @@ -200,7 +204,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local(); let span = tcx.def_span(defining_ty_def_id); - // Insert the facts we know from the predicates. Why? Why not. + // Insert the `'a: 'b` we know from the predicates. + // This does not consider the type-outlives. let param_env = self.param_env; self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); @@ -217,6 +222,32 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.relate_universal_regions(fr, fr_fn_body); } + // Normalize the assumptions we use to borrowck the program. + let mut constraints = vec![]; + let mut known_type_outlives_obligations = vec![]; + for bound in param_env.caller_bounds() { + let Some(mut outlives) = bound.as_type_outlives_clause() else { continue }; + + // In the new solver, normalize the type-outlives obligation assumptions. + if self.infcx.next_trait_solver() { + match deeply_normalize( + self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), + outlives, + ) { + Ok(normalized_outlives) => { + outlives = normalized_outlives; + } + Err(e) => { + self.infcx.err_ctxt().report_fulfillment_errors(e); + } + } + } + + known_type_outlives_obligations.push(outlives); + } + let known_type_outlives_obligations = + self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); + let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -234,7 +265,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // the `relations` is built. let mut normalized_inputs_and_output = Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); - let mut constraints = vec![]; for ty in unnormalized_input_output_tys { debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty. @@ -299,7 +329,19 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } for c in constraints { - self.push_region_constraints(c, span); + constraint_conversion::ConstraintConversion::new( + self.infcx, + &self.universal_regions, + &self.region_bound_pairs, + self.implicit_region_bound, + param_env, + known_type_outlives_obligations, + Locations::All(span), + span, + ConstraintCategory::Internal, + self.constraints, + ) + .convert_all(c); } CreateResult { @@ -308,29 +350,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { outlives: self.outlives.freeze(), inverse_outlives: self.inverse_outlives.freeze(), }), + known_type_outlives_obligations, region_bound_pairs: self.region_bound_pairs, normalized_inputs_and_output, } } - #[instrument(skip(self, data), level = "debug")] - fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) { - debug!("constraints generated: {:#?}", data); - - constraint_conversion::ConstraintConversion::new( - self.infcx, - &self.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - Locations::All(span), - span, - ConstraintCategory::Internal, - self.constraints, - ) - .convert_all(data); - } - /// Update the type of a single local, which should represent /// either the return type of the MIR or one of its arguments. At /// the same time, compute and add any implied bounds that come diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 59518f68ab149..a5a7ce4ea3e86 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,13 +7,18 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). +use std::assert_matches::assert_matches; + use itertools::Itertools; -use rustc_infer::infer::BoundRegionConversionTime; +use rustc_hir as hir; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use crate::universal_regions::UniversalRegions; +use crate::renumber::RegionCtxt; +use crate::universal_regions::{DefiningTy, UniversalRegions}; use super::{Locations, TypeChecker}; @@ -23,9 +28,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[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(); + if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) { return; } + let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); // Instantiate the canonicalized variables from user-provided signature @@ -34,12 +41,75 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // so that they represent the view from "inside" the closure. let user_provided_sig = self .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig); - let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( + let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( body.span, BoundRegionConversionTime::FnCall, user_provided_sig, ); + // FIXME(async_closures): It's kind of wacky that we must apply this + // transformation here, since we do the same thing in HIR typeck. + // Maybe we could just fix up the canonicalized signature during HIR typeck? + if let DefiningTy::CoroutineClosure(_, args) = + self.borrowck_context.universal_regions.defining_ty + { + assert_matches!( + self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure + )), + "this needs to be modified if we're lowering non-async closures" + ); + // Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated + // into the type. + let args = args.as_coroutine_closure(); + let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( + self.tcx(), + args.kind(), + 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 + }), + ); + + let next_ty_var = || { + self.infcx.next_ty_var(TypeVariableOrigin { + span: body.span, + kind: TypeVariableOriginKind::MiscVariable, + }) + }; + let output_ty = Ty::new_coroutine( + self.tcx(), + self.tcx().coroutine_for_closure(mir_def_id), + ty::CoroutineArgs::new( + self.tcx(), + ty::CoroutineArgsParts { + parent_args: args.parent_args(), + kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()), + return_ty: user_provided_sig.output(), + tupled_upvars_ty, + // For async closures, none of these can be annotated, so just fill + // them with fresh ty vars. + resume_ty: next_ty_var(), + yield_ty: next_ty_var(), + witness: next_ty_var(), + }, + ) + .args, + ); + + user_provided_sig = self.tcx().mk_fn_sig( + user_provided_sig.inputs().iter().copied(), + output_ty, + user_provided_sig.c_variadic, + user_provided_sig.unsafety, + user_provided_sig.abi, + ); + } + let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id()) && user_provided_sig.inputs().is_empty(); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index eec128b5f1d58..18975a4e3b271 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::WithSuccessors; -use rustc_index::bit_set::HybridBitSet; +use rustc_index::bit_set::BitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::for_liveness; @@ -135,7 +135,7 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, /// Set of points that define the current local. - defs: HybridBitSet, + defs: BitSet, /// Points where the current variable is "use live" -- meaning /// that there is a future "full use" that may use its value. @@ -158,7 +158,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { let num_points = cx.elements.num_points(); LivenessResults { cx, - defs: HybridBitSet::new_empty(num_points), + defs: BitSet::new_empty(num_points), use_live_at: IntervalSet::new(num_points), drop_live_at: IntervalSet::new(num_points), drop_locations: vec![], diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index dc071b3594466..369dacd37ffb1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -141,7 +141,7 @@ pub(crate) fn type_check<'mir, 'tcx>( let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), - liveness_constraints: LivenessValues::new(elements.clone()), + liveness_constraints: LivenessValues::with_specific_points(elements.clone()), outlives_constraints: OutlivesConstraintSet::default(), member_constraints: MemberConstraintSet::default(), type_tests: Vec::default(), @@ -152,6 +152,7 @@ pub(crate) fn type_check<'mir, 'tcx>( universal_region_relations, region_bound_pairs, normalized_inputs_and_output, + known_type_outlives_obligations, } = free_region_relations::create( infcx, param_env, @@ -176,6 +177,7 @@ pub(crate) fn type_check<'mir, 'tcx>( body, param_env, ®ion_bound_pairs, + known_type_outlives_obligations, implicit_region_bound, &mut borrowck_context, ); @@ -555,7 +557,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let all_facts = &mut None; let mut constraints = Default::default(); let mut liveness_constraints = - LivenessValues::new(Rc::new(DenseLocationMap::new(promoted_body))); + LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); // Don't try to add borrow_region facts for the promoted MIR let mut swap_constraints = |this: &mut Self| { @@ -594,17 +596,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) } - for region in liveness_constraints.regions() { - // If the region is live at at least one location in the promoted MIR, - // then add a liveness constraint to the main MIR for this region - // at the location provided as an argument to this method - if liveness_constraints.is_live_anywhere(region) { - self.cx - .borrowck_context - .constraints - .liveness_constraints - .add_location(region, location); - } + // If the region is live at at least one location in the promoted MIR, + // then add a liveness constraint to the main MIR for this region + // at the location provided as an argument to this method + // + // add_location doesn't care about ordering so not a problem for the live regions to be + // unordered. + #[allow(rustc::potential_query_instability)] + for region in liveness_constraints.live_regions_unordered() { + self.cx + .borrowck_context + .constraints + .liveness_constraints + .add_location(region, location); } } @@ -800,6 +804,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }), }; } + ty::CoroutineClosure(_, args) => { + return match args.as_coroutine_closure().upvar_tys().get(field.index()) { + Some(&ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: args.as_coroutine_closure().upvar_tys().len(), + }), + }; + } ty::Coroutine(_, args) => { // Only prefix fields (upvars and current state) are // accessible without a variant index. @@ -848,6 +860,7 @@ struct TypeChecker<'a, 'tcx> { /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, + known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, @@ -998,6 +1011,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, + known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, ) -> Self { @@ -1008,6 +1022,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { user_type_annotations: &body.user_type_annotations, param_env, region_bound_pairs, + known_type_outlives_obligations, implicit_region_bound, borrowck_context, reported_errors: Default::default(), @@ -1097,10 +1112,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[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_with_fresh_inference_vars(span, user_ty); - self.ascribe_user_type(inferred_ty, annotation, span); + if let ty::UserType::TypeOf(def, args) = annotation + && let DefKind::InlineConst = tcx.def_kind(def) + { + self.check_inline_const(inferred_ty, def.expect_local(), args, span); + } else { + self.ascribe_user_type(inferred_ty, annotation, span); + } } } @@ -1119,6 +1141,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.region_bound_pairs, self.implicit_region_bound, self.param_env, + self.known_type_outlives_obligations, locations, locations.span(self.body), category, @@ -1193,6 +1216,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 } @@ -1829,6 +1882,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }), } } + 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 => { unreachable!("This should have been covered in check_rvalues"); @@ -1851,7 +1912,12 @@ impl<'a, 'tcx> TypeChecker<'a, '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); + 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, @@ -2427,6 +2493,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { AggregateKind::Tuple => None, AggregateKind::Closure(_, _) => None, AggregateKind::Coroutine(_, _) => None, + AggregateKind::CoroutineClosure(_, _) => None, }, } } @@ -2654,9 +2721,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // desugaring. A closure gets desugared to a struct, and // these extra requirements are basically like where // clauses on the struct. - AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => { - (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location)) - } + AggregateKind::Closure(def_id, args) + | AggregateKind::CoroutineClosure(def_id, args) + | AggregateKind::Coroutine(def_id, args) => ( + def_id, + self.prove_closure_bounds( + tcx, + def_id.expect_local(), + args, + location.to_locations(), + ), + ), AggregateKind::Array(_) | AggregateKind::Tuple => { (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) @@ -2675,7 +2750,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: LocalDefId, args: GenericArgsRef<'tcx>, - location: Location, + locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { constraint_conversion::ConstraintConversion::new( @@ -2684,7 +2759,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.region_bound_pairs, self.implicit_region_bound, self.param_env, - location.to_locations(), + self.known_type_outlives_obligations, + locations, DUMMY_SP, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. self.borrowck_context.constraints, @@ -2697,10 +2773,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); let parent_args = match tcx.def_kind(def_id) { - DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => { - args.as_coroutine().parent_args() + // We don't want to dispatch on 3 different kind of closures here, so take + // advantage of the fact that the `parent_args` is the same length as the + // `typeck_root_args`. + DefKind::Closure => { + // FIXME(async_closures): It may be useful to add a debug assert here + // to actually call `type_of` and check the `parent_args` are the same + // length as the `typeck_root_args`. + &args[..typeck_root_args.len()] } - DefKind::Closure => args.as_closure().parent_args(), DefKind::InlineConst => args.as_inline_const().parent_args(), other => bug!("unexpected item {:?}", other), }; @@ -2710,7 +2791,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Err(_) = self.eq_args( typeck_root_args, parent_args, - location.to_locations(), + locations, ConstraintCategory::BoringNoLocation, ) { span_mirbug!( diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index ae8a135f09059..111eaaf60f7b2 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -97,6 +97,13 @@ pub enum DefiningTy<'tcx> { /// `ClosureArgs::coroutine_return_ty`. Coroutine(DefId, GenericArgsRef<'tcx>), + /// The MIR is a special kind of closure that returns coroutines. + /// + /// See the documentation on `CoroutineClosureSignature` for details + /// on how to construct the callable signature of the coroutine from + /// its args. + CoroutineClosure(DefId, GenericArgsRef<'tcx>), + /// The MIR is a fn item with the given `DefId` and args. The signature /// of the function can be bound then with the `fn_sig` query. FnDef(DefId, GenericArgsRef<'tcx>), @@ -119,6 +126,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn upvar_tys(self) -> &'tcx ty::List> { match self { 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() @@ -131,7 +139,9 @@ impl<'tcx> DefiningTy<'tcx> { /// user's code. pub fn implicit_inputs(self) -> usize { match self { - DefiningTy::Closure(..) | DefiningTy::Coroutine(..) => 1, + DefiningTy::Closure(..) + | DefiningTy::CoroutineClosure(..) + | DefiningTy::Coroutine(..) => 1, DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, } } @@ -147,6 +157,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn def_id(&self) -> DefId { match *self { DefiningTy::Closure(def_id, ..) + | DefiningTy::CoroutineClosure(def_id, ..) | DefiningTy::Coroutine(def_id, ..) | DefiningTy::FnDef(def_id, ..) | DefiningTy::Const(def_id, ..) @@ -355,6 +366,9 @@ impl<'tcx> UniversalRegions<'tcx> { err.note(format!("late-bound region is {:?}", self.to_region_vid(r))); }); } + DefiningTy::CoroutineClosure(..) => { + todo!() + } DefiningTy::Coroutine(def_id, args) => { let v = with_no_trimmed_paths!( args[tcx.generics_of(def_id).parent_count..] @@ -568,6 +582,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { match *defining_ty.kind() { ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args), + ty::CoroutineClosure(def_id, args) => { + DefiningTy::CoroutineClosure(def_id, args) + } ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args), _ => span_bug!( tcx.def_span(self.mir_def), @@ -623,6 +640,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); let fr_args = match defining_ty { DefiningTy::Closure(_, args) + | DefiningTy::CoroutineClosure(_, args) | DefiningTy::Coroutine(_, args) | DefiningTy::InlineConst(_, args) => { // In the case of closures, we rely on the fact that @@ -702,6 +720,55 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ty::Binder::dummy(inputs_and_output) } + // Construct the signature of the CoroutineClosure for the purposes of borrowck. + // This is pretty straightforward -- we: + // 1. first grab the `coroutine_closure_sig`, + // 2. compute the self type (`&`/`&mut`/no borrow), + // 3. flatten the tupled_input_tys, + // 4. construct the correct generator type to return with + // `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`. + // Then we wrap it all up into a list of inputs and output. + DefiningTy::CoroutineClosure(def_id, args) => { + assert_eq!(self.mir_def.to_def_id(), def_id); + let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); + let bound_vars = tcx.mk_bound_variable_kinds_from_iter( + closure_sig + .bound_vars() + .iter() + .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BrEnv, + }; + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + let closure_kind = args.as_coroutine_closure().kind(); + + let closure_ty = tcx.closure_env_ty( + Ty::new_coroutine_closure(tcx, def_id, args), + closure_kind, + env_region, + ); + + let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields(); + let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(def_id), + closure_kind, + env_region, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ); + + ty::Binder::bind_with_vars( + tcx.mk_type_list_from_iter( + iter::once(closure_ty).chain(inputs).chain(iter::once(output)), + ), + bound_vars, + ) + } + DefiningTy::FnDef(def_id, _) => { let sig = tcx.fn_sig(def_id).instantiate_identity(); let sig = indices.fold_to_region_vids(tcx, sig); diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 4f7c0266343ca..a01bbeac82497 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -54,7 +54,7 @@ fn invalid_type_err( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), )) => { - assert!(val > u8::MAX.into()); // must be an error + assert!(val.get() > u8::MAX.into()); // must be an error dcx.emit_err(ConcatBytesOob { span }); } Ok(ast::LitKind::Int(_, _)) => { @@ -86,7 +86,7 @@ fn handle_array_element( Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) if val <= u8::MAX.into() => Some(val as u8), + )) if val.get() <= u8::MAX.into() => Some(val.get() as u8), Ok(ast::LitKind::Byte(val)) => Some(val), Ok(ast::LitKind::ByteStr(..)) => { @@ -148,7 +148,7 @@ pub fn expand_concat_bytes( if let Some(elem) = handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) { - for _ in 0..count_val { + for _ in 0..count_val.get() { accumulator.push(elem); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 14ae999427dff..ce3fa1ab32c6a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -19,19 +19,6 @@ pub fn expand_deriving_eq( ) { let span = cx.with_def_site_ctxt(span); - let structural_trait_def = TraitDef { - span, - path: path_std!(marker::StructuralEq), - skip_path_as_bound: true, // crucial! - needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), - supports_unions: true, - methods: Vec::new(), - associated_types: Vec::new(), - is_const: false, - }; - structural_trait_def.expand(cx, mitem, item, push); - let trait_def = TraitDef { span, path: path_std!(cmp::Eq), diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d6dfd0efaf913..eadb48ddd36d8 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, - MultiSpan, SingleLabelManySpans, + codes::*, AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + Level, MultiSpan, SingleLabelManySpans, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -269,7 +269,7 @@ pub(crate) struct ConcatIdentsIdentArgs { } #[derive(Diagnostic)] -#[diag(builtin_macros_bad_derive_target, code = "E0774")] +#[diag(builtin_macros_bad_derive_target, code = E0774)] pub(crate) struct BadDeriveTarget { #[primary_span] #[label] @@ -283,7 +283,7 @@ pub(crate) struct BadDeriveTarget { pub(crate) struct TestsNotSupport {} #[derive(Diagnostic)] -#[diag(builtin_macros_unexpected_lit, code = "E0777")] +#[diag(builtin_macros_unexpected_lit, code = E0777)] pub(crate) struct BadDeriveLit { #[primary_span] #[label] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 93381b69fdcc1..b66f7111ff006 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -139,7 +139,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< _ => { let expr = p.parse_expr()?; if !args.named_args().is_empty() { - ecx.dcx().emit_err(errors::PositionalAfterNamed { + return Err(ecx.dcx().create_err(errors::PositionalAfterNamed { span: expr.span, args: args .named_args() @@ -147,7 +147,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< .filter_map(|a| a.kind.ident().map(|ident| (a, ident))) .map(|(arg, n)| n.span.to(arg.expr.span)) .collect(), - }); + })); } args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr }); } @@ -313,6 +313,8 @@ fn make_format_args( } use ArgRef::*; + let mut unnamed_arg_after_named_arg = false; + let mut lookup_arg = |arg: ArgRef<'_>, span: Option, used_as: PositionUsedAs, @@ -352,6 +354,7 @@ fn make_format_args( // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); + unnamed_arg_after_named_arg = true; DummyResult::raw_expr(span, true) }; Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) @@ -510,7 +513,8 @@ fn make_format_args( }) .collect::>(); - if !unused.is_empty() { + let has_unused = !unused.is_empty(); + if has_unused { // If there's a lot of unused arguments, // let's check if this format arguments looks like another syntax (printf / shell). let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2; @@ -529,7 +533,7 @@ fn make_format_args( // Only check for unused named argument names if there are no other errors to avoid causing // too much noise in output errors, such as when a named argument is entirely unused. - if invalid_refs.is_empty() && ecx.dcx().err_count() == 0 { + if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg { for &(index, span, used_as) in &numeric_refences_to_named_arg { let (position_sp_to_replace, position_sp_for_msg) = match used_as { Placeholder(pspan) => (span, pspan), diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index f60b73fbe9b13..4d7957ef4ddb0 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,16 +5,14 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(array_windows)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(is_sorted)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] -#![recursion_limit = "256"] extern crate proc_macro; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 4d44e340ae149..0631f796894b1 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -9,6 +9,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, Level}; use rustc_expand::base::*; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; +use std::assert_matches::assert_matches; use std::iter; use thin_vec::{thin_vec, ThinVec}; @@ -182,6 +183,16 @@ pub fn expand_test_or_bench( // creates $name: $expr let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr); + // Adds `#[coverage(off)]` to a closure, so it won't be instrumented in + // `-Cinstrument-coverage` builds. + // This requires `#[allow_internal_unstable(coverage_attribute)]` on the + // corresponding macro declaration in `core::macros`. + let coverage_off = |mut expr: P| { + assert_matches!(expr.kind, ast::ExprKind::Closure(_)); + expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp)); + expr + }; + let test_fn = if is_bench { // A simple ident for a lambda let b = Ident::from_str_and_span("b", attr_sp); @@ -190,8 +201,9 @@ pub fn expand_test_or_bench( sp, cx.expr_path(test_path("StaticBenchFn")), thin_vec![ + // #[coverage(off)] // |b| self::test::assert_test_result( - cx.lambda1( + coverage_off(cx.lambda1( sp, cx.expr_call( sp, @@ -206,7 +218,7 @@ pub fn expand_test_or_bench( ], ), b, - ), // ) + )), // ) ], ) } else { @@ -214,8 +226,9 @@ pub fn expand_test_or_bench( sp, cx.expr_path(test_path("StaticTestFn")), thin_vec![ + // #[coverage(off)] // || { - cx.lambda0( + coverage_off(cx.lambda0( sp, // test::assert_test_result( cx.expr_call( @@ -230,7 +243,7 @@ pub fn expand_test_or_bench( ), // ) ], ), // } - ), // ) + )), // ) ], ) }; diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml index bd3b051185b46..e6bf944f5527b 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml @@ -33,14 +33,14 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features if: matrix.os == 'ubuntu-latest' run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml index 3efdec4155932..b4f8ce0f5329d 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml @@ -10,7 +10,7 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: | sed -i 's/components.*/components = []/' rust-toolchain echo 'profile = "minimal"' >> rust-toolchain diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 9bbb18fc37fca..cf9a105538df4 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -10,7 +10,7 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Avoid installing rustc-dev run: | @@ -64,14 +64,14 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features if: matrix.os == 'ubuntu-latest' run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -138,7 +138,7 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo @@ -164,13 +164,13 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -221,10 +221,10 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -276,7 +276,7 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Download all built artifacts uses: actions/download-artifact@v4 diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index 8085dc58263cc..930d025b73edc 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -9,13 +9,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -32,13 +32,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index 834a1362caf32..491646ce59bb3 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -1,8 +1,9 @@ { "editor.formatOnSave": true, - // source for rustc_* is not included in the rust-src component; disable the errors about this + // in case rustc.source is disabled for performance reasons; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], + "rust-analyzer.rustc.source": "discover", "rust-analyzer.imports.granularity.enforce": true, "rust-analyzer.imports.granularity.group": "module", "rust-analyzer.imports.prefix": "crate", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 74e7afee7bcb2..b70a1234af398 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -4,13 +4,14 @@ version = 3 [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -45,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c22542c0b95bd3302f7ed6839869c561f2324bac2fd5e7e99f5cfa65fdc8b92" +checksum = "d819feeda4c420a18f1e28236ca0ce1177b22bf7c8a44ddee92dfe40de15bcf0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3db903ef2e9c8a4de2ea6db5db052c7857282952f9df604aa55d169e6000d8" +checksum = "e9b8d03d5bdbca7e5f72b0e0a0f69933ed1f09e24be6c075aa6fe3f802b0cc0c" dependencies = [ "bumpalo", "cranelift-bforest", @@ -75,39 +76,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6590feb5a1d6438f974bf6a5ac4dddf69fca14e1f07f3265d880f69e61a94463" +checksum = "a3fd3664e38e51649b17dc30cfdd561273fe2f590dcd013fb75d9eabc6272dfb" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7239038c56fafe77fddc8788fc8533dd6c474dc5bdc5637216404f41ba807330" +checksum = "4b031ec5e605828975952622b5a77d49126f20ffe88d33719a0af66b23a0fc36" [[package]] name = "cranelift-control" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dc9c595341404d381d27a3d950160856b35b402275f0c3990cd1ad683c8053" +checksum = "fada054d017cf2ed8f7ed2336e0517fc1b19e6825be1790de9eb00c94788362b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e3ee532fc4776c69bcedf7e62f9632cbb3f35776fa9a525cdade3195baa3f7" +checksum = "177b6f94ae8de6348eb45bf977c79ab9e3c40fc3ac8cb7ed8109560ea39bee7d" [[package]] name = "cranelift-frontend" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a612c94d09e653662ec37681dc2d6fd2b9856e6df7147be0afc9aabb0abf19df" +checksum = "ebebd23a69a23e3ddea78e98ff3a2de222e88c8e045d81ef4a72f042e0d79dbd" dependencies = [ "cranelift-codegen", "log", @@ -117,15 +118,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85db9830abeb1170b7d29b536ffd55af1d4d26ac8a77570b5d1aca003bf225cc" +checksum = "1571bfc14df8966d12c6121b5325026591a4b4009e22fea0fe3765ab7cd33b96" [[package]] name = "cranelift-jit" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4946271f1055e26544ef8c90fa24776f201566419dfac4b3962c39d5a804ff67" +checksum = "2f61e236d7622c3c43016e8b0f3ba27136e21ac7de328c7fda902e61db1de851" dependencies = [ "anyhow", "cranelift-codegen", @@ -138,14 +139,14 @@ dependencies = [ "region", "target-lexicon", "wasmtime-jit-icache-coherence", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "cranelift-module" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7e3bdae2597556e59edeb8ecb62eb32c7e054c4f042d393732902979db69c3" +checksum = "f30c6820342015c5009070e3e48d1da7b13521399de904663f1c84f5ee839657" dependencies = [ "anyhow", "cranelift-codegen", @@ -154,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301ef0edafeaeda5771a5d2db64ac53e1818ae3111220a185677025fe91db4a1" +checksum = "35a69c37e0c10b46fe5527f2397ac821046efbf5f7ec112c8b84df25712f465b" dependencies = [ "cranelift-codegen", "libc", @@ -165,9 +166,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e0ee3d013728903e0c513c31afa389b559bfd4fe8a44f80335c799e3132a41" +checksum = "24425a329b4343177d5f1852243841dcec17f929d72c0e7f41262140155e55e7" dependencies = [ "anyhow", "cranelift-codegen", @@ -246,12 +247,12 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -293,6 +294,24 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "proc-macro2" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + [[package]] name = "regalloc2" version = "0.9.3" @@ -360,12 +379,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "syn" +version = "2.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "target-lexicon" version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "version_check" version = "0.9.4" @@ -374,13 +410,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b6d197fcc34ad32ed440e1f9552fd57d1f377d9699d31dee1b5b457322c1f8a" +checksum = "bdc26415bb89e9ccd3bdc498fef63aabf665c4c0dd710c107691deb9694955da" dependencies = [ "cfg-if", "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -411,7 +447,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -420,13 +465,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -435,38 +495,100 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index fdac789423c9c..586ce2286f971 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,18 +8,18 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.103", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.103" } -cranelift-module = { version = "0.103" } -cranelift-native = { version = "0.103" } -cranelift-jit = { version = "0.103", optional = true } -cranelift-object = { version = "0.103" } +cranelift-codegen = { version = "0.104", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.104" } +cranelift-module = { version = "0.104" } +cranelift-native = { version = "0.104" } +cranelift-jit = { version = "0.104", optional = true } +cranelift-object = { version = "0.104" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" -libloading = { version = "0.7.3", optional = true } +libloading = { version = "0.8.0", optional = true } smallvec = "1.8.1" [patch.crates-io] diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index ca6ecdf1d0e88..4f45526196397 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -62,6 +62,27 @@ $ ./test.sh For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`. +## Platform support + +|OS \ architecture|x86\_64|AArch64|Riscv64|s390x (System-Z)| +|---|---|---|---|---| +|Linux|✅|✅|✅[^no-rustup]|✅[^no-rustup]| +|FreeBSD|✅[^no-rustup]|❓|❓|❓| +|AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| +|Other unixes|❓|❓|❓|❓| +|macOS|✅|❌[^apple-silicon]|N/A|N/A| +|Windows|✅[^no-rustup]|❌|N/A|N/A| + +✅: Fully supported and tested +❓: Maybe supported, not tested +❌: Not supported at all + +Not all targets are available as rustup component for nightly. See notes in the platform support matrix. + +[^xcoff]: XCOFF object file format is not supported. +[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248). +[^no-rustup]: Not available as rustup component for nightly. You can build it yourself. + ## Usage rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. @@ -100,6 +121,8 @@ You need to do this steps to successfully compile and use the cranelift backend * (Optional) run tests: `rustup run stage2 ./y.sh test` 8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. +You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes. + ## Configuration See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index cb7b2454cd5ed..818f3d6f08d26 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -113,8 +113,8 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rust-random", "rand", - "9a02c819cc1e4ec6959ae25eafbb5cf6acb68234", - "4934f0afb1d1c2ca", + "1f4507a8e1cf8050e4ceef95eeda8f64645b6719", + "981f8bf489338978", "rand", ); @@ -133,8 +133,8 @@ pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( "rust-lang", "portable-simd", - "4825b2a64d765317066948867e8714674419359b", - "9e67d07c00f5fb0b", + "97007cc2e70df8c97326ce896a79e2f0ce4dd98b", + "e54a16035cedf205", "portable-simd", ); diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 3607b7cd9448b..a79909ce0c878 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -104,9 +104,6 @@ unsafe impl Freeze for &mut T {} #[lang = "structural_peq"] pub trait StructuralPartialEq {} -#[lang = "structural_teq"] -pub trait StructuralEq {} - #[lang = "not"] pub trait Not { type Output; diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch deleted file mode 100644 index b8c0783f52430..0000000000000 --- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch +++ /dev/null @@ -1,22 +0,0 @@ -From a101a43b795431ce617e7782afb451f4853afc00 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Thu, 7 Dec 2023 14:51:35 +0000 -Subject: [PATCH] Enable the exposed_provenance feature - ---- - crates/core_simd/tests/pointers.rs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs -index 0ae8f83..06620d6 100644 ---- a/crates/core_simd/tests/pointers.rs -+++ b/crates/core_simd/tests/pointers.rs -@@ -1,4 +1,4 @@ --#![feature(portable_simd, strict_provenance)] -+#![feature(exposed_provenance, portable_simd, strict_provenance)] - - use core_simd::simd::{Simd, SimdConstPtr, SimdMutPtr}; - --- -2.34.1 - diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch index be29ae09bcfc6..271ca12eabbcd 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch @@ -21,7 +21,7 @@ index 897a5e9..331f66f 100644 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] - #![feature(slice_group_by)] + #![feature(split_array)] diff --git a/atomic.rs b/atomic.rs index b735957..ea728b6 100644 --- a/atomic.rs diff --git a/compiler/rustc_codegen_cranelift/patches/rand-lock.toml b/compiler/rustc_codegen_cranelift/patches/rand-lock.toml index aacf3653c169e..815b828a68bd6 100644 --- a/compiler/rustc_codegen_cranelift/patches/rand-lock.toml +++ b/compiler/rustc_codegen_cranelift/patches/rand-lock.toml @@ -487,6 +487,7 @@ dependencies = [ "rand_pcg", "rayon", "serde", + "zerocopy", ] [[package]] @@ -505,6 +506,7 @@ version = "0.7.0" dependencies = [ "getrandom", "serde", + "zerocopy", ] [[package]] @@ -525,6 +527,7 @@ name = "rand_pcg" version = "0.4.0" dependencies = [ "bincode", + "rand", "rand_core", "serde", ] @@ -823,3 +826,23 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml index 8e213f71c3f38..ad63b0768d313 100644 --- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml +++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.104" +version = "0.1.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3f9035afc33f4358773239573f7d121099856753e1bbd2a6a5207098fc741" +checksum = "f4ab134a739bafec76aa91ccb15d519a54e569350644a1fea6528d5a0d407e22" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index a086c0293601f..ccd7edbc2a917 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-31" +channel = "nightly-2024-01-26" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index abd70dd4458f6..0f0d828c8fc3f 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -56,11 +56,7 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); } - Conv::Msp430Intr - | Conv::PtxKernel - | Conv::AmdGpuKernel - | Conv::AvrInterrupt - | Conv::AvrNonBlockingInterrupt => { + Conv::Msp430Intr | Conv::PtxKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index cc290a81505a9..dfceafe010350 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -682,7 +682,6 @@ fn codegen_stmt<'tcx>( args, ty::ClosureKind::FnOnce, ) - .expect("failed to normalize and resolve closure during codegen") .polymorphize(fx.tcx); let func_ref = fx.get_function_ref(instance); let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index e6edc452cfb08..2d9c2ecdbc2be 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -13,17 +13,14 @@ use gimli::write::{ }; use gimli::{Encoding, Format, LineEncoding, RunTimeEndian}; use indexmap::IndexSet; +use rustc_session::Session; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; pub(crate) use self::unwind::UnwindContext; use crate::prelude::*; -pub(crate) fn producer() -> String { - format!( - "rustc version {} with cranelift {}", - rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), - cranelift_codegen::VERSION, - ) +pub(crate) fn producer(sess: &Session) -> String { + format!("rustc version {} with cranelift {}", sess.cfg_version, cranelift_codegen::VERSION) } pub(crate) struct DebugContext { @@ -67,7 +64,7 @@ impl DebugContext { let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen(); - let producer = producer(); + let producer = producer(tcx.sess); let comp_dir = tcx .sess .opts diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index e77b0cd0721b2..757082a5fed1c 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -143,6 +143,7 @@ fn emit_cgu( debug: Option, unwind_context: UnwindContext, global_asm_object_file: Option, + producer: &str, ) -> Result { let mut product = module.finish(); @@ -152,8 +153,14 @@ fn emit_cgu( unwind_context.emit(&mut product); - let module_regular = - emit_module(output_filenames, prof, product.object, ModuleKind::Regular, name.clone())?; + let module_regular = emit_module( + output_filenames, + prof, + product.object, + ModuleKind::Regular, + name.clone(), + producer, + )?; Ok(ModuleCodegenResult { module_regular, @@ -174,6 +181,7 @@ fn emit_module( mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, name: String, + producer_str: &str, ) -> Result { if object.format() == cranelift_object::object::BinaryFormat::Elf { let comment_section = object.add_section( @@ -182,7 +190,7 @@ fn emit_module( cranelift_object::object::SectionKind::OtherString, ); let mut producer = vec![0]; - producer.extend(crate::debuginfo::producer().as_bytes()); + producer.extend(producer_str.as_bytes()); producer.push(0); object.set_section_data(comment_section, producer, 1); } @@ -321,6 +329,8 @@ fn module_codegen( (cgu_name, cx, module, codegened_functions) }); + let producer = crate::debuginfo::producer(tcx.sess); + OngoingModuleCodegen::Async(std::thread::spawn(move || { cx.profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| { cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( @@ -348,6 +358,7 @@ fn module_codegen( cx.debug_context, cx.unwind_context, global_asm_object_file, + &producer, ) }); std::mem::drop(token); @@ -453,6 +464,7 @@ pub(crate) fn run_aot( product.object, ModuleKind::Allocator, "allocator_shim".to_owned(), + &crate::debuginfo::producer(tcx.sess), ) { Ok(allocator_module) => Some(allocator_module), Err(err) => tcx.dcx().fatal(err), @@ -467,7 +479,7 @@ pub(crate) fn run_aot( let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")) + .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) .as_str() .to_string(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 50d9f287e74c9..6b2b946db02b6 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -321,10 +321,9 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - sess.dcx() - .struct_err(format!("Can't load static lib {}", name)) - .note("rustc_codegen_cranelift can only load dylibs in JIT mode.") - .emit(); + let mut diag = sess.dcx().struct_err(format!("Can't load static lib {}", name)); + diag.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); + diag.emit(); } Linkage::Dynamic => { dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 6b9cec39d7020..7793b1b70924b 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -52,7 +52,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( } let operands = operands - .into_iter() + .iter() .map(|operand| match *operand { InlineAsmOperand::In { reg, ref value } => CInlineAsmOperand::In { reg, @@ -506,10 +506,34 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push('%'); } - self.registers[*operand_idx] - .unwrap() - .emit(&mut generated_asm, self.arch, *modifier) - .unwrap(); + + let reg = self.registers[*operand_idx].unwrap(); + match self.arch { + InlineAsmArch::X86_64 => match reg { + InlineAsmReg::X86(reg) + if reg as u32 >= X86InlineAsmReg::xmm0 as u32 + && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + { + // rustc emits x0 rather than xmm0 + let class = match *modifier { + None | Some('x') => "xmm", + Some('y') => "ymm", + Some('z') => "zmm", + _ => unreachable!(), + }; + write!( + generated_asm, + "{class}{}", + reg as u32 - X86InlineAsmReg::xmm0 as u32 + ) + .unwrap(); + } + _ => reg + .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) + .unwrap(), + }, + _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), + } } CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); @@ -739,7 +763,7 @@ fn call_inline_asm<'tcx>( }, ) .unwrap(); - let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); + let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(inline_asm_func, asm_name); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 1345c4614e254..e50c74b87f603 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -35,6 +35,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( } match intrinsic { + "llvm.prefetch" => { + // Nothing to do. This is merely a perf hint. + } + _ if intrinsic.starts_with("llvm.ctlz.v") => { intrinsic_args!(fx, args => (a); intrinsic); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index f6f3b85d3ef81..e66bcbf4e40e5 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -243,6 +243,20 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( } // FIXME generalize vector types + "llvm.aarch64.neon.tbl1.v8i8" => { + intrinsic_args!(fx, args => (t, idx); intrinsic); + + let zero = fx.bcx.ins().iconst(types::I8, 0); + for i in 0..8 { + let idx_lane = idx.value_lane(fx, i).load_scalar(fx); + let is_zero = + fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, idx_lane, 16); + let t_idx = fx.bcx.ins().uextend(fx.pointer_type, idx_lane); + let t_lane = t.value_lane_dyn(fx, t_idx).load_scalar(fx); + let res = fx.bcx.ins().select(is_zero, zero, t_lane); + ret.place_lane(fx, i).to_ptr().store(fx, res, MemFlags::trusted()); + } + } "llvm.aarch64.neon.tbl1.v16i8" => { intrinsic_args!(fx, args => (t, idx); intrinsic); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 994dc66835cde..2e3e7ce986b36 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -610,230 +610,56 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi16&ig_expand=4903 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); + "llvm.x86.sse2.packsswb.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi16&ig_expand=4848 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Sse); } "llvm.x86.avx2.packuswb" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi16&ig_expand=4906 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Avx); } - "llvm.x86.sse2.packssdw.128" => { - // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + "llvm.x86.avx2.packsswb" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi16&ig_expand=4851 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Avx); } "llvm.x86.sse41.packusdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi32&ig_expand=4912 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.u16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MIN)); - let max_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MAX)); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u16); + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.sse2.packssdw.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.avx2.packusdw" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi32&ig_expand=4883 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Avx); } "llvm.x86.avx2.packssdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi32&ig_expand=4892 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Avx); } "llvm.x86.fma.vfmaddsub.ps" @@ -1407,3 +1233,115 @@ fn llvm_add_sub<'tcx>( (cb_out, c) } + +enum PackSize { + U8, + U16, + S8, + S16, +} + +impl PackSize { + fn ret_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I8, + Self::U16 | Self::S16 => types::I16, + } + } + fn src_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I16, + Self::U16 | Self::S16 => types::I32, + } + } + fn src_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 | Self::S8 => tcx.types.i16, + Self::U16 | Self::S16 => tcx.types.i32, + } + } + fn ret_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 => tcx.types.u8, + Self::S8 => tcx.types.i8, + Self::U16 => tcx.types.u16, + Self::S16 => tcx.types.i16, + } + } + fn max(&self) -> i64 { + match self { + Self::U8 => u8::MAX as u64 as i64, + Self::S8 => i8::MAX as u8 as u64 as i64, + Self::U16 => u16::MAX as u64 as i64, + Self::S16 => i16::MAX as u64 as u64 as i64, + } + } + fn min(&self) -> i64 { + match self { + Self::U8 | Self::U16 => 0, + Self::S8 => i16::from(i8::MIN) as u16 as i64, + Self::S16 => i32::from(i16::MIN) as u32 as i64, + } + } +} + +enum PackWidth { + Sse = 1, + Avx = 2, +} +impl PackWidth { + fn divisor(&self) -> u64 { + match self { + Self::Sse => 1, + Self::Avx => 2, + } + } +} + +/// Implement an x86 pack instruction with the intrinsic `_mm{,256}pack{us,s}_epi{16,32}`. +/// Validated for correctness against LLVM, see commit `c8f5d35508e062bd2d95e6c03429bfec831db6d3`. +fn pack_instruction<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + a: CValue<'tcx>, + b: CValue<'tcx>, + ret: CPlace<'tcx>, + ret_size: PackSize, + width: PackWidth, +) { + assert_eq!(a.layout(), b.layout()); + let layout = a.layout(); + + let (src_lane_count, src_lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(src_lane_ty, ret_size.src_ty(fx.tcx)); + assert_eq!(ret_lane_ty, ret_size.ret_ty(fx.tcx)); + assert_eq!(src_lane_count * 2, ret_lane_count); + + let min = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.min()); + let max = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.max()); + let ret_lane_layout = fx.layout_of(ret_size.ret_ty(fx.tcx)); + + let mut round = |source: CValue<'tcx>, source_offset: u64, dest_offset: u64| { + let step_amount = src_lane_count / width.divisor(); + let dest_offset = step_amount * dest_offset; + for idx in 0..step_amount { + let lane = source.value_lane(fx, step_amount * source_offset + idx).load_scalar(fx); + let sat = fx.bcx.ins().smax(lane, min); + let sat = match ret_size { + PackSize::U8 | PackSize::U16 => fx.bcx.ins().umin(sat, max), + PackSize::S8 | PackSize::S16 => fx.bcx.ins().smin(sat, max), + }; + let res = fx.bcx.ins().ireduce(ret_size.ret_clif_type(), sat); + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, dest_offset + idx).write_cvalue(fx, res_lane); + } + }; + + round(a, 0, 0); + round(b, 0, 1); + + if let PackWidth::Avx = width { + round(a, 1, 2); + round(b, 1, 3); + } +} diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 195fc6396ba5d..adb32098c1720 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -438,6 +438,12 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().trap(TrapCode::User(0)); return; } + sym::is_val_statically_known => { + intrinsic_args!(fx, args => (_a); intrinsic); + + let res = fx.bcx.ins().iconst(types::I8, 0); + ret.write_cvalue(fx, CValue::by_val(res, ret.layout())); + } sym::breakpoint => { intrinsic_args!(fx, args => (); intrinsic); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index d56d17892d5b6..ebdc744bcd833 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -293,7 +293,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } ret.write_cvalue(fx, base); - let ret_lane = ret.place_lane(fx, idx.try_into().unwrap()); + let ret_lane = ret.place_lane(fx, idx.into()); ret_lane.write_cvalue(fx, val); } @@ -340,7 +340,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); } - let ret_lane = v.value_lane(fx, idx.try_into().unwrap()); + let ret_lane = v.value_lane(fx, idx.into()); ret.write_cvalue(fx, ret_lane); } @@ -822,7 +822,35 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); let lane_layout = fx.layout_of(lane_ty); - let m = m.load_scalar(fx); + let expected_int_bits = lane_count.max(8); + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + + let m = match m.layout().ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => m.load_scalar(fx), + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + m.force_stack(fx).0.load( + fx, + Type::int(expected_int_bits as u16).unwrap(), + MemFlags::trusted(), + ) + } + _ => { + fx.tcx.dcx().span_fatal( + span, + format!( + "invalid monomorphization of `simd_select_bitmask` intrinsic: \ + cannot accept `{}` as mask, expected `u{}` or `[u8; {}]`", + ret.layout().ty, + expected_int_bits, + expected_bytes + ), + ); + } + }; for lane in 0..lane_count { let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(lane) as i64); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index b482f0dd2f0ab..416f87fcc87b3 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -18,7 +18,6 @@ extern crate rustc_fs_util; extern crate rustc_hir; extern crate rustc_incremental; extern crate rustc_index; -extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_session; extern crate rustc_span; @@ -42,7 +41,7 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; pub use crate::config::*; use crate::prelude::*; @@ -190,8 +189,17 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { - vec![] // FIXME necessary for #[cfg(target_feature] + fn target_features(&self, sess: &Session, _allow_unstable: bool) -> 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" { + // x86_64 mandates SSE2 support + vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")] + } else if sess.target.arch == "aarch64" && sess.target.os != "none" { + // AArch64 mandates Neon support + vec![sym::neon] + } else { + vec![] + } } fn print_version(&self) { @@ -305,16 +313,13 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { - let builder = cranelift_native::builder_with_options(true).unwrap(); - builder - } + Some("native") => cranelift_native::builder_with_options(true).unwrap(), Some(value) => { let mut builder = cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| { sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err)); }); - if let Err(_) = builder.enable(value) { + if builder.enable(value).is_err() { sess.dcx() .fatal("the specified target cpu isn't currently supported by Cranelift."); } diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f777e11371f13..acfa461a6f30b 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -28,10 +28,9 @@ pub(crate) fn unsized_info<'tcx>( .bcx .ins() .iconst(fx.pointer_type, len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64), - ( - &ty::Dynamic(ref data_a, _, src_dyn_kind), - &ty::Dynamic(ref data_b, _, target_dyn_kind), - ) if src_dyn_kind == target_dyn_kind => { + (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) + if src_dyn_kind == target_dyn_kind => + { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 41ea0b122de73..d2254d4c15e6f 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -95,7 +95,7 @@ pub(crate) fn get_vtable<'tcx>( let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); let data_id = data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id)); } diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index db94bc1c86af9..230009741dc41 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -100,9 +100,6 @@ unsafe impl Freeze for &mut T {} #[lang = "structural_peq"] pub trait StructuralPartialEq {} -#[lang = "structural_teq"] -pub trait StructuralEq {} - #[lang = "not"] pub trait Not { type Output; diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 9f361d3688695..142f86b003ddb 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -62,9 +62,6 @@ pub fn from_fn_attrs<'gcc, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { func.add_attribute(FnAttribute::Cold); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) { - func.add_attribute(FnAttribute::ReturnsTwice); - } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) { func.add_attribute(FnAttribute::Pure); } diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 053f759329fb1..5760d96165ddf 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -196,15 +196,16 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let mut functions = FxHashMap::default(); let builtins = [ - "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow", - "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ + "__builtin_unreachable", "abort", "__builtin_expect", /*"__builtin_expect_with_probability",*/ + "__builtin_constant_p", "__builtin_add_overflow", "__builtin_mul_overflow", "__builtin_saddll_overflow", + /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow", "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow", "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos", "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf", "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf", "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round", - "__builtin_expect_with_probability", + ]; for builtin in builtins.iter() { diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index e9283b1989453..cc0fbe46dcc11 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -35,7 +35,7 @@ pub(crate) enum PossibleFeature<'a> { struct ExitCode(Option); impl IntoDiagnosticArg for ExitCode { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { let ExitCode(exit_code) = self; match exit_code { Some(t) => t.into_diagnostic_arg(), diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 508abed726037..56592f92d680f 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -117,6 +117,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let func = unsafe { std::mem::transmute(simple.expect("simple")) }; self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) }, + sym::is_val_statically_known => { + let a = args[0].immediate(); + let builtin = self.context.get_builtin_function("__builtin_constant_p"); + let res = self.context.new_call(None, builtin, &[a]); + self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) + } kw::Try => { try_intrinsic( self, diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 03f8f43ff1643..f8f054db65ede 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -408,7 +408,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &Locke .filter(|_feature| { target_info.cpu_supports(_feature) /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma, + 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 diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index e5c0b2de4ca46..25149b8020162 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -87,7 +87,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str if !cx.sess().fewer_names() => { let mut name = with_no_trimmed_paths!(layout.ty.to_string()); diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index 0b933754c2937..e7c46ae3fcc81 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -61,9 +61,6 @@ mod libc { #[lang = "structural_peq"] pub trait StructuralPartialEq {} -#[lang = "structural_teq"] -pub trait StructuralEq {} - #[lang = "drop_in_place"] #[allow(unconditional_recursion)] pub unsafe fn drop_in_place(to_drop: *mut T) { diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 7a86ddc7556a0..d14fe0299e64c 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -28,6 +28,8 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two = codegen_llvm_invalid_minimum_alignment_too_large = invalid minimum global alignment: {$align} is too large +codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`" + codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}" codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err} @@ -39,6 +41,9 @@ codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdy codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type without `-Zdylib-lto` +codegen_llvm_mismatch_data_layout = + data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}` + codegen_llvm_missing_features = add the missing features in a `target_feature` attribute diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 0718bebb31bf8..b5b4f894e4d82 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -590,7 +590,6 @@ impl From for llvm::CallConv { Conv::Cold => llvm::ColdCallConv, Conv::PreserveMost => llvm::PreserveMost, Conv::PreserveAll => llvm::PreserveAll, - Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::AvrInterrupt => llvm::AvrInterrupt, Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, Conv::ArmAapcs => llvm::ArmAapcsCallConv, diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 0a7ea5994312e..07c83f1aa089a 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -356,9 +356,6 @@ pub fn from_fn_attrs<'ll, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { to_add.push(AttributeKind::Cold.create_attr(cx.llcx)); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) { - to_add.push(AttributeKind::ReturnsTwice.create_attr(cx.llcx)); - } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) { to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx)); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1d1b6e6148dd2..7dfcf1ab50e41 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; use libc::c_uint; +use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::ffi::CStr; use std::str; @@ -145,10 +146,17 @@ pub unsafe fn create_module<'ll>( .replace("-Fi64", ""); } } + if llvm_version < (18, 0, 0) { + if sess.target.arch == "x86" || sess.target.arch == "x86_64" { + // LLVM 18 adjusts i128 to be 128-bit aligned on x86 variants. + // Earlier LLVMs leave this as default alignment, so remove it. + // See https://reviews.llvm.org/D86310 + target_data_layout = target_data_layout.replace("-i128:128", ""); + } + } // Ensure the data-layout values hardcoded remain the defaults. - if sess.target.is_builtin { - // tm is disposed by its drop impl + { let tm = crate::back::write::create_informational_target_machine(tcx.sess); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); @@ -156,33 +164,13 @@ pub unsafe fn create_module<'ll>( let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) .expect("got a non-UTF8 data-layout from LLVM"); - // Unfortunately LLVM target specs change over time, and right now we - // don't have proper support to work with any more than one - // `data_layout` than the one that is in the rust-lang/rust repo. If - // this compiler is configured against a custom LLVM, we may have a - // differing data layout, even though we should update our own to use - // that one. - // - // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we - // disable this check entirely as we may be configured with something - // that has a different target layout. - // - // Unsure if this will actually cause breakage when rustc is configured - // as such. - // - // FIXME(#34960) - let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); - - if !custom_llvm_used && target_data_layout != llvm_data_layout { - bug!( - "data-layout for target `{rustc_target}`, `{rustc_layout}`, \ - differs from LLVM target's `{llvm_target}` default layout, `{llvm_layout}`", - rustc_target = sess.opts.target_triple, - rustc_layout = target_data_layout, - llvm_target = sess.target.llvm_target, - llvm_layout = llvm_data_layout - ); + if target_data_layout != llvm_data_layout { + tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + rustc_target: sess.opts.target_triple.to_string().as_str(), + rustc_layout: target_data_layout.as_str(), + llvm_target: sess.target.llvm_target.borrow(), + llvm_layout: llvm_data_layout, + }); } } @@ -908,6 +896,21 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void); ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void); + // FIXME: This is an infinitesimally small portion of the types you can + // pass to this intrinsic, if we can ever lazily register intrinsics we + // should register these when they're used, that way any type can be + // passed. + ifn!("llvm.is.constant.i1", fn(i1) -> i1); + ifn!("llvm.is.constant.i8", fn(t_i8) -> i1); + ifn!("llvm.is.constant.i16", fn(t_i16) -> i1); + ifn!("llvm.is.constant.i32", fn(t_i32) -> i1); + ifn!("llvm.is.constant.i64", fn(t_i64) -> i1); + ifn!("llvm.is.constant.i128", fn(t_i128) -> i1); + ifn!("llvm.is.constant.isize", fn(t_isize) -> i1); + ifn!("llvm.is.constant.f32", fn(t_f32) -> i1); + ifn!("llvm.is.constant.f64", fn(t_f64) -> i1); + ifn!("llvm.is.constant.ptr", fn(ptr) -> i1); + ifn!("llvm.expect.i1", fn(i1, i1) -> i1); ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32); ifn!("llvm.localescape", fn(...) -> void); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 6116a6fd222b3..b1ceb1d4dd56d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -403,6 +403,7 @@ fn codegenned_and_inlined_items(tcx: TyCtxt<'_>) -> DefIdSet { let mut result = items.clone(); for cgu in cgus { + #[allow(rustc::potential_query_instability)] for item in cgu.items().keys() { if let mir::mono::MonoItem::Fn(ref instance) = item { let did = instance.def_id(); diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 697ce6022984b..587c5e9e8d235 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -102,7 +102,7 @@ pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); impl IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(dcx, level); - let (message, _) = diag.messages().first().expect("`LlvmError` with no message"); + let (message, _) = diag.messages.first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args()); DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config) @@ -244,3 +244,18 @@ pub(crate) struct CopyBitcode { pub struct UnknownCompression { pub algorithm: &'static str, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_mismatch_data_layout)] +pub struct MismatchedDataLayout<'a> { + pub rustc_target: &'a str, + pub rustc_layout: &'a str, + pub llvm_target: &'a str, + pub llvm_layout: &'a str, +} + +#[derive(Diagnostic)] +#[diag(codegen_llvm_invalid_target_feature_prefix)] +pub(crate) struct InvalidTargetFeaturePrefix<'a> { + pub feature: &'a str, +} diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 31aa72ac1077c..317308075ac69 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -116,6 +116,18 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { None, ) } + sym::is_val_statically_known => { + let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); + match self.type_kind(intrinsic_type) { + TypeKind::Pointer | TypeKind::Integer | TypeKind::Float | TypeKind::Double => { + self.call_intrinsic( + &format!("llvm.is.constant.{:?}", intrinsic_type), + &[args[0].immediate()], + ) + } + _ => self.const_bool(false), + } + } kw::Try => { try_intrinsic( self, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index a81056ed3ad62..f4f29078190a1 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -14,9 +14,7 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(min_specialization)] -#![feature(never_type)] #![feature(impl_trait_in_assoc_type)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ba5c67bcc79ce..ef91087096111 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -106,7 +106,6 @@ pub enum CallConv { X86_Intr = 83, AvrNonBlockingInterrupt = 84, AvrInterrupt = 85, - AmdGpuKernel = 91, } /// LLVMRustLinkage @@ -185,7 +184,6 @@ pub enum AttributeKind { SanitizeMemory = 22, NonLazyBind = 23, OptimizeNone = 24, - ReturnsTwice = 25, ReadNone = 26, SanitizeHWAddress = 28, WillReturn = 29, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 99f4488ac0f97..4bb400b187989 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,7 +1,7 @@ use crate::back::write::create_informational_target_machine; use crate::errors::{ - PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, - UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, + UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature, }; use crate::llvm; use libc::c_int; @@ -511,7 +511,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Vec Vec Option<&str> { +fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> { // features must start with a `+` or `-`. - let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| { - bug!("target feature `{}` must begin with a `+` or `-`", s); - }); + let feature = s + .strip_prefix(&['+', '-'][..]) + .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s })); // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e88f4217c9dca..219c702531141 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -33,7 +33,7 @@ fn uncached_llvm_type<'a, 'tcx>( // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str // For performance reasons we use names only when emitting LLVM IR. if !cx.sess().fewer_names() => { diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 5881c6236ece6..a80f6a1add099 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -325,7 +325,7 @@ codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` 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#cargorustc-link-libkindname) +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) codegen_ssa_version_script_write_failure = failed to write version script: {$error} diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index a1daadce958eb..3e5a43c6e73a6 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -206,7 +206,7 @@ impl fmt::Display for CguReuse { } impl IntoDiagnosticArg for CguReuse { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.to_string())) } } @@ -267,6 +267,7 @@ impl CguReuseTracker { fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { + #[allow(rustc::potential_query_instability)] let mut keys = data.expected_reuse.keys().collect::>(); keys.sort_unstable(); for cgu_name in keys { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 959653c932653..b29f71bfb9553 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -52,6 +52,15 @@ use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; +#[derive(Default)] +pub struct SearchPaths(OnceCell>); + +impl SearchPaths { + pub(super) fn get(&self, sess: &Session) -> &[PathBuf] { + self.0.get_or_init(|| archive_search_paths(sess)) + } +} + pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) { if let Err(e) = fs::remove_file(path) { if e.kind() != io::ErrorKind::NotFound { @@ -673,6 +682,7 @@ fn link_dwarf_object<'a>( } // Input rlibs contain .o/.dwo files from dependencies. + #[allow(rustc::potential_query_instability)] let input_rlibs = cg_results .crate_info .used_crate_source @@ -1265,7 +1275,7 @@ fn link_sanitizer_runtime( let path = find_sanitizer_runtime(sess, &filename); let rpath = path.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); - linker.link_dylib(&filename, false, true); + linker.link_dylib_by_name(&filename, false, true); } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" { // MSVC provides the `/INFERASANLIBS` argument to automatically find the // compatible ASAN library. @@ -1273,7 +1283,7 @@ fn link_sanitizer_runtime( } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); - linker.link_whole_rlib(&path); + linker.link_staticlib_by_path(&path, true); } } @@ -2445,7 +2455,7 @@ fn add_native_libs_from_crate( archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, tmpdir: &Path, - search_paths: &OnceCell>, + search_paths: &SearchPaths, bundled_libs: &FxHashSet, cnum: CrateNum, link_static: bool, @@ -2505,28 +2515,16 @@ fn add_native_libs_from_crate( if let Some(filename) = lib.filename { // If rlib contains native libs as archives, they are unpacked to tmpdir. let path = tmpdir.join(filename.as_str()); - if whole_archive { - cmd.link_whole_rlib(&path); - } else { - cmd.link_rlib(&path); - } + cmd.link_staticlib_by_path(&path, whole_archive); } } else { - if whole_archive { - cmd.link_whole_staticlib( - name, - verbatim, - search_paths.get_or_init(|| archive_search_paths(sess)), - ); - } else { - cmd.link_staticlib(name, verbatim) - } + cmd.link_staticlib_by_name(name, verbatim, whole_archive, search_paths); } } } NativeLibKind::Dylib { as_needed } => { if link_dynamic { - cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true)) + cmd.link_dylib_by_name(name, verbatim, as_needed.unwrap_or(true)) } } NativeLibKind::Unspecified => { @@ -2534,17 +2532,17 @@ fn add_native_libs_from_crate( // link kind is unspecified. if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs { if link_static { - cmd.link_staticlib(name, verbatim) + cmd.link_staticlib_by_name(name, verbatim, false, search_paths); } } else { if link_dynamic { - cmd.link_dylib(name, verbatim, true); + cmd.link_dylib_by_name(name, verbatim, true); } } } NativeLibKind::Framework { as_needed } => { if link_dynamic { - cmd.link_framework(name, as_needed.unwrap_or(true)) + cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true)) } } NativeLibKind::RawDylib => { @@ -2581,7 +2579,7 @@ fn add_local_native_libraries( } } - let search_paths = OnceCell::new(); + let search_paths = SearchPaths::default(); // All static and dynamic native library dependencies are linked to the local crate. let link_static = true; let link_dynamic = true; @@ -2623,7 +2621,7 @@ fn add_upstream_rust_crates<'a>( .find(|(ty, _)| *ty == crate_type) .expect("failed to find crate type in dependency format list"); - let search_paths = OnceCell::new(); + let search_paths = SearchPaths::default(); for &cnum in &codegen_results.crate_info.used_crates { // We may not pass all crates through to the linker. Some crates may appear statically in // an existing dylib, meaning we'll pick up all the symbols from the dylib. @@ -2698,7 +2696,7 @@ fn add_upstream_native_libraries( tmpdir: &Path, link_output_kind: LinkOutputKind, ) { - let search_path = OnceCell::new(); + let search_paths = SearchPaths::default(); for &cnum in &codegen_results.crate_info.used_crates { // Static libraries are not linked here, they are linked in `add_upstream_rust_crates`. // FIXME: Merge this function to `add_upstream_rust_crates` so that all native libraries @@ -2720,7 +2718,7 @@ fn add_upstream_native_libraries( archive_builder_builder, codegen_results, tmpdir, - &search_path, + &search_paths, &Default::default(), cnum, link_static, @@ -2791,7 +2789,7 @@ fn add_static_crate<'a>( } else { fix_windows_verbatim_for_gcc(path) }; - cmd.link_rlib(&rlib_path); + cmd.link_staticlib_by_path(&rlib_path, false); }; if !are_upstream_rust_objects_already_included(sess) @@ -2859,13 +2857,24 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { // Just need to tell the linker about where the library lives and // what its name is let parent = cratepath.parent(); + // When producing a dll, the MSVC linker may not actually emit a + // `foo.lib` file if the dll doesn't actually export any symbols, so we + // check to see if the file is there and just omit linking to it if it's + // not present. + if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() { + return; + } if let Some(dir) = parent { cmd.include_path(&rehome_sysroot_lib_dir(sess, dir)); } - let stem = cratepath.file_stem().unwrap().to_str().unwrap(); + // "/name.dll -> name.dll" on windows-msvc + // "/name.dll -> name" on windows-gnu + // "/libname. -> name" elsewhere + let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() }; + let stem = stem.unwrap().to_str().unwrap(); // Convert library file-stem into a cc -l argument. let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; - cmd.link_rust_dylib(&stem[prefix..], parent.unwrap_or_else(|| Path::new(""))); + cmd.link_dylib_by_name(&stem[prefix..], false, true); } fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 90f5027c26494..9f06f398288f2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,5 +1,6 @@ use super::command::Command; use super::symbol_export; +use crate::back::link::SearchPaths; use crate::errors; use rustc_span::symbol::sym; @@ -166,13 +167,18 @@ pub fn get_linker<'a>( pub trait Linker { fn cmd(&mut self) -> &mut Command; fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool); - fn link_rust_dylib(&mut self, lib: &str, path: &Path); - fn link_framework(&mut self, framework: &str, as_needed: bool); - fn link_staticlib(&mut self, lib: &str, verbatim: bool); - fn link_rlib(&mut self, lib: &Path); - fn link_whole_rlib(&mut self, lib: &Path); - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]); + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); + fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { + bug!("framework linked with unsupported linker") + } + fn link_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + whole_archive: bool, + search_paths: &SearchPaths, + ); + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); @@ -432,8 +438,8 @@ impl<'a> Linker for GccLinker<'a> { } } - fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) { - if self.sess.target.os == "illumos" && lib == "c" { + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) { + if self.sess.target.os == "illumos" && name == "c" { // libc will be added via late_link_args on illumos so that it will // appear last in the library search order. // FIXME: This should be replaced by a more complete and generic @@ -454,7 +460,7 @@ impl<'a> Linker for GccLinker<'a> { } } self.hint_dynamic(); - self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },)); + self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); if !as_needed { if self.sess.target.is_like_osx { // See above FIXME comment @@ -463,14 +469,56 @@ impl<'a> Linker for GccLinker<'a> { } } } - fn link_staticlib(&mut self, lib: &str, verbatim: bool) { + + fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { + self.hint_dynamic(); + if !as_needed { + // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework + // flag but we have no way to detect that here. + // self.cmd.arg("-needed_framework").arg(name); + self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); + } + self.cmd.arg("-framework").arg(name); + } + + fn link_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + whole_archive: bool, + search_paths: &SearchPaths, + ) { self.hint_static(); - self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },)); + let colon = if verbatim && self.is_gnu { ":" } else { "" }; + if !whole_archive { + self.cmd.arg(format!("-l{colon}{name}")); + } else if self.sess.target.is_like_osx { + // -force_load is the macOS equivalent of --whole-archive, but it + // involves passing the full path to the library to link. + self.linker_arg("-force_load"); + let search_paths = search_paths.get(self.sess); + self.linker_arg(find_native_static_library(name, verbatim, search_paths, self.sess)); + } else { + self.linker_arg("--whole-archive"); + self.cmd.arg(format!("-l{colon}{name}")); + self.linker_arg("--no-whole-archive"); + } } - fn link_rlib(&mut self, lib: &Path) { + + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); - self.cmd.arg(lib); + if !whole_archive { + self.cmd.arg(path); + } else if self.sess.target.is_like_osx { + self.linker_arg("-force_load"); + self.linker_arg(path); + } else { + self.linker_arg("--whole-archive"); + self.linker_arg(path); + self.linker_arg("--no-whole-archive"); + } } + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -493,55 +541,6 @@ impl<'a> Linker for GccLinker<'a> { self.linker_args(&["-z", "norelro"]); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.hint_dynamic(); - self.cmd.arg(format!("-l{lib}")); - } - - fn link_framework(&mut self, framework: &str, as_needed: bool) { - self.hint_dynamic(); - if !as_needed { - // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework - // flag but we have no way to detect that here. - // self.cmd.arg("-needed_framework").arg(framework); - self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); - } - self.cmd.arg("-framework").arg(framework); - } - - // Here we explicitly ask that the entire archive is included into the - // result artifact. For more details see #15460, but the gist is that - // the linker will strip away any unused objects in the archive if we - // don't otherwise explicitly reference them. This can occur for - // libraries which are just providing bindings, libraries with generic - // functions, etc. - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { - self.hint_static(); - let target = &self.sess.target; - if !target.is_like_osx { - self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },)); - self.linker_arg("--no-whole-archive"); - } else { - // -force_load is the macOS equivalent of --whole-archive, but it - // involves passing the full path to the library to link. - self.linker_arg("-force_load"); - let lib = find_native_static_library(lib, verbatim, search_path, self.sess); - self.linker_arg(&lib); - } - } - - fn link_whole_rlib(&mut self, lib: &Path) { - self.hint_static(); - if self.sess.target.is_like_osx { - self.linker_arg("-force_load"); - self.linker_arg(&lib); - } else { - self.linker_args(&[OsString::from("--whole-archive"), lib.into()]); - self.linker_arg("--no-whole-archive"); - } - } - fn gc_sections(&mut self, keep_metadata: bool) { // The dead_strip option to the linker specifies that functions and data // unreachable by the entry point will be removed. This is quite useful @@ -821,9 +820,32 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { + self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + } + + fn link_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + whole_archive: bool, + _search_paths: &SearchPaths, + ) { + let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; + let suffix = if verbatim { "" } else { ".lib" }; + self.cmd.arg(format!("{prefix}{name}{suffix}")); + } + + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { + if !whole_archive { + self.cmd.arg(path); + } else { + let mut arg = OsString::from("/WHOLEARCHIVE:"); + arg.push(path); + self.cmd.arg(arg); + } } + fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } @@ -845,25 +867,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/OPT:NOREF,NOICF"); } - fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); - } - - fn link_rust_dylib(&mut self, lib: &str, path: &Path) { - // When producing a dll, the MSVC linker may not actually emit a - // `foo.lib` file if the dll doesn't actually export any symbols, so we - // check to see if the file is there and just omit linking to it if it's - // not present. - let name = format!("{lib}.dll.lib"); - if path.join(&name).exists() { - self.cmd.arg(name); - } - } - - fn link_staticlib(&mut self, lib: &str, verbatim: bool) { - self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); - } - fn full_relro(&mut self) { // noop } @@ -899,18 +902,7 @@ impl<'a> Linker for MsvcLinker<'a> { fn framework_path(&mut self, _path: &Path) { bug!("frameworks are not supported on windows") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks are not supported on windows") - } - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { - self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); - } - fn link_whole_rlib(&mut self, path: &Path) { - let mut arg = OsString::from("/WHOLEARCHIVE:"); - arg.push(path); - self.cmd.arg(arg); - } fn optimize(&mut self) { // Needs more investigation of `/OPT` arguments } @@ -1057,43 +1049,35 @@ impl<'a> Linker for EmLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { - self.cmd.arg("-l").arg(lib); + fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { + // Emscripten always links statically + self.cmd.arg("-l").arg(name); } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); + fn link_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + _whole_archive: bool, + _search_paths: &SearchPaths, + ) { + self.cmd.arg("-l").arg(name); } - fn add_object(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { self.cmd.arg(path); } - fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { - // Emscripten always links statically - self.link_staticlib(lib, verbatim); - } - - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { - // not supported? - self.link_staticlib(lib, verbatim); - } - - fn link_whole_rlib(&mut self, lib: &Path) { - // not supported? - self.link_rlib(lib); + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.link_dylib(lib, false, true); + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); } - fn link_rlib(&mut self, lib: &Path) { - self.add_object(lib); + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); } fn full_relro(&mut self) { @@ -1112,10 +1096,6 @@ impl<'a> Linker for EmLinker<'a> { bug!("frameworks are not supported on Emscripten") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks are not supported on Emscripten") - } - fn gc_sections(&mut self, _keep_metadata: bool) { // noop } @@ -1249,16 +1229,30 @@ impl<'a> Linker for WasmLd<'a> { } } - fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").arg(lib); + fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { + self.cmd.arg("-l").arg(name); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { - self.cmd.arg("-l").arg(lib); + fn link_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + whole_archive: bool, + _search_paths: &SearchPaths, + ) { + if !whole_archive { + self.cmd.arg("-l").arg(name); + } else { + self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); + } } - fn link_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { + if !whole_archive { + self.cmd.arg(path); + } else { + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + } } fn include_path(&mut self, path: &Path) { @@ -1283,22 +1277,6 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.cmd.arg("-l").arg(lib); - } - - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - panic!("frameworks not supported") - } - - fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { - self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive"); - } - - fn link_whole_rlib(&mut self, lib: &Path) { - self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); - } - fn gc_sections(&mut self, _keep_metadata: bool) { self.cmd.arg("--gc-sections"); } @@ -1398,17 +1376,40 @@ pub struct L4Bender<'a> { } impl<'a> Linker for L4Bender<'a> { - fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("dylibs are not supported on L4Re"); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + + fn link_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + whole_archive: bool, + _search_paths: &SearchPaths, + ) { self.hint_static(); - self.cmd.arg(format!("-PC{lib}")); + if !whole_archive { + self.cmd.arg(format!("-PC{name}")); + } else { + self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive"); + } } - fn link_rlib(&mut self, lib: &Path) { + + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); - self.cmd.arg(lib); + if !whole_archive { + self.cmd.arg(path); + } else { + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + } } + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -1436,31 +1437,6 @@ impl<'a> Linker for L4Bender<'a> { self.cmd.arg("-z").arg("norelro"); } - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_rust_dylib(&mut self, _: &str, _: &Path) { - panic!("Rust dylibs not supported"); - } - - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks not supported on L4Re"); - } - - fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { - self.hint_static(); - self.cmd.arg("--whole-archive").arg(format!("-l{lib}")); - self.cmd.arg("--no-whole-archive"); - } - - fn link_whole_rlib(&mut self, lib: &Path) { - self.hint_static(); - self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); - } - fn gc_sections(&mut self, keep_metadata: bool) { if !keep_metadata { self.cmd.arg("--gc-sections"); @@ -1571,19 +1547,56 @@ impl<'a> AixLinker<'a> { } impl<'a> Linker for AixLinker<'a> { - fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicDylib => { + self.hint_dynamic(); + self.build_dylib(out_filename); + } + LinkOutputKind::StaticDylib => { + self.hint_static(); + self.build_dylib(out_filename); + } + _ => {} + } + } + + fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.cmd.arg(format!("-l{lib}")); + self.cmd.arg(format!("-l{name}")); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + fn link_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + whole_archive: bool, + search_paths: &SearchPaths, + ) { self.hint_static(); - self.cmd.arg(format!("-l{lib}")); + if !whole_archive { + self.cmd.arg(format!("-l{name}")); + } else { + let mut arg = OsString::from("-bkeepfile:"); + let search_path = search_paths.get(self.sess); + arg.push(find_native_static_library(name, verbatim, search_path, self.sess)); + self.cmd.arg(arg); + } } - fn link_rlib(&mut self, lib: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); - self.cmd.arg(lib); + if !whole_archive { + self.cmd.arg(path); + } else { + let mut arg = OsString::from("-bkeepfile:"); + arg.push(path); + self.cmd.arg(arg); + } } fn include_path(&mut self, path: &Path) { @@ -1608,44 +1621,6 @@ impl<'a> Linker for AixLinker<'a> { fn no_relro(&mut self) {} - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { - match output_kind { - LinkOutputKind::DynamicDylib => { - self.hint_dynamic(); - self.build_dylib(out_filename); - } - LinkOutputKind::StaticDylib => { - self.hint_static(); - self.build_dylib(out_filename); - } - _ => {} - } - } - - fn link_rust_dylib(&mut self, lib: &str, _: &Path) { - self.hint_dynamic(); - self.cmd.arg(format!("-l{lib}")); - } - - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks not supported on AIX"); - } - - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { - self.hint_static(); - let lib = find_native_static_library(lib, verbatim, search_path, self.sess); - self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); - } - - fn link_whole_rlib(&mut self, lib: &Path) { - self.hint_static(); - self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); - } - fn gc_sections(&mut self, _keep_metadata: bool) { self.cmd.arg("-bgc"); } @@ -1810,11 +1785,21 @@ impl<'a> Linker for PtxLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_rlib(&mut self, path: &Path) { - self.cmd.arg("--rlib").arg(path); + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { + panic!("external dylibs not supported") + } + + fn link_staticlib_by_name( + &mut self, + _name: &str, + _verbatim: bool, + _whole_archive: bool, + _search_paths: &SearchPaths, + ) { + panic!("staticlibs not supported") } - fn link_whole_rlib(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { self.cmd.arg("--rlib").arg(path); } @@ -1844,30 +1829,10 @@ impl<'a> Linker for PtxLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { - panic!("external dylibs not supported") - } - - fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { - panic!("staticlibs not supported") - } - - fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { - panic!("staticlibs not supported") - } - fn framework_path(&mut self, _path: &Path) { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1907,11 +1872,21 @@ impl<'a> Linker for BpfLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_rlib(&mut self, path: &Path) { - self.cmd.arg(path); + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { + panic!("external dylibs not supported") } - fn link_whole_rlib(&mut self, path: &Path) { + fn link_staticlib_by_name( + &mut self, + _name: &str, + _verbatim: bool, + _whole_archive: bool, + _search_paths: &SearchPaths, + ) { + panic!("staticlibs not supported") + } + + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { self.cmd.arg(path); } @@ -1942,30 +1917,10 @@ impl<'a> Linker for BpfLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { - panic!("external dylibs not supported") - } - - fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { - panic!("staticlibs not supported") - } - - fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { - panic!("staticlibs not supported") - } - fn framework_path(&mut self, _path: &Path) { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 5d497d4a1883a..9b24339d2551f 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -14,8 +14,11 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; -use rustc_errors::{translation::Translate, DiagCtxt, FatalError, Level}; -use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, Style}; +use rustc_errors::translation::Translate; +use rustc_errors::{ + DiagCtxt, DiagnosticArgName, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrCode, + FatalError, FluentBundle, Level, Style, +}; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ @@ -36,7 +39,6 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet}; use crate::errors::ErrorCreatingRemarkDir; use std::any::Any; -use std::borrow::Cow; use std::fs; use std::io; use std::marker::PhantomData; @@ -995,12 +997,10 @@ pub(crate) enum Message { /// process another codegen unit. pub struct CguMessage; -type DiagnosticArgName<'source> = Cow<'source, str>; - struct Diagnostic { msgs: Vec<(DiagnosticMessage, Style)>, - args: FxHashMap, rustc_errors::DiagnosticArgValue<'static>>, - code: Option, + args: FxHashMap, + code: Option, lvl: Level, } @@ -1800,23 +1800,23 @@ impl SharedEmitter { } impl Translate for SharedEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&Lrc> { None } - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { + fn fallback_fluent_bundle(&self) -> &FluentBundle { panic!("shared emitter attempted to translate a diagnostic"); } } impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) { - let args: FxHashMap, rustc_errors::DiagnosticArgValue<'_>> = + fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) { + let args: FxHashMap = diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msgs: diag.messages.clone(), args: args.clone(), - code: diag.code.clone(), + code: diag.code, lvl: diag.level(), }))); for child in &diag.children { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 198b7ac417072..b387d0b2258b0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,6 +1,6 @@ use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; @@ -103,9 +103,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { match name { sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR, - sym::ffi_returns_twice => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE - } sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST, sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, @@ -563,7 +560,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if codegen_fn_attrs.inline == InlineAttr::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.struct_span_lint_hir( + tcx.node_span_lint( lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, @@ -658,7 +655,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment // about LINK.EXE failing.) if *ordinal <= u16::MAX as u128 { - Some(*ordinal as u16) + Some(ordinal.get() as u16) } else { let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal); tcx.dcx() diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 4f9f70648bd88..5bd7442822a21 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -398,7 +398,9 @@ fn push_debuginfo_type_name<'tcx>( // processing visited.remove(&t); } - ty::Closure(def_id, args) | ty::Coroutine(def_id, args, ..) => { + ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) + | ty::Coroutine(def_id, args, ..) => { // Name will be "{closure_env#0}", "{coroutine_env#0}", or // "{async_fn_env#0}", etc. // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of @@ -768,6 +770,8 @@ fn push_closure_or_coroutine_name<'tcx>( // Truncate the args to the length of the above generics. This will cut off // anything closure- or coroutine-specific. + // FIXME(async_closures): This is probably not going to be correct w.r.t. + // multiple coroutine flavors. Maybe truncate to (parent + 1)? let args = args.truncate_to(tcx, generics); push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited); } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f90e1906caf0a..06ea5b9e8f4ab 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -4,7 +4,7 @@ use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + codes::*, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, IntoDiagnosticArg, Level, }; use rustc_macros::Diagnostic; @@ -147,7 +147,7 @@ impl<'a> CopyPath<'a> { struct DebugArgPath<'a>(pub &'a Path); impl IntoDiagnosticArg for DebugArgPath<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0))) } } @@ -612,7 +612,7 @@ pub struct UnknownAtomicOperation; #[derive(Diagnostic)] pub enum InvalidMonomorphization<'tcx> { - #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = E0511)] BasicIntegerType { #[primary_span] span: Span, @@ -620,7 +620,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = E0511)] BasicFloatType { #[primary_span] span: Span, @@ -628,14 +628,14 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = E0511)] FloatToIntUnchecked { #[primary_span] span: Span, ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = E0511)] FloatingPointVector { #[primary_span] span: Span, @@ -644,7 +644,7 @@ pub enum InvalidMonomorphization<'tcx> { in_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = E0511)] FloatingPointType { #[primary_span] span: Span, @@ -652,14 +652,14 @@ pub enum InvalidMonomorphization<'tcx> { in_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = E0511)] UnrecognizedIntrinsic { #[primary_span] span: Span, name: Symbol, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = E0511)] SimdArgument { #[primary_span] span: Span, @@ -667,7 +667,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = E0511)] SimdInput { #[primary_span] span: Span, @@ -675,7 +675,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = E0511)] SimdFirst { #[primary_span] span: Span, @@ -683,7 +683,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = E0511)] SimdSecond { #[primary_span] span: Span, @@ -691,7 +691,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = E0511)] SimdThird { #[primary_span] span: Span, @@ -699,7 +699,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = E0511)] SimdReturn { #[primary_span] span: Span, @@ -707,7 +707,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = E0511)] InvalidBitmask { #[primary_span] span: Span, @@ -717,7 +717,7 @@ pub enum InvalidMonomorphization<'tcx> { expected_bytes: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = E0511)] ReturnLengthInputType { #[primary_span] span: Span, @@ -728,7 +728,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = E0511)] SecondArgumentLength { #[primary_span] span: Span, @@ -739,7 +739,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = E0511)] ThirdArgumentLength { #[primary_span] span: Span, @@ -750,7 +750,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = E0511)] ReturnIntegerType { #[primary_span] span: Span, @@ -759,7 +759,7 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = E0511)] SimdShuffle { #[primary_span] span: Span, @@ -767,7 +767,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_return_length, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_length, code = E0511)] ReturnLength { #[primary_span] span: Span, @@ -777,7 +777,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_return_element, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_element, code = E0511)] ReturnElement { #[primary_span] span: Span, @@ -788,7 +788,7 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = E0511)] ShuffleIndexNotConstant { #[primary_span] span: Span, @@ -796,7 +796,7 @@ pub enum InvalidMonomorphization<'tcx> { arg_idx: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = E0511)] ShuffleIndexOutOfBounds { #[primary_span] span: Span, @@ -805,7 +805,7 @@ pub enum InvalidMonomorphization<'tcx> { total_len: u128, }, - #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = E0511)] InsertedType { #[primary_span] span: Span, @@ -815,7 +815,7 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_return_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_type, code = E0511)] ReturnType { #[primary_span] span: Span, @@ -825,7 +825,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = E0511)] ExpectedReturnType { #[primary_span] span: Span, @@ -834,7 +834,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = E0511)] MismatchedLengths { #[primary_span] span: Span, @@ -843,7 +843,7 @@ pub enum InvalidMonomorphization<'tcx> { v_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)] MaskType { #[primary_span] span: Span, @@ -851,7 +851,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = E0511)] VectorArgument { #[primary_span] span: Span, @@ -860,7 +860,7 @@ pub enum InvalidMonomorphization<'tcx> { in_elem: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = E0511)] CannotReturn { #[primary_span] span: Span, @@ -870,7 +870,7 @@ pub enum InvalidMonomorphization<'tcx> { expected_bytes: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = E0511)] ExpectedElementType { #[primary_span] span: Span, @@ -882,7 +882,7 @@ pub enum InvalidMonomorphization<'tcx> { mutability: ExpectedPointerMutability, }, - #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = E0511)] ThirdArgElementType { #[primary_span] span: Span, @@ -891,7 +891,7 @@ pub enum InvalidMonomorphization<'tcx> { third_arg: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = E0511)] UnsupportedSymbolOfSize { #[primary_span] span: Span, @@ -903,7 +903,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = E0511)] UnsupportedSymbol { #[primary_span] span: Span, @@ -914,7 +914,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)] CastFatPointer { #[primary_span] span: Span, @@ -922,7 +922,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = E0511)] ExpectedPointer { #[primary_span] span: Span, @@ -930,7 +930,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = E0511)] ExpectedUsize { #[primary_span] span: Span, @@ -938,7 +938,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = E0511)] UnsupportedCast { #[primary_span] span: Span, @@ -949,7 +949,7 @@ pub enum InvalidMonomorphization<'tcx> { out_elem: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = E0511)] UnsupportedOperation { #[primary_span] span: Span, @@ -958,7 +958,7 @@ pub enum InvalidMonomorphization<'tcx> { in_elem: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = E0511)] ExpectedVectorElementType { #[primary_span] span: Span, @@ -974,7 +974,7 @@ pub enum ExpectedPointerMutability { } impl IntoDiagnosticArg for ExpectedPointerMutability { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { match self { ExpectedPointerMutability::Mut => DiagnosticArgValue::Str(Cow::Borrowed("*mut")), ExpectedPointerMutability::Not => DiagnosticArgValue::Str(Cow::Borrowed("*_")), diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8f5421823a384..fc833a3863e40 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -7,10 +7,8 @@ #![feature(if_let_guard)] #![feature(let_chains)] #![feature(negative_impls)] -#![feature(never_type)] #![feature(strict_provenance)] #![feature(try_blocks)] -#![recursion_limit = "256"] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). //! The backend-agnostic functions of this crate use functions defined in various traits that diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 02b51dfe5bf7f..266505d3f2691 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -435,7 +435,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args, ty::ClosureKind::FnOnce, ) - .expect("failed to normalize and resolve closure during codegen") .polymorphize(bx.cx().tcx()); OperandValue::Immediate(bx.cx().get_fn_addr(instance)) } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 4a426ed16e541..e7e8b2b36006d 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -46,8 +46,8 @@ const_eval_dangling_int_pointer = {$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance) const_eval_dangling_null_pointer = {$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance) -const_eval_dangling_ptr_in_final = encountered dangling pointer in final constant +const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind} const_eval_dead_local = accessing a dead local variable const_eval_dealloc_immutable = @@ -134,6 +134,14 @@ const_eval_interior_mutable_data_refer = This would make multiple uses of a constant to be able to see different values and allow circumventing the `Send` and `Sync` requirements for shared mutable data, which is unsound. +const_eval_intern_kind = {$kind -> + [static] static + [static_mut] mutable static + [const] constant + [promoted] promoted + *[other] {""} +} + const_eval_invalid_align = align has to be a power of 2 @@ -205,6 +213,8 @@ const_eval_modified_global = const_eval_mut_deref = mutation through a reference is not allowed in {const_eval_const_context}s +const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} + const_eval_non_const_fmt_macro_call = cannot call non-const formatting macro in {const_eval_const_context}s @@ -327,7 +337,7 @@ const_eval_too_many_caller_args = const_eval_transient_mut_borrow = mutable references are not allowed in {const_eval_const_context}s -const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {const_eval_const_context}s +const_eval_transient_mut_raw = raw mutable pointers are not allowed in {const_eval_const_context}s const_eval_try_block_from_output_non_const = `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s @@ -341,21 +351,21 @@ const_eval_unallowed_heap_allocations = const_eval_unallowed_inline_asm = inline assembly is not allowed in {const_eval_const_context}s -const_eval_unallowed_mutable_refs = - mutable references are not allowed in the final value of {const_eval_const_context}s +const_eval_unallowed_mutable_raw = + raw mutable pointers are not allowed in the final value of {const_eval_const_context}s .teach_note = + References in statics and constants may only refer to immutable values. + + Statics are shared everywhere, and if they refer to mutable data one might violate memory safety since holding multiple mutable references to shared data is not allowed. If you really want global mutable state, try using static mut or a global UnsafeCell. -const_eval_unallowed_mutable_refs_raw = - raw mutable references are not allowed in the final value of {const_eval_const_context}s +const_eval_unallowed_mutable_refs = + mutable references are not allowed in the final value of {const_eval_const_context}s .teach_note = - References in statics and constants may only refer to immutable values. - - Statics are shared everywhere, and if they refer to mutable data one might violate memory safety since holding multiple mutable references to shared data is not allowed. @@ -392,9 +402,6 @@ const_eval_unstable_in_stable = .unstable_sugg = if it is not part of the public API, make this function unstably const .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks -const_eval_unsupported_untyped_pointer = unsupported untyped pointer in constant - .note = memory only reachable via raw pointers is not supported - const_eval_unterminated_c_string = reading a null-terminated string starting at {$pointer} with no null found before end of allocation @@ -406,7 +413,6 @@ const_eval_upcast_mismatch = ## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. ## (We'd love to sort this differently to make that more clear but tidy won't let us...) -const_eval_validation_box_to_mut = {$front_matter}: encountered a box pointing to mutable memory in a constant const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance) @@ -441,7 +447,8 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer -const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const` +const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const` or `static` +const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` const_eval_validation_null_box = {$front_matter}: encountered a null box const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer @@ -451,7 +458,6 @@ const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} -const_eval_validation_ref_to_mut = {$front_matter}: encountered a reference pointing to mutable memory in a constant const_eval_validation_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) @@ -459,7 +465,7 @@ const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}` const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected} -const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const` +const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in read-only memory const_eval_write_through_immutable_pointer = writing through a pointer that was derived from a shared (immutable) reference diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index ef39d13d78ab4..62af21396ab4b 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,6 +1,8 @@ use std::mem; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg}; +use rustc_errors::{ + DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg, +}; use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; @@ -32,10 +34,7 @@ impl MachineStopType for ConstEvalErrKind { AssertFailure(x) => x.diagnostic_message(), } } - fn add_args( - self: Box, - adder: &mut dyn FnMut(std::borrow::Cow<'static, str>, DiagnosticArgValue<'static>), - ) { + fn add_args(self: Box, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) { use ConstEvalErrKind::*; match *self { ConstAccessesStatic | ModifiedGlobal => {} @@ -50,9 +49,7 @@ impl MachineStopType for ConstEvalErrKind { } } -// The errors become `MachineStop` with plain strings when being raised. -// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to -// handle these. +/// The errors become [`InterpError::MachineStop`] when being raised. impl<'tcx> Into> for ConstEvalErrKind { fn into(self) -> InterpErrorInfo<'tcx> { err_machine_stop!(self).into() @@ -175,7 +172,7 @@ pub(super) fn lint<'tcx, 'mir, L>( { let (span, frames) = get_span_and_frames(tcx, machine); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( lint, // We use the root frame for this so the crate that defines the const defines whether the // lint is emitted. diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 9d22df50d4f34..6a92ed9717de5 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -225,17 +225,10 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // see comment in eval_to_allocation_raw_provider for what we're doing here - if key.param_env.reveal() == Reveal::All { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_const_value_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::TooGeneric(_)) => {} - // deduplicate calls - other => return other, - } - } + // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of + // opaque types. This is needed for trivial things like `size_of`, but also for using associated + // types that are not specified in the opaque type. + assert_eq!(key.param_env.reveal(), Reveal::All); // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. @@ -265,24 +258,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - // Because the constant is computed twice (once per value of `Reveal`), we are at risk of - // reporting the same error twice here. To resolve this, we check whether we can evaluate the - // constant in the more restrictive `Reveal::UserFacing`, which most likely already was - // computed. For a large percentage of constants that will already have succeeded. Only - // associated constants of generic functions will fail due to not enough monomorphization - // information being available. - - // In case we fail in the `UserFacing` variant, we just do the real computation. - if key.param_env.reveal() == Reveal::All { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_allocation_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::TooGeneric(_)) => {} - // deduplicate calls - other => return other, - } - } + // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of + // opaque types. This is needed for trivial things like `size_of`, but also for using associated + // types that are not specified in the opaque type. + + assert_eq!(key.param_env.reveal(), Reveal::All); if cfg!(debug_assertions) { // Make sure we format the instance even if we do not print it. // This serves as a regression test against an ICE on printing. @@ -313,6 +293,9 @@ pub fn eval_in_interpreter<'mir, 'tcx>( cid: GlobalId<'tcx>, is_static: bool, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { + // `is_static` just means "in static", it could still be a promoted! + debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some()); + let res = ecx.load_mir(cid.instance.def, cid.promoted); match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) { Err(error) => { @@ -350,8 +333,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>( Ok(mplace) => { // Since evaluation had no errors, validate the resulting constant. // This is a separate `try` block to provide more targeted error reporting. - let validation = - const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some()); + let validation = const_validate_mplace(&ecx, &mplace, cid); let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); @@ -370,22 +352,26 @@ pub fn eval_in_interpreter<'mir, 'tcx>( pub fn const_validate_mplace<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, mplace: &MPlaceTy<'tcx>, - is_static: bool, - is_promoted: bool, + cid: GlobalId<'tcx>, ) -> InterpResult<'tcx> { let mut ref_tracking = RefTracking::new(mplace.clone()); let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { - let mode = if is_static { - if is_promoted { - // Promoteds in statics are allowed to point to statics. - CtfeValidationMode::Const { inner, allow_static_ptrs: true } - } else { - // a `static` - CtfeValidationMode::Regular + let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) { + Some(_) if cid.promoted.is_some() => { + // Promoteds in statics are consts that re allowed to point to statics. + CtfeValidationMode::Const { + allow_immutable_unsafe_cell: false, + allow_static_ptrs: true, + } + } + Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static` + None => { + // In normal `const` (not promoted), the outermost allocation is always only copied, + // so having `UnsafeCell` in there is okay despite them being in immutable memory. + let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner; + CtfeValidationMode::Const { allow_immutable_unsafe_cell, allow_static_ptrs: false } } - } else { - CtfeValidationMode::Const { inner, allow_static_ptrs: false } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?; inner = true; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 6947ace17c5e6..274ff25fb9b58 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -531,6 +531,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, )?; } } + // The intrinsic represents whether the value is known to the optimizer (LLVM). + // We're not doing any optimizations here, so there is no optimizer that could know the value. + // (We know the value here in the machine of course, but this is the runtime of that code, + // not the optimization stage.) + sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, _ => { throw_unsup_format!( "intrinsic `{intrinsic_name}` is not supported at compile-time" @@ -611,7 +616,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, .0 .is_error(); let span = ecx.cur_span(); - ecx.tcx.emit_spanned_lint( + ecx.tcx.emit_node_span_lint( rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL, hir_id, span, @@ -723,7 +728,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, && ty.is_freeze(*ecx.tcx, ecx.param_env) { let place = ecx.ref_to_mplace(val)?; - let new_place = place.map_provenance(|p| p.map(CtfeProvenance::as_immutable)); + let new_place = place.map_provenance(CtfeProvenance::as_immutable); Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) } else { Ok(val.clone()) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 707bb8d893336..5c2bf4626c4c3 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -138,7 +138,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( } // Trait objects are not allowed in type level constants, as we have no concept for // resolving their backing type, even if we can do that at const eval time. We may - // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, + // hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future, // but it is unclear if this is useful. ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType), @@ -172,6 +172,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( | ty::Infer(_) // FIXME(oli-obk): we can probably encode closures just like structs | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType), } @@ -301,6 +302,7 @@ pub fn valtree_to_const_value<'tcx>( | ty::Placeholder(..) | ty::Infer(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::FnPtr(_) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 171cc89d6adb8..4d2b1ba3eec89 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -1,6 +1,8 @@ +use std::borrow::Cow; + use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, - IntoDiagnostic, Level, + codes::*, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, + EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -13,12 +15,24 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_target::abi::call::AdjustForForeignAbiError; use rustc_target::abi::{Size, WrappingRange}; +use rustc_type_ir::Mutability; + +use crate::interpret::InternKind; #[derive(Diagnostic)] #[diag(const_eval_dangling_ptr_in_final)] pub(crate) struct DanglingPtrInFinal { #[primary_span] pub span: Span, + pub kind: InternKind, +} + +#[derive(Diagnostic)] +#[diag(const_eval_mutable_ptr_in_final)] +pub(crate) struct MutablePtrInFinal { + #[primary_span] + pub span: Span, + pub kind: InternKind, } #[derive(Diagnostic)] @@ -41,14 +55,14 @@ pub(crate) struct UnstableInStable { } #[derive(Diagnostic)] -#[diag(const_eval_thread_local_access, code = "E0625")] +#[diag(const_eval_thread_local_access, code = E0625)] pub(crate) struct NonConstOpErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_static_access, code = "E0013")] +#[diag(const_eval_static_access, code = E0013)] #[help] pub(crate) struct StaticAccessErr { #[primary_span] @@ -84,7 +98,7 @@ pub(crate) struct PanicNonStrErr { } #[derive(Diagnostic)] -#[diag(const_eval_mut_deref, code = "E0658")] +#[diag(const_eval_mut_deref, code = E0658)] pub(crate) struct MutDerefErr { #[primary_span] pub span: Span, @@ -92,7 +106,7 @@ pub(crate) struct MutDerefErr { } #[derive(Diagnostic)] -#[diag(const_eval_transient_mut_borrow, code = "E0658")] +#[diag(const_eval_transient_mut_borrow, code = E0658)] pub(crate) struct TransientMutBorrowErr { #[primary_span] pub span: Span, @@ -100,8 +114,8 @@ pub(crate) struct TransientMutBorrowErr { } #[derive(Diagnostic)] -#[diag(const_eval_transient_mut_borrow_raw, code = "E0658")] -pub(crate) struct TransientMutBorrowErrRaw { +#[diag(const_eval_transient_mut_raw, code = E0658)] +pub(crate) struct TransientMutRawErr { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -132,7 +146,7 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_refs, code = "E0764")] +#[diag(const_eval_unallowed_mutable_refs, code = E0764)] pub(crate) struct UnallowedMutableRefs { #[primary_span] pub span: Span, @@ -142,8 +156,8 @@ pub(crate) struct UnallowedMutableRefs { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_refs_raw, code = "E0764")] -pub(crate) struct UnallowedMutableRefsRaw { +#[diag(const_eval_unallowed_mutable_raw, code = E0764)] +pub(crate) struct UnallowedMutableRaw { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -151,7 +165,7 @@ pub(crate) struct UnallowedMutableRefsRaw { pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval_non_const_fmt_macro_call, code = "E0015")] +#[diag(const_eval_non_const_fmt_macro_call, code = E0015)] pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, @@ -159,7 +173,7 @@ pub(crate) struct NonConstFmtMacroCall { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_fn_call, code = "E0015")] +#[diag(const_eval_non_const_fn_call, code = E0015)] pub(crate) struct NonConstFnCall { #[primary_span] pub span: Span, @@ -176,7 +190,7 @@ pub(crate) struct UnallowedOpInConstContext { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_heap_allocations, code = "E0010")] +#[diag(const_eval_unallowed_heap_allocations, code = E0010)] pub(crate) struct UnallowedHeapAllocations { #[primary_span] #[label] @@ -187,7 +201,7 @@ pub(crate) struct UnallowedHeapAllocations { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_inline_asm, code = "E0015")] +#[diag(const_eval_unallowed_inline_asm, code = E0015)] pub(crate) struct UnallowedInlineAsm { #[primary_span] pub span: Span, @@ -195,15 +209,7 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_unsupported_untyped_pointer)] -#[note] -pub(crate) struct UnsupportedUntypedPointer { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_data_refer, code = "E0492")] +#[diag(const_eval_interior_mutable_data_refer, code = E0492)] pub(crate) struct InteriorMutableDataRefer { #[primary_span] #[label] @@ -268,7 +274,7 @@ pub struct RawBytesNote { // FIXME(fee1-dead) do not use stringly typed `ConstContext` #[derive(Diagnostic)] -#[diag(const_eval_match_eq_non_const, code = "E0015")] +#[diag(const_eval_match_eq_non_const, code = E0015)] #[note] pub struct NonConstMatchEq<'tcx> { #[primary_span] @@ -278,7 +284,7 @@ pub struct NonConstMatchEq<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")] +#[diag(const_eval_for_loop_into_iter_non_const, code = E0015)] pub struct NonConstForLoopIntoIter<'tcx> { #[primary_span] pub span: Span, @@ -287,7 +293,7 @@ pub struct NonConstForLoopIntoIter<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_question_branch_non_const, code = "E0015")] +#[diag(const_eval_question_branch_non_const, code = E0015)] pub struct NonConstQuestionBranch<'tcx> { #[primary_span] pub span: Span, @@ -296,7 +302,7 @@ pub struct NonConstQuestionBranch<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_question_from_residual_non_const, code = "E0015")] +#[diag(const_eval_question_from_residual_non_const, code = E0015)] pub struct NonConstQuestionFromResidual<'tcx> { #[primary_span] pub span: Span, @@ -305,7 +311,7 @@ pub struct NonConstQuestionFromResidual<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_try_block_from_output_non_const, code = "E0015")] +#[diag(const_eval_try_block_from_output_non_const, code = E0015)] pub struct NonConstTryBlockFromOutput<'tcx> { #[primary_span] pub span: Span, @@ -314,7 +320,7 @@ pub struct NonConstTryBlockFromOutput<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_await_non_const, code = "E0015")] +#[diag(const_eval_await_non_const, code = E0015)] pub struct NonConstAwait<'tcx> { #[primary_span] pub span: Span, @@ -323,7 +329,7 @@ pub struct NonConstAwait<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_closure_non_const, code = "E0015")] +#[diag(const_eval_closure_non_const, code = E0015)] pub struct NonConstClosure { #[primary_span] pub span: Span, @@ -356,7 +362,7 @@ pub struct ConsiderDereferencing { } #[derive(Diagnostic)] -#[diag(const_eval_operator_non_const, code = "E0015")] +#[diag(const_eval_operator_non_const, code = E0015)] pub struct NonConstOperator { #[primary_span] pub span: Span, @@ -366,7 +372,7 @@ pub struct NonConstOperator { } #[derive(Diagnostic)] -#[diag(const_eval_deref_coercion_non_const, code = "E0015")] +#[diag(const_eval_deref_coercion_non_const, code = E0015)] #[note] pub struct NonConstDerefCoercion<'tcx> { #[primary_span] @@ -379,7 +385,7 @@ pub struct NonConstDerefCoercion<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_live_drop, code = "E0493")] +#[diag(const_eval_live_drop, code = E0493)] pub struct LiveDrop<'tcx> { #[primary_span] #[label] @@ -391,7 +397,7 @@ pub struct LiveDrop<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_error, code = "E0080")] +#[diag(const_eval_error, code = E0080)] pub struct ConstEvalError { #[primary_span] pub span: Span, @@ -417,7 +423,7 @@ pub struct NullaryIntrinsicError { } #[derive(Diagnostic)] -#[diag(const_eval_undefined_behavior, code = "E0080")] +#[diag(const_eval_undefined_behavior, code = E0080)] pub struct UndefinedBehavior { #[primary_span] pub span: Span, @@ -615,18 +621,16 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static, PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static, - PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut, - PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_mut, - PointerAsInt { .. } => const_eval_validation_pointer_as_int, PartialPointer => const_eval_validation_partial_pointer, MutableRefInConst => const_eval_validation_mutable_ref_in_const, + MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable, NullFnPtr => const_eval_validation_null_fn_ptr, NeverVal => const_eval_validation_never_val, NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, OutOfRange { .. } => const_eval_validation_out_of_range, - UnsafeCell => const_eval_validation_unsafe_cell, + UnsafeCellInImmutable => const_eval_validation_unsafe_cell, UninhabitedVal { .. } => const_eval_validation_uninhabited_val, InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag, UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, @@ -772,11 +776,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { } NullPtr { .. } | PtrToStatic { .. } - | PtrToMut { .. } | MutableRefInConst + | MutableRefToImmutable | NullFnPtr | NeverVal - | UnsafeCell + | UnsafeCellInImmutable | InvalidMetaSliceTooLarge { .. } | InvalidMetaTooLarge { .. } | DanglingPtrUseAfterFree { .. } @@ -860,9 +864,6 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { InvalidProgramInfo::FnAbiAdjustForForeignAbi(_) => { rustc_middle::error::middle_adjust_for_foreign_abi_error } - InvalidProgramInfo::ConstPropNonsense => { - panic!("We had const-prop nonsense, this should never be printed") - } } } fn add_args( @@ -871,9 +872,7 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { builder: &mut DiagnosticBuilder<'_, G>, ) { match self { - InvalidProgramInfo::TooGeneric - | InvalidProgramInfo::AlreadyReported(_) - | InvalidProgramInfo::ConstPropNonsense => {} + InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {} InvalidProgramInfo::Layout(e) => { // The level doesn't matter, `diag` is consumed without it being used. let dummy_level = Level::Bug; @@ -905,3 +904,14 @@ impl ReportErrorExt for ResourceExhaustionInfo { } fn add_args(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {} } + +impl rustc_errors::IntoDiagnosticArg for InternKind { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + InternKind::Static(Mutability::Not) => "static", + InternKind::Static(Mutability::Mut) => "static_mut", + InternKind::Constant => "const", + InternKind::Promoted => "promoted", + })) + } +} diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index d296ff5928b36..0cb5c634b22ba 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -117,8 +117,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { def_id, args, ty::ClosureKind::FnOnce, - ) - .ok_or_else(|| err_inval!(TooGeneric))?; + ); let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index e6370adb983a7..dd989ab80fd3c 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1007,6 +1007,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Error(_) => true, @@ -1131,13 +1132,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { span: Option, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - let const_val = val.eval(*self.tcx, self.param_env, span).map_err(|err| { - // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on. - // Are we not always populating `required_consts`? - err.emit_note(*self.tcx); - err - })?; - self.const_val_to_op(const_val, val.ty(), layout) + M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| { + let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| { + // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on. + // Are we not always populating `required_consts`? + err.emit_note(*ecx.tcx); + err + })?; + ecx.const_val_to_op(const_val, val.ty(), layout) + }) } #[must_use] diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 202819ee6338f..751fbfacaad00 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -5,30 +5,24 @@ //! //! In principle, this is not very complicated: we recursively walk the final value, follow all the //! pointers, and move all reachable allocations to the global `tcx` memory. The only complication -//! is picking the right mutability for the allocations in a `static` initializer: we want to make -//! as many allocations as possible immutable so LLVM can put them into read-only memory. At the -//! same time, we need to make memory that could be mutated by the program mutable to avoid -//! incorrect compilations. To achieve this, we do a type-based traversal of the final value, -//! tracking mutable and shared references and `UnsafeCell` to determine the current mutability. -//! (In principle, we could skip this type-based part for `const` and promoteds, as they need to be -//! always immutable. At least for `const` however we use this opportunity to reject any `const` -//! that contains allocations whose mutability we cannot identify.) +//! is picking the right mutability: the outermost allocation generally has a clear mutability, but +//! what about the other allocations it points to that have also been created with this value? We +//! don't want to do guesswork here. The rules are: `static`, `const`, and promoted can only create +//! immutable allocations that way. `static mut` can be initialized with expressions like `&mut 42`, +//! so all inner allocations are marked mutable. Some of them could potentially be made immutable, +//! but that would require relying on type information, and given how many ways Rust has to lie +//! about type information, we want to avoid doing that. -use super::validity::RefTracking; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_ast::Mutability; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult}; -use rustc_middle::ty::{self, layout::TyAndLayout, Ty}; - -use rustc_ast::Mutability; +use rustc_middle::ty::layout::TyAndLayout; -use super::{ - AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, Projectable, - ValueVisitor, -}; +use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy}; use crate::const_eval; -use crate::errors::{DanglingPtrInFinal, UnsupportedUntypedPointer}; +use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal}; pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< 'mir, @@ -41,271 +35,44 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< MemoryMap = FxIndexMap, Allocation)>, >; -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { - /// The ectx from which we intern. - ecx: &'rt mut InterpCx<'mir, 'tcx, M>, - /// Previously encountered safe references. - ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>, - /// A list of all encountered allocations. After type-based interning, we traverse this list to - /// also intern allocations that are only referenced by a raw pointer or inside a union. - leftover_allocations: &'rt mut FxIndexSet, - /// The root kind of the value that we're looking at. This field is never mutated for a - /// particular allocation. It is primarily used to make as many allocations as possible - /// read-only so LLVM can place them in const memory. - mode: InternMode, - /// This field stores whether we are *currently* inside an `UnsafeCell`. This can affect - /// the intern mode of references we encounter. - inside_unsafe_cell: bool, -} - -#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] -enum InternMode { - /// A static and its current mutability. Below shared references inside a `static mut`, - /// this is *immutable*, and below mutable references inside an `UnsafeCell`, this - /// is *mutable*. - Static(hir::Mutability), - /// A `const`. - Const, -} - -/// Signalling data structure to ensure we don't recurse -/// into the memory of other constants or statics -struct IsStaticOrFn; - -/// Intern an allocation without looking at its children. -/// `mode` is the mode of the environment where we found this pointer. -/// `mutability` is the mutability of the place to be interned; even if that says -/// `immutable` things might become mutable if `ty` is not frozen. -/// `ty` can be `None` if there is no potential interior mutability -/// to account for (e.g. for vtables). -fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( +/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. +/// +/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the +/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be* +/// already mutable (as a sanity check). +/// +/// `recursive_alloc` is called for all recursively encountered allocations. +fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, - leftover_allocations: &'rt mut FxIndexSet, alloc_id: AllocId, - mode: InternMode, - ty: Option>, -) -> Option { - trace!("intern_shallow {:?} with {:?}", alloc_id, mode); + mutability: Mutability, + mut recursive_alloc: impl FnMut(&InterpCx<'mir, 'tcx, M>, CtfeProvenance), +) -> Result<(), ()> { + trace!("intern_shallow {:?}", alloc_id); // remove allocation - let tcx = ecx.tcx; - let Some((kind, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else { - // Pointer not found in local memory map. It is either a pointer to the global - // map, or dangling. - // If the pointer is dangling (neither in local nor global memory), we leave it - // to validation to error -- it has the much better error messages, pointing out where - // in the value the dangling reference lies. - // The `span_delayed_bug` ensures that we don't forget such a check in validation. - if tcx.try_get_global_alloc(alloc_id).is_none() { - tcx.dcx().span_delayed_bug(ecx.tcx.span, "tried to intern dangling pointer"); - } - // treat dangling pointers like other statics - // just to stop trying to recurse into them - return Some(IsStaticOrFn); + let Some((_kind, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else { + return Err(()); }; - // This match is just a canary for future changes to `MemoryKind`, which most likely need - // changes in this function. - match kind { - MemoryKind::Stack - | MemoryKind::Machine(const_eval::MemoryKind::Heap) - | MemoryKind::CallerLocation => {} - } // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that // access this one. - if let InternMode::Static(mutability) = mode { - // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume - // no interior mutability. - let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env)); - // For statics, allocation mutability is the combination of place mutability and - // type mutability. - // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. - let immutable = mutability == Mutability::Not && frozen; - if immutable { + match mutability { + Mutability::Not => { alloc.mutability = Mutability::Not; - } else { - // Just making sure we are not "upgrading" an immutable allocation to mutable. + } + Mutability::Mut => { + // This must be already mutable, we won't "un-freeze" allocations ever. assert_eq!(alloc.mutability, Mutability::Mut); } - } else { - // No matter what, *constants are never mutable*. Mutating them is UB. - // See const_eval::machine::MemoryExtra::can_access_statics for why - // immutability is so important. - - // Validation will ensure that there is no `UnsafeCell` on an immutable allocation. - alloc.mutability = Mutability::Not; - }; - // link the alloc id to the actual allocation - leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, prov)| prov.alloc_id())); - let alloc = tcx.mk_const_alloc(alloc); - tcx.set_alloc_id_memory(alloc_id, alloc); - None -} - -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> - InternVisitor<'rt, 'mir, 'tcx, M> -{ - fn intern_shallow( - &mut self, - alloc_id: AllocId, - mode: InternMode, - ty: Option>, - ) -> Option { - intern_shallow(self.ecx, self.leftover_allocations, alloc_id, mode, ty) } -} - -impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> - ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> -{ - type V = MPlaceTy<'tcx>; - - #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - self.ecx - } - - fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { - // Handle Reference types, as these are the only types with provenance supported by const eval. - // Raw pointers (and boxes) are handled by the `leftover_allocations` logic. - let tcx = self.ecx.tcx; - let ty = mplace.layout.ty; - if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { - let value = self.ecx.read_immediate(mplace)?; - let mplace = self.ecx.ref_to_mplace(&value)?; - assert_eq!(mplace.layout.ty, referenced_ty); - // Handle trait object vtables. - if let ty::Dynamic(_, _, ty::Dyn) = - tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() - { - let ptr = mplace.meta().unwrap_meta().to_pointer(&tcx)?; - if let Some(prov) = ptr.provenance { - // Explicitly choose const mode here, since vtables are immutable, even - // if the reference of the fat pointer is mutable. - self.intern_shallow(prov.alloc_id(), InternMode::Const, None); - } else { - // Validation will error (with a better message) on an invalid vtable pointer. - // Let validation show the error message, but make sure it *does* error. - tcx.dcx() - .span_delayed_bug(tcx.span, "vtables pointers cannot be integer pointers"); - } - } - // Check if we have encountered this pointer+layout combination before. - // Only recurse for allocation-backed pointers. - if let Some(prov) = mplace.ptr().provenance { - // Compute the mode with which we intern this. Our goal here is to make as many - // statics as we can immutable so they can be placed in read-only memory by LLVM. - let ref_mode = match self.mode { - InternMode::Static(mutbl) => { - // In statics, merge outer mutability with reference mutability and - // take into account whether we are in an `UnsafeCell`. - - // The only way a mutable reference actually works as a mutable reference is - // by being in a `static mut` directly or behind another mutable reference. - // If there's an immutable reference or we are inside a `static`, then our - // mutable reference is equivalent to an immutable one. As an example: - // `&&mut Foo` is semantically equivalent to `&&Foo` - match ref_mutability { - _ if self.inside_unsafe_cell => { - // Inside an `UnsafeCell` is like inside a `static mut`, the "outer" - // mutability does not matter. - InternMode::Static(ref_mutability) - } - Mutability::Not => { - // A shared reference, things become immutable. - // We do *not* consider `freeze` here: `intern_shallow` considers - // `freeze` for the actual mutability of this allocation; the intern - // mode for references contained in this allocation is tracked more - // precisely when traversing the referenced data (by tracking - // `UnsafeCell`). This makes sure that `&(&i32, &Cell)` still - // has the left inner reference interned into a read-only - // allocation. - InternMode::Static(Mutability::Not) - } - Mutability::Mut => { - // Mutable reference. - InternMode::Static(mutbl) - } - } - } - InternMode::Const => { - // Ignore `UnsafeCell`, everything is immutable. Validity does some sanity - // checking for mutable references that we encounter -- they must all be - // ZST. - InternMode::Const - } - }; - match self.intern_shallow(prov.alloc_id(), ref_mode, Some(referenced_ty)) { - // No need to recurse, these are interned already and statics may have - // cycles, so we don't want to recurse there - Some(IsStaticOrFn) => {} - // intern everything referenced by this value. The mutability is taken from the - // reference. It is checked above that mutable references only happen in - // `static mut` - None => self.ref_tracking.track((mplace, ref_mode), || ()), - } - } - Ok(()) - } else { - // Not a reference. Check if we want to recurse. - let is_walk_needed = |mplace: &MPlaceTy<'tcx>| -> InterpResult<'tcx, bool> { - // ZSTs cannot contain pointers, we can avoid the interning walk. - if mplace.layout.is_zst() { - return Ok(false); - } - - // Now, check whether this allocation could contain references. - // - // Note, this check may sometimes not be cheap, so we only do it when the walk we'd like - // to avoid could be expensive: on the potentially larger types, arrays and slices, - // rather than on all aggregates unconditionally. - if matches!(mplace.layout.ty.kind(), ty::Array(..) | ty::Slice(..)) { - let Some((size, _align)) = self.ecx.size_and_align_of_mplace(mplace)? else { - // We do the walk if we can't determine the size of the mplace: we may be - // dealing with extern types here in the future. - return Ok(true); - }; - - // If there is no provenance in this allocation, it does not contain references - // that point to another allocation, and we can avoid the interning walk. - if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr(), size)? { - if !alloc.has_provenance() { - return Ok(false); - } - } else { - // We're encountering a ZST here, and can avoid the walk as well. - return Ok(false); - } - } - - // In the general case, we do the walk. - Ok(true) - }; - - // If this allocation contains no references to intern, we avoid the potentially costly - // walk. - // - // We can do this before the checks for interior mutability below, because only references - // are relevant in that situation, and we're checking if there are any here. - if !is_walk_needed(mplace)? { - return Ok(()); - } - - if let Some(def) = mplace.layout.ty.ty_adt_def() { - if def.is_unsafe_cell() { - // We are crossing over an `UnsafeCell`, we can mutate again. This means that - // References we encounter inside here are interned as pointing to mutable - // allocations. - // Remember the `old` value to handle nested `UnsafeCell`. - let old = std::mem::replace(&mut self.inside_unsafe_cell, true); - let walked = self.walk_value(mplace); - self.inside_unsafe_cell = old; - return walked; - } - } - - self.walk_value(mplace) - } + // record child allocations + for &(_, prov) in alloc.provenance().ptrs().iter() { + recursive_alloc(ecx, prov); } + // link the alloc id to the actual allocation + let alloc = ecx.tcx.mk_const_alloc(alloc); + ecx.tcx.set_alloc_id_memory(alloc_id, alloc); + Ok(()) } /// How a constant value should be interned. @@ -332,122 +99,108 @@ pub fn intern_const_alloc_recursive< intern_kind: InternKind, ret: &MPlaceTy<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let tcx = ecx.tcx; - let base_intern_mode = match intern_kind { - InternKind::Static(mutbl) => InternMode::Static(mutbl), - // `Constant` includes array lengths. - InternKind::Constant | InternKind::Promoted => InternMode::Const, - }; - - // Type based interning. - // `ref_tracking` tracks typed references we have already interned and still need to crawl for - // more typed information inside them. - // `leftover_allocations` collects *all* allocations we see, because some might not - // be available in a typed way. They get interned at the end. - let mut ref_tracking = RefTracking::empty(); - let leftover_allocations = &mut FxIndexSet::default(); - - // start with the outermost allocation - intern_shallow( - ecx, - leftover_allocations, - // The outermost allocation must exist, because we allocated it with - // `Memory::allocate`. - ret.ptr().provenance.unwrap().alloc_id(), - base_intern_mode, - Some(ret.layout.ty), - ); - - ref_tracking.track((ret.clone(), base_intern_mode), || ()); - - while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() { - let res = InternVisitor { - ref_tracking: &mut ref_tracking, - ecx, - mode, - leftover_allocations, - inside_unsafe_cell: false, + // We are interning recursively, and for mutability we are distinguishing the "root" allocation + // that we are starting in, and all other allocations that we are encountering recursively. + let (base_mutability, inner_mutability) = match intern_kind { + InternKind::Constant | InternKind::Promoted => { + // Completely immutable. Interning anything mutably here can only lead to unsoundness, + // since all consts are conceptually independent values but share the same underlying + // memory. + (Mutability::Not, Mutability::Not) } - .visit_value(&mplace); - // We deliberately *ignore* interpreter errors here. When there is a problem, the remaining - // references are "leftover"-interned, and later validation will show a proper error - // and point at the right part of the value causing the problem. - match res { - Ok(()) => {} - Err(error) => { - ecx.tcx.dcx().span_delayed_bug( - ecx.tcx.span, - format!( - "error during interning should later cause validation failure: {}", - ecx.format_error(error), - ), - ); - } + InternKind::Static(Mutability::Not) => { + ( + // Outermost allocation is mutable if `!Freeze`. + if ret.layout.ty.is_freeze(*ecx.tcx, ecx.param_env) { + Mutability::Not + } else { + Mutability::Mut + }, + // Inner allocations are never mutable. They can only arise via the "tail + // expression" / "outer scope" rule, and we treat them consistently with `const`. + Mutability::Not, + ) } - } - - // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw - // pointers, ... So we can't intern them according to their type rules + InternKind::Static(Mutability::Mut) => { + // Just make everything mutable. We accept code like + // `static mut X = &mut [42]`, so even inner allocations need to be mutable. + (Mutability::Mut, Mutability::Mut) + } + }; - let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect(); - debug!(?todo); - debug!("dead_alloc_map: {:#?}", ecx.memory.dead_alloc_map); - while let Some(alloc_id) = todo.pop() { - if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) { - // We can't call the `intern_shallow` method here, as its logic is tailored to safe - // references and a `leftover_allocations` set (where we only have a todo-list here). - // So we hand-roll the interning logic here again. - match intern_kind { - // Statics may point to mutable allocations. - // Even for immutable statics it would be ok to have mutable allocations behind - // raw pointers, e.g. for `static FOO: *const AtomicUsize = &AtomicUsize::new(42)`. - InternKind::Static(_) => {} - // Raw pointers in promoteds may only point to immutable things so we mark - // everything as immutable. - // It is UB to mutate through a raw pointer obtained via an immutable reference: - // Since all references and pointers inside a promoted must by their very definition - // be created from an immutable reference (and promotion also excludes interior - // mutability), mutating through them would be UB. - // There's no way we can check whether the user is using raw pointers correctly, - // so all we can do is mark this as immutable here. - InternKind::Promoted => { - // See const_eval::machine::MemoryExtra::can_access_statics for why - // immutability is so important. - alloc.mutability = Mutability::Not; - } - // If it's a constant, we should not have any "leftovers" as everything - // is tracked by const-checking. - // FIXME: downgrade this to a warning? It rejects some legitimate consts, - // such as `const CONST_RAW: *const Vec = &Vec::new() as *const _;`. - // - // NOTE: it looks likes this code path is only reachable when we try to intern - // something that cannot be promoted, which in constants means values that have - // drop glue, such as the example above. - InternKind::Constant => { - ecx.tcx.dcx().emit_err(UnsupportedUntypedPointer { span: ecx.tcx.span }); - // For better errors later, mark the allocation as immutable. - alloc.mutability = Mutability::Not; - } - } - let alloc = tcx.mk_const_alloc(alloc); - tcx.set_alloc_id_memory(alloc_id, alloc); - for &(_, prov) in alloc.inner().provenance().ptrs().iter() { - let alloc_id = prov.alloc_id(); - if leftover_allocations.insert(alloc_id) { - todo.push(alloc_id); + // Initialize recursive interning. + let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); + let mut todo = vec![(base_alloc_id, base_mutability)]; + // We need to distinguish "has just been interned" from "was already in `tcx`", + // so we track this in a separate set. + let mut just_interned = FxHashSet::default(); + // Whether we encountered a bad mutable pointer. + // We want to first report "dangling" and then "mutable", so we need to delay reporting these + // errors. + let mut found_bad_mutable_pointer = false; + + // Keep interning as long as there are things to intern. + // We show errors if there are dangling pointers, or mutable pointers in immutable contexts + // (i.e., everything except for `static mut`). When these errors affect references, it is + // unfortunate that we show these errors here and not during validation, since validation can + // show much nicer errors. However, we do need these checks to be run on all pointers, including + // raw pointers, so we cannot rely on validation to catch them -- and since interning runs + // before validation, and interning doesn't know the type of anything, this means we can't show + // better errors. Maybe we should consider doing validation before interning in the future. + while let Some((alloc_id, mutability)) = todo.pop() { + if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { + // Already interned. + debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id)); + continue; + } + just_interned.insert(alloc_id); + intern_shallow(ecx, alloc_id, mutability, |ecx, prov| { + let alloc_id = prov.alloc_id(); + if intern_kind != InternKind::Promoted + && inner_mutability == Mutability::Not + && !prov.immutable() + { + if ecx.tcx.try_get_global_alloc(alloc_id).is_some() + && !just_interned.contains(&alloc_id) + { + // This is a pointer to some memory from another constant. We encounter mutable + // pointers to such memory since we do not always track immutability through + // these "global" pointers. Allowing them is harmless; the point of these checks + // during interning is to justify why we intern the *new* allocations immutably, + // so we can completely ignore existing allocations. We also don't need to add + // this to the todo list, since after all it is already interned. + return; } + // Found a mutable pointer inside a const where inner allocations should be + // immutable. We exclude promoteds from this, since things like `&mut []` and + // `&None::>` lead to promotion that can produce mutable pointers. We rely + // on the promotion analysis not screwing up to ensure that it is sound to intern + // promoteds as immutable. + found_bad_mutable_pointer = true; } - } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) { - // Codegen does not like dangling pointers, and generally `tcx` assumes that - // all allocations referenced anywhere actually exist. So, make sure we error here. - let reported = ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span }); - return Err(reported); - } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() { - // We have hit an `AllocId` that is neither in local or global memory and isn't - // marked as dangling by local memory. That should be impossible. - span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); - } + // We always intern with `inner_mutability`, and furthermore we ensured above that if + // that is "immutable", then there are *no* mutable pointers anywhere in the newly + // interned memory -- justifying that we can indeed intern immutably. However this also + // means we can *not* easily intern immutably here if `prov.immutable()` is true and + // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and + // we'd have to somehow check that they are *all* immutable before deciding that this + // allocation can be made immutable. In the future we could consider analyzing all + // pointers before deciding which allocations can be made immutable; but for now we are + // okay with losing some potential for immutability here. This can anyway only affect + // `static mut`. + todo.push((alloc_id, inner_mutability)); + }) + .map_err(|()| { + ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) + })?; } + if found_bad_mutable_pointer { + return Err(ecx + .tcx + .dcx() + .emit_err(MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })); + } + Ok(()) } @@ -462,29 +215,18 @@ pub fn intern_const_alloc_for_constprop< ecx: &mut InterpCx<'mir, 'tcx, M>, alloc_id: AllocId, ) -> InterpResult<'tcx, ()> { - // Move allocation to `tcx`. - let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else { - // Pointer not found in local memory map. It is either a pointer to the global - // map, or dangling. - if ecx.tcx.try_get_global_alloc(alloc_id).is_none() { - throw_ub!(DeadLocal) - } + if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // The constant is already in global memory. Do nothing. return Ok(()); - }; - - alloc.mutability = Mutability::Not; - - // We are not doing recursive interning, so we don't currently support provenance. - // (If this assertion ever triggers, we should just implement a - // proper recursive interning loop.) - assert!(alloc.provenance().ptrs().is_empty()); - - // Link the alloc id to the actual allocation - let alloc = ecx.tcx.mk_const_alloc(alloc); - ecx.tcx.set_alloc_id_memory(alloc_id, alloc); - - Ok(()) + } + // Move allocation to `tcx`. + intern_shallow(ecx, alloc_id, Mutability::Not, |_ecx, _| { + // We are not doing recursive interning, so we don't currently support provenance. + // (If this assertion ever triggers, we should just implement a + // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. + panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance") + }) + .map_err(|()| err_ub!(DeadLocal).into()) } impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> @@ -504,12 +246,16 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> // `allocate` picks a fresh AllocId that we will associate with its data below. let dest = self.allocate(layout, MemoryKind::Stack)?; f(self, &dest.clone().into())?; - let mut alloc = - self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap().alloc_id()).unwrap().1; - alloc.mutability = Mutability::Not; - let alloc = self.tcx.mk_const_alloc(alloc); let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance - self.tcx.set_alloc_id_memory(alloc_id, alloc); + intern_shallow(self, alloc_id, Mutability::Not, |ecx, prov| { + // We are not doing recursive interning, so we don't currently support provenance. + // (If this assertion ever triggers, we should just implement a + // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. + if !ecx.tcx.try_get_global_alloc(prov.alloc_id()).is_some() { + panic!("`intern_with_temp_alloc` with nested allocations"); + } + }) + .unwrap(); Ok(alloc_id) } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 76807c62e4a36..a80d36960f977 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -85,6 +85,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 5e69965512b94..b981a1ee2ca16 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -13,6 +13,7 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::DefId; +use rustc_span::Span; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; @@ -510,6 +511,27 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { ) -> InterpResult<'tcx> { Ok(()) } + + /// Evaluate the given constant. The `eval` function will do all the required evaluation, + /// but this hook has the chance to do some pre/postprocessing. + #[inline(always)] + fn eval_mir_constant( + ecx: &InterpCx<'mir, 'tcx, Self>, + val: mir::Const<'tcx>, + span: Option, + layout: Option>, + eval: F, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + where + F: Fn( + &InterpCx<'mir, 'tcx, Self>, + mir::Const<'tcx>, + Option, + Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + { + eval(ecx, val, span, layout) + } } /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 3afd14eb57435..38ad8cbf3a691 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -396,7 +396,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// to the allocation it points to. Supports both shared and mutable references, as the actual /// checking is offloaded to a helper closure. /// - /// If this returns `None`, the size is 0; it can however return `Some` even for size 0. + /// Returns `None` if and only if the size is 0. fn check_and_deref_ptr( &self, ptr: Pointer>, @@ -1214,10 +1214,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size_in_bytes = size.bytes_usize(); // For particularly large arrays (where this is perf-sensitive) it's common that // we're writing a single byte repeatedly. So, optimize that case to a memset. - if size_in_bytes == 1 && num_copies >= 1 { - // SAFETY: `src_bytes` would be read from anyway by copies below (num_copies >= 1). - // Since size_in_bytes = 1, then the `init.no_bytes_init()` check above guarantees - // that this read at type `u8` is OK -- it must be an initialized byte. + if size_in_bytes == 1 { + debug_assert!(num_copies >= 1); // we already handled the zero-sized cases above. + // SAFETY: `src_bytes` would be read from anyway by `copy` below (num_copies >= 1). let value = *src_bytes; dest_bytes.write_bytes(value, (size * num_copies).bytes_usize()); } else if src_alloc_id == dest_alloc_id { diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index b39b219b46a14..4653c9016c698 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -260,8 +260,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { // This makes several assumptions about what layouts we will encounter; we match what // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). let inner_val: Immediate<_> = match (**self, self.layout.abi) { - // if the entire value is uninit, then so is the field (can happen in ConstProp) + // If the entire value is uninit, then so is the field (can happen in ConstProp). (Immediate::Uninit, _) => Immediate::Uninit, + // If the field is uninhabited, we can forget the data (can happen in ConstProp). + // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that + // has an `Uninhabited` variant, which means this case is possible. + _ if layout.abi.is_uninhabited() => Immediate::Uninit, // the field contains no information, can be left uninit // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST) _ if layout.is_zst() => Immediate::Uninit, @@ -643,11 +647,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of_local(frame, local, layout)?; let op = *frame.locals[local].access()?; if matches!(op, Operand::Immediate(_)) { - if layout.is_unsized() { - // ConstProp marks *all* locals as `Immediate::Uninit` since it cannot - // efficiently check whether they are sized. We have to catch that case here. - throw_inval!(ConstPropNonsense); - } + assert!(!layout.is_unsized()); } Ok(OpTy { op, layout }) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 639b269ac257a..772445f4f622e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -62,8 +62,8 @@ pub(super) struct MemPlace { impl MemPlace { /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { - MemPlace { ptr: self.ptr.map_provenance(f), ..self } + pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { + MemPlace { ptr: self.ptr.map_provenance(|p| p.map(f)), ..self } } /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. @@ -128,7 +128,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { } /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { + pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { MPlaceTy { mplace: self.mplace.map_provenance(f), ..self } } @@ -519,11 +519,7 @@ where } else { // Unsized `Local` isn't okay (we cannot store the metadata). match frame_ref.locals[local].access()? { - Operand::Immediate(_) => { - // ConstProp marks *all* locals as `Immediate::Uninit` since it cannot - // efficiently check whether they are sized. We have to catch that case here. - throw_inval!(ConstPropNonsense); - } + Operand::Immediate(_) => bug!(), Operand::Indirect(mplace) => Place::Ptr(*mplace), } }; @@ -816,17 +812,8 @@ where // avoid force_allocation. let src = match self.read_immediate_raw(src)? { Right(src_val) => { - // FIXME(const_prop): Const-prop can possibly evaluate an - // unsized copy operation when it thinks that the type is - // actually sized, due to a trivially false where-clause - // predicate like `where Self: Sized` with `Self = dyn Trait`. - // See #102553 for an example of such a predicate. - if src.layout().is_unsized() { - throw_inval!(ConstPropNonsense); - } - if dest.layout().is_unsized() { - throw_inval!(ConstPropNonsense); - } + assert!(!src.layout().is_unsized()); + assert!(!dest.layout().is_unsized()); assert_eq!(src.layout().size, dest.layout().size); // Yay, we got a value that we can write directly. return if layout_compat { diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 9a034ba22b989..3a441c1d649ca 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -153,11 +153,7 @@ where // Offset may need adjustment for unsized fields. let (meta, offset) = if field_layout.is_unsized() { - if base.layout().is_sized() { - // An unsized field of a sized type? Sure... - // But const-prop actually feeds us such nonsense MIR! (see test `const_prop/issue-86351.rs`) - throw_inval!(ConstPropNonsense); - } + assert!(!base.layout().is_sized()); let base_meta = base.meta(); // Re-use parent metadata to determine dynamic field layout. // With custom DSTS, this *will* execute user-defined code, but the same @@ -205,29 +201,9 @@ where // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) // So we just "offset" by 0. let layout = base.layout().for_variant(self, variant); - if layout.abi.is_uninhabited() { - // `read_discriminant` should have excluded uninhabited variants... but ConstProp calls - // us on dead code. - // In the future we might want to allow this to permit code like this: - // (this is a Rust/MIR pseudocode mix) - // ``` - // enum Option2 { - // Some(i32, !), - // None, - // } - // - // fn panic() -> ! { panic!() } - // - // let x: Option2; - // x.Some.0 = 42; - // x.Some.1 = panic(); - // SetDiscriminant(x, Some); - // ``` - // However, for now we don't generate such MIR, and this check here *has* found real - // bugs (see https://github.com/rust-lang/rust/issues/115145), so we will keep rejecting - // it. - throw_inval!(ConstPropNonsense) - } + // This variant may in fact be uninhabited. + // See . + // This cannot be `transmute` as variants *can* have a smaller size than the entire enum. base.offset(Size::ZERO, layout, self) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 7b993279f18e8..85a2e4778d252 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -373,7 +373,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) { // This is okay if they have the same metadata type. let meta_ty = |ty: Ty<'tcx>| { - let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, |ty| ty); + // Even if `ty` is normalized, the search for the unsized tail will project + // to fields, which can yield non-normalized types. So we need to provide a + // normalization function. + let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); + let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, normalize); assert!( !only_if_sized, "there should be no more 'maybe has that metadata' types during interpretation" @@ -541,6 +545,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 8b44b87647dab..90cde81c01874 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -9,12 +9,13 @@ use std::num::NonZeroUsize; use either::{Left, Right}; +use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::mir::interpret::{ - ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, ValidationErrorInfo, - ValidationErrorKind, ValidationErrorKind::*, + ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, + ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, }; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; @@ -123,15 +124,41 @@ pub enum PathElem { } /// Extra things to check for during validation of CTFE results. +#[derive(Copy, Clone)] pub enum CtfeValidationMode { - /// Regular validation, nothing special happening. - Regular, - /// Validation of a `const`. - /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const - /// allocation). Being an inner allocation makes a difference because the top-level allocation - /// of a `const` is copied for each use, but the inner allocations are implicitly shared. + /// Validation of a `static` + Static { mutbl: Mutability }, + /// Validation of a `const` (including promoteds). + /// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the + /// case for the top-level allocation of a `const`, where this is fine because the allocation will be + /// copied at each use site). /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). - Const { inner: bool, allow_static_ptrs: bool }, + Const { allow_immutable_unsafe_cell: bool, allow_static_ptrs: bool }, +} + +impl CtfeValidationMode { + fn allow_immutable_unsafe_cell(self) -> bool { + match self { + CtfeValidationMode::Static { .. } => false, + CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => { + allow_immutable_unsafe_cell + } + } + } + + fn allow_static_ptrs(self) -> bool { + match self { + CtfeValidationMode::Static { .. } => true, // statics can point to statics + CtfeValidationMode::Const { allow_static_ptrs, .. } => allow_static_ptrs, + } + } + + fn may_contain_mutable_ref(self) -> bool { + match self { + CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut, + CtfeValidationMode::Const { .. } => false, + } + } } /// State for tracking recursive validation of references @@ -418,26 +445,52 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } // Recursive checking if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { + // Determine whether this pointer expects to be pointing to something mutable. + let ptr_expected_mutbl = match ptr_kind { + PointerKind::Box => Mutability::Mut, + PointerKind::Ref => { + let tam = value.layout.ty.builtin_deref(false).unwrap(); + // ZST never require mutability. We do not take into account interior mutability + // here since we cannot know if there really is an `UnsafeCell` inside + // `Option` -- so we check that in the recursive descent behind this + // reference. + if size == Size::ZERO { Mutability::Not } else { tam.mutbl } + } + }; // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) { // Let's see what kind of memory this points to. - let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id); + // `unwrap` since dangling pointers have already been handled. + let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id).unwrap(); match alloc_kind { - Some(GlobalAlloc::Static(did)) => { + GlobalAlloc::Static(did) => { // Special handling for pointers to statics (irrespective of their type). assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); - if matches!( - self.ctfe_mode, - Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) - ) { + if self.ctfe_mode.is_some_and(|c| !c.allow_static_ptrs()) { // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static, // but never read it (so we never entered `before_access_global`). throw_validation_failure!(self.path, PtrToStatic { ptr_kind }); } + // Mutability check. + if ptr_expected_mutbl == Mutability::Mut { + if matches!( + self.ecx.tcx.def_kind(did), + DefKind::Static(Mutability::Not) + ) && self + .ecx + .tcx + .type_of(did) + .no_bound_vars() + .expect("statics should not have generic parameters") + .is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all()) + { + throw_validation_failure!(self.path, MutableRefToImmutable); + } + } // We skip recursively checking other statics. These statics must be sound by // themselves, and the only way to get broken statics here is by using // unsafe code. @@ -450,18 +503,31 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // referring to statics). return Ok(()); } - Some(GlobalAlloc::Memory(alloc)) => { + GlobalAlloc::Memory(alloc) => { if alloc.inner().mutability == Mutability::Mut && matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { - // This should be unreachable, but if someone manages to copy a pointer - // out of a `static`, then that pointer might point to mutable memory, - // and we would catch that here. - throw_validation_failure!(self.path, PtrToMut { ptr_kind }); + // This is impossible: this can only be some inner allocation of a + // `static mut` (everything else either hits the `GlobalAlloc::Static` + // case or is interned immutably). To get such a pointer we'd have to + // load it from a static, but such loads lead to a CTFE error. + span_bug!( + self.ecx.tcx.span, + "encountered reference to mutable memory inside a `const`" + ); + } + if ptr_expected_mutbl == Mutability::Mut + && alloc.inner().mutability == Mutability::Not + { + throw_validation_failure!(self.path, MutableRefToImmutable); + } + } + GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => { + // These are immutable, we better don't allow mutable pointers here. + if ptr_expected_mutbl == Mutability::Mut { + throw_validation_failure!(self.path, MutableRefToImmutable); } } - // Nothing to check for these. - None | Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {} } } let path = &self.path; @@ -532,11 +598,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(true) } ty::Ref(_, ty, mutbl) => { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) + if self.ctfe_mode.is_some_and(|c| !c.may_contain_mutable_ref()) && *mutbl == Mutability::Mut { - // A mutable reference inside a const? That does not seem right (except if it is - // a ZST). let layout = self.ecx.layout_of(*ty)?; if !layout.is_zst() { throw_validation_failure!(self.path, MutableRefInConst); @@ -580,6 +644,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Str | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) => Ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. @@ -642,6 +707,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ) } } + + fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool { + if let Some(mplace) = op.as_mplace_or_imm().left() { + if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { + if self.ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner().mutability + == Mutability::Mut + { + return true; + } + } + } + false + } } impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> @@ -705,10 +783,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> op: &OpTy<'tcx, M::Provenance>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { - // Special check preventing `UnsafeCell` inside unions in the inner part of constants. - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) { - if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { - throw_validation_failure!(self.path, UnsafeCell); + // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. + if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { + if !op.layout.is_zst() && !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { + if !self.in_mutable_memory(op) { + throw_validation_failure!(self.path, UnsafeCellInImmutable); + } } } Ok(()) @@ -730,11 +810,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } // Special check preventing `UnsafeCell` in the inner part of constants - if let Some(def) = op.layout.ty.ty_adt_def() { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) + if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { + if !op.layout.is_zst() + && let Some(def) = op.layout.ty.ty_adt_def() && def.is_unsafe_cell() { - throw_validation_failure!(self.path, UnsafeCell); + if !self.in_mutable_memory(op) { + throw_validation_failure!(self.path, UnsafeCellInImmutable); + } } } @@ -910,10 +993,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Complain about any other kind of error -- those are bad because we'd like to // report them in a way that shows *where* in the value the issue lies. Err(err) => { - bug!( - "Unexpected Undefined Behavior error during validation: {}", - self.format_error(err) - ); + bug!("Unexpected error during validation: {}", self.format_error(err)); } } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index d6c36ccc5ec8b..946a49982aa1a 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -11,20 +11,13 @@ Rust MIR: a lowered representation of Rust. #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] -#![feature(exact_size_is_empty)] #![feature(let_chains)] -#![feature(map_try_insert)] -#![feature(min_specialization)] #![feature(slice_ptr_get)] -#![feature(option_get_or_insert_default)] #![feature(never_type)] #![feature(trait_alias)] -#![feature(trusted_len)] -#![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] #![feature(if_let_guard)] -#![recursion_limit = "256"] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 89c65d9232586..5ff81615552bf 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -20,7 +20,7 @@ use std::mem; use std::ops::{ControlFlow, Deref}; use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; +use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; @@ -149,37 +149,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let return_loc = ccx.body.terminator_loc(return_block); - let custom_eq = match ccx.const_kind() { - // We don't care whether a `const fn` returns a value that is not structurally - // matchable. Functions calls are opaque and always use type-based qualification, so - // this value should never be used. - hir::ConstContext::ConstFn => true, - - // If we know that all values of the return type are structurally matchable, there's no - // need to run dataflow. - // Opaque types do not participate in const generics or pattern matching, so we can safely count them out. - _ if ccx.body.return_ty().has_opaque_types() - || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => - { - false - } - - hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => { - let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) - .into_engine(ccx.tcx, ccx.body) - .iterate_to_fixpoint() - .into_results_cursor(ccx.body); - - cursor.seek_after_primary_effect(return_loc); - cursor.get().contains(RETURN_PLACE) - } - }; - ConstQualifs { needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), - custom_eq, tainted_by_errors, } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 327c91731bf58..fb705d91977d7 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -2,7 +2,7 @@ use hir::def_id::LocalDefId; use hir::{ConstContext, LangItem}; -use rustc_errors::{error_code, DiagnosticBuilder}; +use rustc_errors::{codes::*, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -372,7 +372,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx.dcx().create_err(errors::UnallowedHeapAllocations { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), + teach: ccx.tcx.sess.teach(E0010).then_some(()), }) } } @@ -434,14 +434,14 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { span, opt_help: Some(()), kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + teach: ccx.tcx.sess.teach(E0492).then_some(()), }) } else { ccx.dcx().create_err(errors::InteriorMutableDataRefer { span, opt_help: None, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + teach: ccx.tcx.sess.teach(E0492).then_some(()), }) } } @@ -466,15 +466,15 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { match self.0 { - hir::BorrowKind::Raw => ccx.dcx().create_err(errors::UnallowedMutableRefsRaw { + hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + teach: ccx.tcx.sess.teach(E0764).then_some(()), }), hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + teach: ccx.tcx.sess.teach(E0764).then_some(()), }), } } @@ -491,10 +491,10 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let kind = ccx.const_kind(); match self.0 { - hir::BorrowKind::Raw => ccx.tcx.sess.create_feature_err( - errors::TransientMutBorrowErrRaw { span, kind }, - sym::const_mut_refs, - ), + hir::BorrowKind::Raw => ccx + .tcx + .sess + .create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs), hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err( errors::TransientMutBorrowErr { span, kind }, sym::const_mut_refs, @@ -588,7 +588,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { ccx.dcx().create_err(errors::StaticAccessErr { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()), + teach: ccx.tcx.sess.teach(E0013).then_some(()), }) } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 1efa52df5817b..67fef20807910 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::*; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty}; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, + ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, }; use super::ConstCx; @@ -24,7 +24,6 @@ pub fn in_any_value_of_ty<'tcx>( has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), - custom_eq: CustomEq::in_any_value_of_ty(cx, ty), tainted_by_errors, } } @@ -213,35 +212,6 @@ impl Qualif for NeedsNonConstDrop { } } -/// A constant that cannot be used as part of a pattern in a `match` expression. -pub struct CustomEq; - -impl Qualif for CustomEq { - const ANALYSIS_NAME: &'static str = "flow_custom_eq"; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.custom_eq - } - - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`, - // we know that at least some values of that type are not structural-match. I say "some" - // because that component may be part of an enum variant (e.g., - // `Option::::Some`), in which case some values of this type may be - // structural-match (`Option::None`). - traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some() - } - - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - def: AdtDef<'tcx>, - args: GenericArgsRef<'tcx>, - ) -> bool { - let ty = Ty::new_adt(cx.tcx, def, args); - !ty.is_structural_eq_shallow(cx.tcx) - } -} - // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. /// Returns `true` if this `Rvalue` contains qualif `Q`. diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index f39c1b4f2abdd..5b90692970d53 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -58,6 +58,7 @@ impl<'tcx> MirPass<'tcx> for Validator { let body_abi = match body_ty.kind() { ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::Closure(..) => Abi::RustCall, + ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, _ => { span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase) @@ -665,6 +666,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; check_equal(self, location, f_ty); } + ty::CoroutineClosure(_, args) => { + let args = args.as_coroutine_closure(); + let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else { + fail_out_of_bounds(self, location); + return; + }; + check_equal(self, location, f_ty); + } &ty::Coroutine(def_id, args) => { let f_ty = if let Some(var) = parent_ty.variant_index { let gen_body = if def_id == self.body.source.def_id() { @@ -796,7 +805,86 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; } match rvalue { - Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {} + Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {} + Rvalue::Aggregate(kind, fields) => match **kind { + AggregateKind::Tuple => {} + AggregateKind::Array(dest) => { + for src in fields { + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { + self.fail(location, "array field has the wrong type"); + } + } + } + AggregateKind::Adt(def_id, idx, args, _, Some(field)) => { + let adt_def = self.tcx.adt_def(def_id); + assert!(adt_def.is_union()); + assert_eq!(idx, FIRST_VARIANT); + let dest_ty = self.tcx.normalize_erasing_regions( + self.param_env, + adt_def.non_enum_variant().fields[field].ty(self.tcx, args), + ); + if fields.len() == 1 { + let src_ty = fields.raw[0].ty(self.body, self.tcx); + if !self.mir_assign_valid_types(src_ty, dest_ty) { + self.fail(location, "union field has the wrong type"); + } + } else { + self.fail(location, "unions should have one initialized field"); + } + } + AggregateKind::Adt(def_id, idx, args, _, None) => { + let adt_def = self.tcx.adt_def(def_id); + assert!(!adt_def.is_union()); + let variant = &adt_def.variants()[idx]; + if variant.fields.len() != fields.len() { + self.fail(location, "adt has the wrong number of initialized fields"); + } + for (src, dest) in std::iter::zip(fields, &variant.fields) { + let dest_ty = self + .tcx + .normalize_erasing_regions(self.param_env, dest.ty(self.tcx, args)); + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest_ty) { + self.fail(location, "adt field has the wrong type"); + } + } + } + AggregateKind::Closure(_, args) => { + let upvars = args.as_closure().upvar_tys(); + if upvars.len() != fields.len() { + self.fail(location, "closure has the wrong number of initialized fields"); + } + for (src, dest) in std::iter::zip(fields, upvars) { + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { + self.fail(location, "closure field has the wrong type"); + } + } + } + AggregateKind::Coroutine(_, args) => { + let upvars = args.as_coroutine().upvar_tys(); + if upvars.len() != fields.len() { + self.fail(location, "coroutine has the wrong number of initialized fields"); + } + for (src, dest) in std::iter::zip(fields, upvars) { + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { + self.fail(location, "coroutine field has the wrong type"); + } + } + } + AggregateKind::CoroutineClosure(_, args) => { + let upvars = args.as_coroutine_closure().upvar_tys(); + if upvars.len() != fields.len() { + self.fail( + location, + "coroutine-closure has the wrong number of initialized fields", + ); + } + for (src, dest) in std::iter::zip(fields, upvars) { + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { + self.fail(location, "coroutine-closure field has the wrong type"); + } + } + } + }, Rvalue::Ref(_, BorrowKind::Fake, _) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 4a3cfd50b4414..36a315b8f3078 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -27,6 +27,7 @@ fn alloc_caller_location<'mir, 'tcx>( // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 ecx.allocate_str("", MemoryKind::CallerLocation, Mutability::Not).unwrap() }; + let file = file.map_provenance(CtfeProvenance::as_immutable); let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 1e58bd645cdde..a8060463b69ed 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -14,7 +14,7 @@ pub use self::type_name::type_name; /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the /// same type as the result. #[inline] -pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool { +pub fn binop_left_homogeneous(op: mir::BinOp) -> bool { use rustc_middle::mir::BinOp::*; match op { Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor @@ -26,7 +26,7 @@ pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool { /// Classify whether an operator is "right-homogeneous", i.e., the RHS has the /// same type as the LHS. #[inline] -pub(crate) fn binop_right_homogeneous(op: mir::BinOp) -> bool { +pub fn binop_right_homogeneous(op: mir::BinOp) -> bool { use rustc_middle::mir::BinOp::*; match op { Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 976e42ad76836..2b80623ab4545 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -51,6 +51,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 9d598c32e6fc4..08aa68ca54a7a 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -7,10 +7,10 @@ edition = "2021" # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" +either = "1.0" elsa = "=1.7.1" ena = "0.14.2" indexmap = { version = "2.0.0" } -itertools = "0.11" jobserver_crate = { version = "0.1.27", package = "jobserver" } libc = "0.2" measureme = "11" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 93b4032c31089..a71d012db2d9d 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,6 +10,7 @@ #![allow(internal_features)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] +#![cfg_attr(not(parallel_compiler), feature(cell_leak))] #![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::untranslatable_diagnostic)] #![deny(unsafe_op_in_unsafe_fn)] @@ -18,7 +19,6 @@ #![feature(allocator_api)] #![feature(array_windows)] #![feature(auto_traits)] -#![feature(cell_leak)] #![feature(cfg_match)] #![feature(core_intrinsics)] #![feature(extend_one)] @@ -93,6 +93,7 @@ pub mod aligned; pub mod frozen; mod hashes; pub mod owned_slice; +pub mod packed; pub mod sso; pub mod steal; pub mod tagged_ptr; @@ -147,7 +148,7 @@ pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Printer { f } } -// See comments in src/librustc_middle/lib.rs +// See comments in compiler/rustc_middle/src/tests.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 266e54604a6b4..a9ccfbed41165 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -177,7 +177,6 @@ cfg_match! { [Vec where T: DynSync, A: std::alloc::Allocator + DynSync] [Box where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync] [crate::sync::RwLock where T: DynSend + DynSync] - [crate::sync::OneThread where T] [crate::sync::WorkerLocal where T: DynSend] [crate::intern::Interned<'a, T> where 'a, T: DynSync] [crate::tagged_ptr::CopyTaggedPtr where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool] diff --git a/compiler/rustc_data_structures/src/packed.rs b/compiler/rustc_data_structures/src/packed.rs new file mode 100644 index 0000000000000..b8d4b295dfa10 --- /dev/null +++ b/compiler/rustc_data_structures/src/packed.rs @@ -0,0 +1,71 @@ +use crate::stable_hasher::{HashStable, StableHasher}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::cmp::Ordering; +use std::fmt; + +#[repr(packed(8))] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Pu128(pub u128); + +impl Pu128 { + #[inline] + pub fn get(self) -> u128 { + self.0 + } +} + +impl From for Pu128 { + #[inline] + fn from(value: u128) -> Self { + Self(value) + } +} + +impl PartialEq for Pu128 { + #[inline] + fn eq(&self, other: &u128) -> bool { + ({ self.0 }) == *other + } +} + +impl PartialOrd for Pu128 { + #[inline] + fn partial_cmp(&self, other: &u128) -> Option { + { self.0 }.partial_cmp(other) + } +} + +impl fmt::Display for Pu128 { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + { self.0 }.fmt(f) + } +} + +impl fmt::UpperHex for Pu128 { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + { self.0 }.fmt(f) + } +} + +impl HashStable for Pu128 { + #[inline] + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + { self.0 }.hash_stable(ctx, hasher) + } +} + +impl Encodable for Pu128 { + #[inline] + fn encode(&self, s: &mut S) { + { self.0 }.encode(s); + } +} + +impl Decodable for Pu128 { + #[inline] + fn decode(d: &mut D) -> Self { + Self(u128::decode(d)) + } +} diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 162dbd234d676..4b02b18346069 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -3,7 +3,7 @@ use crate::fx::{FxHashMap, FxHasher}; use crate::sync::{is_dyn_thread_safe, CacheAligned}; use crate::sync::{Lock, LockGuard, Mode}; #[cfg(parallel_compiler)] -use itertools::Either; +use either::Either; use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; use std::hash::{Hash, Hasher}; diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 04e359a54708c..2ef4a2ccd8476 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -1,6 +1,6 @@ use crate::fx::FxHashMap; use arrayvec::ArrayVec; -use itertools::Either; +use either::Either; use std::fmt; use std::hash::Hash; use std::ops::Index; diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 48edfba8da082..adcb6ceaebf89 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -43,7 +43,6 @@ pub use crate::marker::*; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; -use std::ops::{Deref, DerefMut}; mod lock; pub use lock::{Lock, LockGuard, Mode}; @@ -309,8 +308,6 @@ cfg_match! { use parking_lot::RwLock as InnerRwLock; - use std::thread; - /// 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; @@ -445,56 +442,3 @@ impl Clone for RwLock { RwLock::new(self.borrow().clone()) } } - -/// A type which only allows its inner value to be used in one thread. -/// It will panic if it is used on multiple threads. -#[derive(Debug)] -pub struct OneThread { - #[cfg(parallel_compiler)] - thread: thread::ThreadId, - inner: T, -} - -#[cfg(parallel_compiler)] -unsafe impl std::marker::Sync for OneThread {} -#[cfg(parallel_compiler)] -unsafe impl std::marker::Send for OneThread {} - -impl OneThread { - #[inline(always)] - fn check(&self) { - #[cfg(parallel_compiler)] - assert_eq!(thread::current().id(), self.thread); - } - - #[inline(always)] - pub fn new(inner: T) -> Self { - OneThread { - #[cfg(parallel_compiler)] - thread: thread::current().id(), - inner, - } - } - - #[inline(always)] - pub fn into_inner(value: Self) -> T { - value.check(); - value.inner - } -} - -impl Deref for OneThread { - type Target = T; - - fn deref(&self) -> &T { - self.check(); - &self.inner - } -} - -impl DerefMut for OneThread { - fn deref_mut(&mut self) -> &mut T { - self.check(); - &mut self.inner - } -} diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 97a7dfef3b395..bfdd871455c94 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -15,7 +15,6 @@ rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_error_codes = { path = "../rustc_error_codes" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 11dcf4108d4ec..5903c43ae98af 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -9,11 +9,9 @@ #![feature(rustdoc_internals)] #![allow(internal_features)] #![feature(decl_macro)] -#![feature(lazy_cell)] #![feature(let_chains)] #![feature(panic_update_hook)] #![feature(result_flattening)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -25,9 +23,8 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; -use rustc_errors::registry::{InvalidErrorCode, Registry}; -use rustc_errors::{markdown, ColorConfig}; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; +use rustc_errors::registry::Registry; +use rustc_errors::{markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, PResult}; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; @@ -209,7 +206,7 @@ impl Callbacks for TimePassesCallbacks { } pub fn diagnostics_registry() -> Registry { - Registry::new(rustc_error_codes::DIAGNOSTICS) + Registry::new(rustc_errors::codes::DIAGNOSTICS) } /// This is the primary entry point for rustc. @@ -537,37 +534,36 @@ pub enum Compilation { } fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, color: ColorConfig) { + // Allow "E0123" or "0123" form. let upper_cased_code = code.to_ascii_uppercase(); - let normalised = - if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") }; - match registry.try_find_description(&normalised) { - Ok(description) => { - let mut is_in_code_block = false; - let mut text = String::new(); - // Slice off the leading newline and print. - for line in description.lines() { - let indent_level = - line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len()); - let dedented_line = &line[indent_level..]; - if dedented_line.starts_with("```") { - is_in_code_block = !is_in_code_block; - text.push_str(&line[..(indent_level + 3)]); - } else if is_in_code_block && dedented_line.starts_with("# ") { - continue; - } else { - text.push_str(line); - } - text.push('\n'); - } - if io::stdout().is_terminal() { - show_md_content_with_pager(&text, color); + let start = if upper_cased_code.starts_with('E') { 1 } else { 0 }; + if let Ok(code) = upper_cased_code[start..].parse::() + && let Ok(description) = registry.try_find_description(ErrCode::from_u32(code)) + { + let mut is_in_code_block = false; + let mut text = String::new(); + // Slice off the leading newline and print. + for line in description.lines() { + let indent_level = + line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len()); + let dedented_line = &line[indent_level..]; + if dedented_line.starts_with("```") { + is_in_code_block = !is_in_code_block; + text.push_str(&line[..(indent_level + 3)]); + } else if is_in_code_block && dedented_line.starts_with("# ") { + continue; } else { - safe_print!("{text}"); + text.push_str(line); } + text.push('\n'); } - Err(InvalidErrorCode) => { - early_dcx.early_fatal(format!("{code} is not a valid error code")); + if io::stdout().is_terminal() { + show_md_content_with_pager(&text, color); + } else { + safe_print!("{text}"); } + } else { + early_dcx.early_fatal(format!("{code} is not a valid error code")); } } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs deleted file mode 100644 index 9cd9ed54d4146..0000000000000 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ /dev/null @@ -1,658 +0,0 @@ -// Error messages for EXXXX errors. Each message should start and end with a -// new line, and be wrapped to 80 characters. In vim you can `:set tw=80` and -// use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -// -// /!\ IMPORTANT /!\ -// -// Error messages' format must follow the RFC 1567 available here: -// https://rust-lang.github.io/rfcs/1567-long-error-codes-explanation-normalization.html - -register_diagnostics! { -E0001: include_str!("./error_codes/E0001.md"), -E0002: include_str!("./error_codes/E0002.md"), -E0004: include_str!("./error_codes/E0004.md"), -E0005: include_str!("./error_codes/E0005.md"), -E0007: include_str!("./error_codes/E0007.md"), -E0009: include_str!("./error_codes/E0009.md"), -E0010: include_str!("./error_codes/E0010.md"), -E0013: include_str!("./error_codes/E0013.md"), -E0014: include_str!("./error_codes/E0014.md"), -E0015: include_str!("./error_codes/E0015.md"), -E0023: include_str!("./error_codes/E0023.md"), -E0025: include_str!("./error_codes/E0025.md"), -E0026: include_str!("./error_codes/E0026.md"), -E0027: include_str!("./error_codes/E0027.md"), -E0029: include_str!("./error_codes/E0029.md"), -E0030: include_str!("./error_codes/E0030.md"), -E0033: include_str!("./error_codes/E0033.md"), -E0034: include_str!("./error_codes/E0034.md"), -E0038: include_str!("./error_codes/E0038.md"), -E0040: include_str!("./error_codes/E0040.md"), -E0044: include_str!("./error_codes/E0044.md"), -E0045: include_str!("./error_codes/E0045.md"), -E0046: include_str!("./error_codes/E0046.md"), -E0049: include_str!("./error_codes/E0049.md"), -E0050: include_str!("./error_codes/E0050.md"), -E0053: include_str!("./error_codes/E0053.md"), -E0054: include_str!("./error_codes/E0054.md"), -E0055: include_str!("./error_codes/E0055.md"), -E0057: include_str!("./error_codes/E0057.md"), -E0059: include_str!("./error_codes/E0059.md"), -E0060: include_str!("./error_codes/E0060.md"), -E0061: include_str!("./error_codes/E0061.md"), -E0062: include_str!("./error_codes/E0062.md"), -E0063: include_str!("./error_codes/E0063.md"), -E0067: include_str!("./error_codes/E0067.md"), -E0069: include_str!("./error_codes/E0069.md"), -E0070: include_str!("./error_codes/E0070.md"), -E0071: include_str!("./error_codes/E0071.md"), -E0072: include_str!("./error_codes/E0072.md"), -E0073: include_str!("./error_codes/E0073.md"), -E0074: include_str!("./error_codes/E0074.md"), -E0075: include_str!("./error_codes/E0075.md"), -E0076: include_str!("./error_codes/E0076.md"), -E0077: include_str!("./error_codes/E0077.md"), -E0080: include_str!("./error_codes/E0080.md"), -E0081: include_str!("./error_codes/E0081.md"), -E0084: include_str!("./error_codes/E0084.md"), -E0087: include_str!("./error_codes/E0087.md"), -E0088: include_str!("./error_codes/E0088.md"), -E0089: include_str!("./error_codes/E0089.md"), -E0090: include_str!("./error_codes/E0090.md"), -E0091: include_str!("./error_codes/E0091.md"), -E0092: include_str!("./error_codes/E0092.md"), -E0093: include_str!("./error_codes/E0093.md"), -E0094: include_str!("./error_codes/E0094.md"), -E0106: include_str!("./error_codes/E0106.md"), -E0107: include_str!("./error_codes/E0107.md"), -E0109: include_str!("./error_codes/E0109.md"), -E0110: include_str!("./error_codes/E0110.md"), -E0116: include_str!("./error_codes/E0116.md"), -E0117: include_str!("./error_codes/E0117.md"), -E0118: include_str!("./error_codes/E0118.md"), -E0119: include_str!("./error_codes/E0119.md"), -E0120: include_str!("./error_codes/E0120.md"), -E0121: include_str!("./error_codes/E0121.md"), -E0124: include_str!("./error_codes/E0124.md"), -E0128: include_str!("./error_codes/E0128.md"), -E0130: include_str!("./error_codes/E0130.md"), -E0131: include_str!("./error_codes/E0131.md"), -E0132: include_str!("./error_codes/E0132.md"), -E0133: include_str!("./error_codes/E0133.md"), -E0136: include_str!("./error_codes/E0136.md"), -E0137: include_str!("./error_codes/E0137.md"), -E0138: include_str!("./error_codes/E0138.md"), -E0139: include_str!("./error_codes/E0139.md"), -E0152: include_str!("./error_codes/E0152.md"), -E0154: include_str!("./error_codes/E0154.md"), -E0158: include_str!("./error_codes/E0158.md"), -E0161: include_str!("./error_codes/E0161.md"), -E0162: include_str!("./error_codes/E0162.md"), -E0164: include_str!("./error_codes/E0164.md"), -E0165: include_str!("./error_codes/E0165.md"), -E0170: include_str!("./error_codes/E0170.md"), -E0178: include_str!("./error_codes/E0178.md"), -E0183: include_str!("./error_codes/E0183.md"), -E0184: include_str!("./error_codes/E0184.md"), -E0185: include_str!("./error_codes/E0185.md"), -E0186: include_str!("./error_codes/E0186.md"), -E0191: include_str!("./error_codes/E0191.md"), -E0192: include_str!("./error_codes/E0192.md"), -E0193: include_str!("./error_codes/E0193.md"), -E0195: include_str!("./error_codes/E0195.md"), -E0197: include_str!("./error_codes/E0197.md"), -E0198: include_str!("./error_codes/E0198.md"), -E0199: include_str!("./error_codes/E0199.md"), -E0200: include_str!("./error_codes/E0200.md"), -E0201: include_str!("./error_codes/E0201.md"), -E0203: include_str!("./error_codes/E0203.md"), -E0204: include_str!("./error_codes/E0204.md"), -E0205: include_str!("./error_codes/E0205.md"), -E0206: include_str!("./error_codes/E0206.md"), -E0207: include_str!("./error_codes/E0207.md"), -E0208: include_str!("./error_codes/E0208.md"), -E0210: include_str!("./error_codes/E0210.md"), -E0211: include_str!("./error_codes/E0211.md"), -E0212: include_str!("./error_codes/E0212.md"), -E0214: include_str!("./error_codes/E0214.md"), -E0220: include_str!("./error_codes/E0220.md"), -E0221: include_str!("./error_codes/E0221.md"), -E0222: include_str!("./error_codes/E0222.md"), -E0223: include_str!("./error_codes/E0223.md"), -E0224: include_str!("./error_codes/E0224.md"), -E0225: include_str!("./error_codes/E0225.md"), -E0226: include_str!("./error_codes/E0226.md"), -E0227: include_str!("./error_codes/E0227.md"), -E0228: include_str!("./error_codes/E0228.md"), -E0229: include_str!("./error_codes/E0229.md"), -E0230: include_str!("./error_codes/E0230.md"), -E0231: include_str!("./error_codes/E0231.md"), -E0232: include_str!("./error_codes/E0232.md"), -E0243: include_str!("./error_codes/E0243.md"), -E0244: include_str!("./error_codes/E0244.md"), -E0251: include_str!("./error_codes/E0251.md"), -E0252: include_str!("./error_codes/E0252.md"), -E0253: include_str!("./error_codes/E0253.md"), -E0254: include_str!("./error_codes/E0254.md"), -E0255: include_str!("./error_codes/E0255.md"), -E0256: include_str!("./error_codes/E0256.md"), -E0259: include_str!("./error_codes/E0259.md"), -E0260: include_str!("./error_codes/E0260.md"), -E0261: include_str!("./error_codes/E0261.md"), -E0262: include_str!("./error_codes/E0262.md"), -E0263: include_str!("./error_codes/E0263.md"), -E0264: include_str!("./error_codes/E0264.md"), -E0267: include_str!("./error_codes/E0267.md"), -E0268: include_str!("./error_codes/E0268.md"), -E0271: include_str!("./error_codes/E0271.md"), -E0275: include_str!("./error_codes/E0275.md"), -E0276: include_str!("./error_codes/E0276.md"), -E0277: include_str!("./error_codes/E0277.md"), -E0281: include_str!("./error_codes/E0281.md"), -E0282: include_str!("./error_codes/E0282.md"), -E0283: include_str!("./error_codes/E0283.md"), -E0284: include_str!("./error_codes/E0284.md"), -E0297: include_str!("./error_codes/E0297.md"), -E0301: include_str!("./error_codes/E0301.md"), -E0302: include_str!("./error_codes/E0302.md"), -E0303: include_str!("./error_codes/E0303.md"), -E0307: include_str!("./error_codes/E0307.md"), -E0308: include_str!("./error_codes/E0308.md"), -E0309: include_str!("./error_codes/E0309.md"), -E0310: include_str!("./error_codes/E0310.md"), -E0311: include_str!("./error_codes/E0311.md"), -E0312: include_str!("./error_codes/E0312.md"), -E0316: include_str!("./error_codes/E0316.md"), -E0317: include_str!("./error_codes/E0317.md"), -E0320: include_str!("./error_codes/E0320.md"), -E0321: include_str!("./error_codes/E0321.md"), -E0322: include_str!("./error_codes/E0322.md"), -E0323: include_str!("./error_codes/E0323.md"), -E0324: include_str!("./error_codes/E0324.md"), -E0325: include_str!("./error_codes/E0325.md"), -E0326: include_str!("./error_codes/E0326.md"), -E0328: include_str!("./error_codes/E0328.md"), -E0329: include_str!("./error_codes/E0329.md"), -E0364: include_str!("./error_codes/E0364.md"), -E0365: include_str!("./error_codes/E0365.md"), -E0366: include_str!("./error_codes/E0366.md"), -E0367: include_str!("./error_codes/E0367.md"), -E0368: include_str!("./error_codes/E0368.md"), -E0369: include_str!("./error_codes/E0369.md"), -E0370: include_str!("./error_codes/E0370.md"), -E0371: include_str!("./error_codes/E0371.md"), -E0373: include_str!("./error_codes/E0373.md"), -E0374: include_str!("./error_codes/E0374.md"), -E0375: include_str!("./error_codes/E0375.md"), -E0376: include_str!("./error_codes/E0376.md"), -E0377: include_str!("./error_codes/E0377.md"), -E0378: include_str!("./error_codes/E0378.md"), -E0379: include_str!("./error_codes/E0379.md"), -E0380: include_str!("./error_codes/E0380.md"), -E0381: include_str!("./error_codes/E0381.md"), -E0382: include_str!("./error_codes/E0382.md"), -E0383: include_str!("./error_codes/E0383.md"), -E0384: include_str!("./error_codes/E0384.md"), -E0386: include_str!("./error_codes/E0386.md"), -E0387: include_str!("./error_codes/E0387.md"), -E0388: include_str!("./error_codes/E0388.md"), -E0389: include_str!("./error_codes/E0389.md"), -E0390: include_str!("./error_codes/E0390.md"), -E0391: include_str!("./error_codes/E0391.md"), -E0392: include_str!("./error_codes/E0392.md"), -E0393: include_str!("./error_codes/E0393.md"), -E0398: include_str!("./error_codes/E0398.md"), -E0399: include_str!("./error_codes/E0399.md"), -E0401: include_str!("./error_codes/E0401.md"), -E0403: include_str!("./error_codes/E0403.md"), -E0404: include_str!("./error_codes/E0404.md"), -E0405: include_str!("./error_codes/E0405.md"), -E0407: include_str!("./error_codes/E0407.md"), -E0408: include_str!("./error_codes/E0408.md"), -E0409: include_str!("./error_codes/E0409.md"), -E0411: include_str!("./error_codes/E0411.md"), -E0412: include_str!("./error_codes/E0412.md"), -E0415: include_str!("./error_codes/E0415.md"), -E0416: include_str!("./error_codes/E0416.md"), -E0422: include_str!("./error_codes/E0422.md"), -E0423: include_str!("./error_codes/E0423.md"), -E0424: include_str!("./error_codes/E0424.md"), -E0425: include_str!("./error_codes/E0425.md"), -E0426: include_str!("./error_codes/E0426.md"), -E0428: include_str!("./error_codes/E0428.md"), -E0429: include_str!("./error_codes/E0429.md"), -E0430: include_str!("./error_codes/E0430.md"), -E0431: include_str!("./error_codes/E0431.md"), -E0432: include_str!("./error_codes/E0432.md"), -E0433: include_str!("./error_codes/E0433.md"), -E0434: include_str!("./error_codes/E0434.md"), -E0435: include_str!("./error_codes/E0435.md"), -E0436: include_str!("./error_codes/E0436.md"), -E0437: include_str!("./error_codes/E0437.md"), -E0438: include_str!("./error_codes/E0438.md"), -E0439: include_str!("./error_codes/E0439.md"), -E0445: include_str!("./error_codes/E0445.md"), -E0446: include_str!("./error_codes/E0446.md"), -E0447: include_str!("./error_codes/E0447.md"), -E0448: include_str!("./error_codes/E0448.md"), -E0449: include_str!("./error_codes/E0449.md"), -E0451: include_str!("./error_codes/E0451.md"), -E0452: include_str!("./error_codes/E0452.md"), -E0453: include_str!("./error_codes/E0453.md"), -E0454: include_str!("./error_codes/E0454.md"), -E0455: include_str!("./error_codes/E0455.md"), -E0457: include_str!("./error_codes/E0457.md"), -E0458: include_str!("./error_codes/E0458.md"), -E0459: include_str!("./error_codes/E0459.md"), -E0460: include_str!("./error_codes/E0460.md"), -E0461: include_str!("./error_codes/E0461.md"), -E0462: include_str!("./error_codes/E0462.md"), -E0463: include_str!("./error_codes/E0463.md"), -E0464: include_str!("./error_codes/E0464.md"), -E0466: include_str!("./error_codes/E0466.md"), -E0468: include_str!("./error_codes/E0468.md"), -E0469: include_str!("./error_codes/E0469.md"), -E0472: include_str!("./error_codes/E0472.md"), -E0476: include_str!("./error_codes/E0476.md"), -E0477: include_str!("./error_codes/E0477.md"), -E0478: include_str!("./error_codes/E0478.md"), -E0482: include_str!("./error_codes/E0482.md"), -E0491: include_str!("./error_codes/E0491.md"), -E0492: include_str!("./error_codes/E0492.md"), -E0493: include_str!("./error_codes/E0493.md"), -E0495: include_str!("./error_codes/E0495.md"), -E0496: include_str!("./error_codes/E0496.md"), -E0497: include_str!("./error_codes/E0497.md"), -E0498: include_str!("./error_codes/E0498.md"), -E0499: include_str!("./error_codes/E0499.md"), -E0500: include_str!("./error_codes/E0500.md"), -E0501: include_str!("./error_codes/E0501.md"), -E0502: include_str!("./error_codes/E0502.md"), -E0503: include_str!("./error_codes/E0503.md"), -E0504: include_str!("./error_codes/E0504.md"), -E0505: include_str!("./error_codes/E0505.md"), -E0506: include_str!("./error_codes/E0506.md"), -E0507: include_str!("./error_codes/E0507.md"), -E0508: include_str!("./error_codes/E0508.md"), -E0509: include_str!("./error_codes/E0509.md"), -E0510: include_str!("./error_codes/E0510.md"), -E0511: include_str!("./error_codes/E0511.md"), -E0512: include_str!("./error_codes/E0512.md"), -E0514: include_str!("./error_codes/E0514.md"), -E0515: include_str!("./error_codes/E0515.md"), -E0516: include_str!("./error_codes/E0516.md"), -E0517: include_str!("./error_codes/E0517.md"), -E0518: include_str!("./error_codes/E0518.md"), -E0519: include_str!("./error_codes/E0519.md"), -E0520: include_str!("./error_codes/E0520.md"), -E0521: include_str!("./error_codes/E0521.md"), -E0522: include_str!("./error_codes/E0522.md"), -E0523: include_str!("./error_codes/E0523.md"), -E0524: include_str!("./error_codes/E0524.md"), -E0525: include_str!("./error_codes/E0525.md"), -E0527: include_str!("./error_codes/E0527.md"), -E0528: include_str!("./error_codes/E0528.md"), -E0529: include_str!("./error_codes/E0529.md"), -E0530: include_str!("./error_codes/E0530.md"), -E0531: include_str!("./error_codes/E0531.md"), -E0532: include_str!("./error_codes/E0532.md"), -E0533: include_str!("./error_codes/E0533.md"), -E0534: include_str!("./error_codes/E0534.md"), -E0535: include_str!("./error_codes/E0535.md"), -E0536: include_str!("./error_codes/E0536.md"), -E0537: include_str!("./error_codes/E0537.md"), -E0538: include_str!("./error_codes/E0538.md"), -E0539: include_str!("./error_codes/E0539.md"), -E0541: include_str!("./error_codes/E0541.md"), -E0542: include_str!("./error_codes/E0542.md"), -E0543: include_str!("./error_codes/E0543.md"), -E0544: include_str!("./error_codes/E0544.md"), -E0545: include_str!("./error_codes/E0545.md"), -E0546: include_str!("./error_codes/E0546.md"), -E0547: include_str!("./error_codes/E0547.md"), -E0549: include_str!("./error_codes/E0549.md"), -E0550: include_str!("./error_codes/E0550.md"), -E0551: include_str!("./error_codes/E0551.md"), -E0552: include_str!("./error_codes/E0552.md"), -E0554: include_str!("./error_codes/E0554.md"), -E0556: include_str!("./error_codes/E0556.md"), -E0557: include_str!("./error_codes/E0557.md"), -E0559: include_str!("./error_codes/E0559.md"), -E0560: include_str!("./error_codes/E0560.md"), -E0561: include_str!("./error_codes/E0561.md"), -E0562: include_str!("./error_codes/E0562.md"), -E0565: include_str!("./error_codes/E0565.md"), -E0566: include_str!("./error_codes/E0566.md"), -E0567: include_str!("./error_codes/E0567.md"), -E0568: include_str!("./error_codes/E0568.md"), -E0569: include_str!("./error_codes/E0569.md"), -E0570: include_str!("./error_codes/E0570.md"), -E0571: include_str!("./error_codes/E0571.md"), -E0572: include_str!("./error_codes/E0572.md"), -E0573: include_str!("./error_codes/E0573.md"), -E0574: include_str!("./error_codes/E0574.md"), -E0575: include_str!("./error_codes/E0575.md"), -E0576: include_str!("./error_codes/E0576.md"), -E0577: include_str!("./error_codes/E0577.md"), -E0578: include_str!("./error_codes/E0578.md"), -E0579: include_str!("./error_codes/E0579.md"), -E0580: include_str!("./error_codes/E0580.md"), -E0581: include_str!("./error_codes/E0581.md"), -E0582: include_str!("./error_codes/E0582.md"), -E0583: include_str!("./error_codes/E0583.md"), -E0584: include_str!("./error_codes/E0584.md"), -E0585: include_str!("./error_codes/E0585.md"), -E0586: include_str!("./error_codes/E0586.md"), -E0587: include_str!("./error_codes/E0587.md"), -E0588: include_str!("./error_codes/E0588.md"), -E0589: include_str!("./error_codes/E0589.md"), -E0590: include_str!("./error_codes/E0590.md"), -E0591: include_str!("./error_codes/E0591.md"), -E0592: include_str!("./error_codes/E0592.md"), -E0593: include_str!("./error_codes/E0593.md"), -E0594: include_str!("./error_codes/E0594.md"), -E0595: include_str!("./error_codes/E0595.md"), -E0596: include_str!("./error_codes/E0596.md"), -E0597: include_str!("./error_codes/E0597.md"), -E0599: include_str!("./error_codes/E0599.md"), -E0600: include_str!("./error_codes/E0600.md"), -E0601: include_str!("./error_codes/E0601.md"), -E0602: include_str!("./error_codes/E0602.md"), -E0603: include_str!("./error_codes/E0603.md"), -E0604: include_str!("./error_codes/E0604.md"), -E0605: include_str!("./error_codes/E0605.md"), -E0606: include_str!("./error_codes/E0606.md"), -E0607: include_str!("./error_codes/E0607.md"), -E0608: include_str!("./error_codes/E0608.md"), -E0609: include_str!("./error_codes/E0609.md"), -E0610: include_str!("./error_codes/E0610.md"), -E0614: include_str!("./error_codes/E0614.md"), -E0615: include_str!("./error_codes/E0615.md"), -E0616: include_str!("./error_codes/E0616.md"), -E0617: include_str!("./error_codes/E0617.md"), -E0618: include_str!("./error_codes/E0618.md"), -E0619: include_str!("./error_codes/E0619.md"), -E0620: include_str!("./error_codes/E0620.md"), -E0621: include_str!("./error_codes/E0621.md"), -E0622: include_str!("./error_codes/E0622.md"), -E0623: include_str!("./error_codes/E0623.md"), -E0624: include_str!("./error_codes/E0624.md"), -E0625: include_str!("./error_codes/E0625.md"), -E0626: include_str!("./error_codes/E0626.md"), -E0627: include_str!("./error_codes/E0627.md"), -E0628: include_str!("./error_codes/E0628.md"), -E0631: include_str!("./error_codes/E0631.md"), -E0632: include_str!("./error_codes/E0632.md"), -E0633: include_str!("./error_codes/E0633.md"), -E0634: include_str!("./error_codes/E0634.md"), -E0635: include_str!("./error_codes/E0635.md"), -E0636: include_str!("./error_codes/E0636.md"), -E0637: include_str!("./error_codes/E0637.md"), -E0638: include_str!("./error_codes/E0638.md"), -E0639: include_str!("./error_codes/E0639.md"), -E0640: include_str!("./error_codes/E0640.md"), -E0641: include_str!("./error_codes/E0641.md"), -E0642: include_str!("./error_codes/E0642.md"), -E0643: include_str!("./error_codes/E0643.md"), -E0644: include_str!("./error_codes/E0644.md"), -E0646: include_str!("./error_codes/E0646.md"), -E0647: include_str!("./error_codes/E0647.md"), -E0648: include_str!("./error_codes/E0648.md"), -E0657: include_str!("./error_codes/E0657.md"), -E0658: include_str!("./error_codes/E0658.md"), -E0659: include_str!("./error_codes/E0659.md"), -E0660: include_str!("./error_codes/E0660.md"), -E0661: include_str!("./error_codes/E0661.md"), -E0662: include_str!("./error_codes/E0662.md"), -E0663: include_str!("./error_codes/E0663.md"), -E0664: include_str!("./error_codes/E0664.md"), -E0665: include_str!("./error_codes/E0665.md"), -E0666: include_str!("./error_codes/E0666.md"), -E0667: include_str!("./error_codes/E0667.md"), -E0668: include_str!("./error_codes/E0668.md"), -E0669: include_str!("./error_codes/E0669.md"), -E0670: include_str!("./error_codes/E0670.md"), -E0671: include_str!("./error_codes/E0671.md"), -E0687: include_str!("./error_codes/E0687.md"), -E0688: include_str!("./error_codes/E0688.md"), -E0689: include_str!("./error_codes/E0689.md"), -E0690: include_str!("./error_codes/E0690.md"), -E0691: include_str!("./error_codes/E0691.md"), -E0692: include_str!("./error_codes/E0692.md"), -E0693: include_str!("./error_codes/E0693.md"), -E0695: include_str!("./error_codes/E0695.md"), -E0696: include_str!("./error_codes/E0696.md"), -E0697: include_str!("./error_codes/E0697.md"), -E0698: include_str!("./error_codes/E0698.md"), -E0699: include_str!("./error_codes/E0699.md"), -E0700: include_str!("./error_codes/E0700.md"), -E0701: include_str!("./error_codes/E0701.md"), -E0703: include_str!("./error_codes/E0703.md"), -E0704: include_str!("./error_codes/E0704.md"), -E0705: include_str!("./error_codes/E0705.md"), -E0706: include_str!("./error_codes/E0706.md"), -E0708: include_str!("./error_codes/E0708.md"), -E0710: include_str!("./error_codes/E0710.md"), -E0712: include_str!("./error_codes/E0712.md"), -E0713: include_str!("./error_codes/E0713.md"), -E0714: include_str!("./error_codes/E0714.md"), -E0715: include_str!("./error_codes/E0715.md"), -E0716: include_str!("./error_codes/E0716.md"), -E0711: include_str!("./error_codes/E0711.md"), -E0717: include_str!("./error_codes/E0717.md"), -E0718: include_str!("./error_codes/E0718.md"), -E0719: include_str!("./error_codes/E0719.md"), -E0720: include_str!("./error_codes/E0720.md"), -E0722: include_str!("./error_codes/E0722.md"), -E0724: include_str!("./error_codes/E0724.md"), -E0725: include_str!("./error_codes/E0725.md"), -E0726: include_str!("./error_codes/E0726.md"), -E0727: include_str!("./error_codes/E0727.md"), -E0728: include_str!("./error_codes/E0728.md"), -E0729: include_str!("./error_codes/E0729.md"), -E0730: include_str!("./error_codes/E0730.md"), -E0731: include_str!("./error_codes/E0731.md"), -E0732: include_str!("./error_codes/E0732.md"), -E0733: include_str!("./error_codes/E0733.md"), -E0734: include_str!("./error_codes/E0734.md"), -E0735: include_str!("./error_codes/E0735.md"), -E0736: include_str!("./error_codes/E0736.md"), -E0737: include_str!("./error_codes/E0737.md"), -E0739: include_str!("./error_codes/E0739.md"), -E0740: include_str!("./error_codes/E0740.md"), -E0741: include_str!("./error_codes/E0741.md"), -E0742: include_str!("./error_codes/E0742.md"), -E0743: include_str!("./error_codes/E0743.md"), -E0744: include_str!("./error_codes/E0744.md"), -E0745: include_str!("./error_codes/E0745.md"), -E0746: include_str!("./error_codes/E0746.md"), -E0747: include_str!("./error_codes/E0747.md"), -E0748: include_str!("./error_codes/E0748.md"), -E0749: include_str!("./error_codes/E0749.md"), -E0750: include_str!("./error_codes/E0750.md"), -E0751: include_str!("./error_codes/E0751.md"), -E0752: include_str!("./error_codes/E0752.md"), -E0753: include_str!("./error_codes/E0753.md"), -E0754: include_str!("./error_codes/E0754.md"), -E0755: include_str!("./error_codes/E0755.md"), -E0756: include_str!("./error_codes/E0756.md"), -E0757: include_str!("./error_codes/E0757.md"), -E0758: include_str!("./error_codes/E0758.md"), -E0759: include_str!("./error_codes/E0759.md"), -E0760: include_str!("./error_codes/E0760.md"), -E0761: include_str!("./error_codes/E0761.md"), -E0762: include_str!("./error_codes/E0762.md"), -E0763: include_str!("./error_codes/E0763.md"), -E0764: include_str!("./error_codes/E0764.md"), -E0765: include_str!("./error_codes/E0765.md"), -E0766: include_str!("./error_codes/E0766.md"), -E0767: include_str!("./error_codes/E0767.md"), -E0768: include_str!("./error_codes/E0768.md"), -E0769: include_str!("./error_codes/E0769.md"), -E0770: include_str!("./error_codes/E0770.md"), -E0771: include_str!("./error_codes/E0771.md"), -E0772: include_str!("./error_codes/E0772.md"), -E0773: include_str!("./error_codes/E0773.md"), -E0774: include_str!("./error_codes/E0774.md"), -E0775: include_str!("./error_codes/E0775.md"), -E0776: include_str!("./error_codes/E0776.md"), -E0777: include_str!("./error_codes/E0777.md"), -E0778: include_str!("./error_codes/E0778.md"), -E0779: include_str!("./error_codes/E0779.md"), -E0780: include_str!("./error_codes/E0780.md"), -E0781: include_str!("./error_codes/E0781.md"), -E0782: include_str!("./error_codes/E0782.md"), -E0783: include_str!("./error_codes/E0783.md"), -E0784: include_str!("./error_codes/E0784.md"), -E0785: include_str!("./error_codes/E0785.md"), -E0786: include_str!("./error_codes/E0786.md"), -E0787: include_str!("./error_codes/E0787.md"), -E0788: include_str!("./error_codes/E0788.md"), -E0789: include_str!("./error_codes/E0789.md"), -E0790: include_str!("./error_codes/E0790.md"), -E0791: include_str!("./error_codes/E0791.md"), -E0792: include_str!("./error_codes/E0792.md"), -E0793: include_str!("./error_codes/E0793.md"), -E0794: include_str!("./error_codes/E0794.md"), -E0795: include_str!("./error_codes/E0795.md"), -E0796: include_str!("./error_codes/E0796.md"), -E0797: include_str!("./error_codes/E0797.md"), -} - -// Undocumented removed error codes. Note that many removed error codes are kept in the list above -// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example). -// E0006, // merged with E0005 -// E0008, // cannot bind by-move into a pattern guard -// E0019, // merged into E0015 -// E0035, // merged into E0087/E0089 -// E0036, // merged into E0087/E0089 -// E0068, -// E0085, -// E0086, -// E0101, // replaced with E0282 -// E0102, // replaced with E0282 -// E0103, -// E0104, -// E0122, // bounds in type aliases are ignored, turned into proper lint -// E0123, -// E0127, -// E0129, -// E0134, -// E0135, -// E0141, -// E0153, // unused error code -// E0157, // unused error code -// E0159, // use of trait `{}` as struct constructor -// E0163, // merged into E0071 -// E0167, -// E0168, -// E0172, // non-trait found in a type sum, moved to resolve -// E0173, // manual implementations of unboxed closure traits are experimental -// E0174, -// E0182, // merged into E0229 -// E0187, // cannot infer the kind of the closure -// E0188, // can not cast an immutable reference to a mutable pointer -// E0189, // deprecated: can only cast a boxed pointer to a boxed object -// E0190, // deprecated: can only cast a &-pointer to an &-object -// E0194, // merged into E0403 -// E0196, // cannot determine a type for this closure -// E0209, // builtin traits can only be implemented on structs or enums -// E0213, // associated types are not accepted in this context -// E0215, // angle-bracket notation is not stable with `Fn` -// E0216, // parenthetical notation is only stable with `Fn` -// E0217, // ambiguous associated type, defined in multiple supertraits -// E0218, // no associated type defined -// E0219, // associated type defined in higher-ranked supertrait -// E0233, -// E0234, -// E0235, // structure constructor specifies a structure of type but -// E0236, // no lang item for range syntax -// E0237, // no lang item for range syntax -// E0238, // parenthesized parameters may only be used with a trait -// E0239, // `next` method of `Iterator` trait has unexpected type -// E0240, -// E0241, -// E0242, -// E0245, // not a trait -// E0246, // invalid recursive type -// E0247, -// E0248, // value used as a type, now reported earlier during resolution -// // as E0412 -// E0249, -// E0257, -// E0258, -// E0272, // on_unimplemented #0 -// E0273, // on_unimplemented #1 -// E0274, // on_unimplemented #2 -// E0278, // requirement is not satisfied -// E0279, -// E0280, // changed to ICE -// E0285, // overflow evaluation builtin bounds -// E0296, // replaced with a generic attribute input check -// E0298, // cannot compare constants -// E0299, // mismatched types between arms -// E0300, // unexpanded macro -// E0304, // expected signed integer constant -// E0305, // expected constant -// E0313, // removed: found unreachable -// E0314, // closure outlives stack frame -// E0315, // cannot invoke closure outside of its lifetime -// E0319, // trait impls for defaulted traits allowed just for structs/enums -// E0372, // coherence not object safe -// E0385, // {} in an aliasable location -// E0402, // cannot use an outer type parameter in this context -// E0406, // merged into 420 -// E0410, // merged into 408 -// E0413, // merged into 530 -// E0414, // merged into 530 -// E0417, // merged into 532 -// E0418, // merged into 532 -// E0419, // merged into 531 -// E0420, // merged into 532 -// E0421, // merged into 531 -// E0427, // merged into 530 -// E0445, // merged into 446 and type privacy lints -// E0456, // plugin `..` is not available for triple `..` -// E0465, // removed: merged with E0464 -// E0467, // removed -// E0470, // removed -// E0471, // constant evaluation error (in pattern) -// E0473, // dereference of reference outside its lifetime -// E0474, // captured variable `..` does not outlive the enclosing closure -// E0475, // index of slice outside its lifetime -// E0479, // the type `..` (provided as the value of a type parameter) is... -// E0480, // lifetime of method receiver does not outlive the method call -// E0481, // lifetime of function argument does not outlive the function call -// E0483, // lifetime of operand does not outlive the operation -// E0484, // reference is not valid at the time of borrow -// E0485, // automatically reference is not valid at the time of borrow -// E0486, // type of expression contains references that are not valid during.. -// E0487, // unsafe use of destructor: destructor might be called while... -// E0488, // lifetime of variable does not enclose its declaration -// E0489, // type/lifetime parameter not in scope here -// E0490, // removed: unreachable -// E0526, // shuffle indices are not constant -// E0540, // multiple rustc_deprecated attributes -// E0548, // replaced with a generic attribute input check -// E0553, // multiple rustc_const_unstable attributes -// E0555, // replaced with a generic attribute input check -// E0558, // replaced with a generic attribute input check -// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 -// E0564, // only named lifetimes are allowed in `impl Trait`, -// // but `{}` was found in the type `{}` -// E0598, // lifetime of {} is too short to guarantee its contents can be... -// E0611, // merged into E0616 -// E0612, // merged into E0609 -// E0613, // Removed (merged with E0609) -// E0629, // missing 'feature' (rustc_const_unstable) -// E0630, // rustc_const_unstable attribute must be paired with stable/unstable -// // attribute -// E0645, // trait aliases not finished -// E0694, // an unknown tool name found in scoped attributes -// E0702, // replaced with a generic attribute input check -// E0707, // multiple elided lifetimes used in arguments of `async fn` -// E0709, // multiple different lifetimes used in arguments of `async fn` -// E0721, // `await` keyword -// E0723, // unstable feature in `const` context -// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. -// E0744, // merged into E0728 diff --git a/compiler/rustc_error_codes/src/error_codes/E0091.md b/compiler/rustc_error_codes/src/error_codes/E0091.md index 03cb32803715e..3bf4e907ecb1f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0091.md +++ b/compiler/rustc_error_codes/src/error_codes/E0091.md @@ -1,11 +1,11 @@ -An unnecessary type or const parameter was given in a type alias. +An unnecessary type parameter was given in a type alias. Erroneous code example: ```compile_fail,E0091 -type Foo = u32; // error: type parameter `T` is unused +type Foo = u32; // error: type parameter `T` is never used // or: -type Foo = Box; // error: type parameter `B` is unused +type Foo = Box; // error: type parameter `B` is never used ``` Please check you didn't write too many parameters. Example: diff --git a/compiler/rustc_error_codes/src/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md index d790607622992..33ddf3405acca 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0264.md +++ b/compiler/rustc_error_codes/src/error_codes/E0264.md @@ -13,7 +13,7 @@ extern "C" { ``` A list of available external lang items is available in -`src/librustc_middle/middle/weak_lang_items.rs`. Example: +`compiler/rustc_hir/src/weak_lang_items.rs`. Example: ``` #![feature(lang_items)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md index 70578acbe0d5f..bcefd0a74798b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0724.md +++ b/compiler/rustc_error_codes/src/error_codes/E0724.md @@ -1,9 +1,12 @@ +#### Note: this error code is no longer emitted by the compiler. + + `#[ffi_returns_twice]` was used on something other than a foreign function declaration. Erroneous code example: -```compile_fail,E0724 +```compile_fail #![feature(ffi_returns_twice)] #![crate_type = "lib"] @@ -15,7 +18,7 @@ pub fn foo() {} For example, we might correct the previous example by declaring the function inside of an `extern` block. -``` +```compile_fail #![feature(ffi_returns_twice)] extern "C" { diff --git a/compiler/rustc_error_codes/src/error_codes/E0795.md b/compiler/rustc_error_codes/src/error_codes/E0795.md index 20f51441c2911..ad77d72c913a8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0795.md +++ b/compiler/rustc_error_codes/src/error_codes/E0795.md @@ -3,7 +3,7 @@ Invalid argument for the `offset_of!` macro. Erroneous code example: ```compile_fail,E0795 -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] let x = std::mem::offset_of!(Option, Some); ``` @@ -16,7 +16,7 @@ The offset of the contained `u8` in the `Option` can be found by specifying the field name `0`: ``` -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] let x: usize = std::mem::offset_of!(Option, Some.0); ``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index dd2818116368b..5b2766618fccb 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,19 +1,679 @@ +//! This library is used to gather all error codes into one place, to make +//! their maintenance easier. + #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] #![deny(rustdoc::invalid_codeblock_attributes)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -//! This library is used to gather all error codes into one place, -//! the goal being to make their maintenance easier. -macro_rules! register_diagnostics { - ($($ecode:ident: $message:expr,)*) => ( - pub static DIAGNOSTICS: &[(&str, &str)] = &[ - $( (stringify!($ecode), $message), )* - ]; +// This higher-order macro defines the error codes that are in use. It is used +// in the `rustc_errors` crate. Removed error codes are listed in the comment +// below. +// +// /!\ IMPORTANT /!\ +// +// Error code explanation are defined in `error_codes/EXXXX.md` files. They must follow the RFC +// 1567 available here: +// https://rust-lang.github.io/rfcs/1567-long-error-codes-explanation-normalization.html +// +// Also, the contents of this macro is checked by tidy (in `check_error_codes_docs`). If you change +// the macro syntax you will need to change tidy as well. +// +// Both columns are necessary because it's not possible in Rust to create a new identifier such as +// `E0123` from an integer literal such as `0123`, unfortunately. +#[macro_export] +macro_rules! error_codes { + ($macro:path) => ( + $macro!( +E0001: 0001, +E0002: 0002, +E0004: 0004, +E0005: 0005, +E0007: 0007, +E0009: 0009, +E0010: 0010, +E0013: 0013, +E0014: 0014, +E0015: 0015, +E0023: 0023, +E0025: 0025, +E0026: 0026, +E0027: 0027, +E0029: 0029, +E0030: 0030, +E0033: 0033, +E0034: 0034, +E0038: 0038, +E0040: 0040, +E0044: 0044, +E0045: 0045, +E0046: 0046, +E0049: 0049, +E0050: 0050, +E0053: 0053, +E0054: 0054, +E0055: 0055, +E0057: 0057, +E0059: 0059, +E0060: 0060, +E0061: 0061, +E0062: 0062, +E0063: 0063, +E0067: 0067, +E0069: 0069, +E0070: 0070, +E0071: 0071, +E0072: 0072, +E0073: 0073, +E0074: 0074, +E0075: 0075, +E0076: 0076, +E0077: 0077, +E0080: 0080, +E0081: 0081, +E0084: 0084, +E0087: 0087, +E0088: 0088, +E0089: 0089, +E0090: 0090, +E0091: 0091, +E0092: 0092, +E0093: 0093, +E0094: 0094, +E0106: 0106, +E0107: 0107, +E0109: 0109, +E0110: 0110, +E0116: 0116, +E0117: 0117, +E0118: 0118, +E0119: 0119, +E0120: 0120, +E0121: 0121, +E0124: 0124, +E0128: 0128, +E0130: 0130, +E0131: 0131, +E0132: 0132, +E0133: 0133, +E0136: 0136, +E0137: 0137, +E0138: 0138, +E0139: 0139, +E0152: 0152, +E0154: 0154, +E0158: 0158, +E0161: 0161, +E0162: 0162, +E0164: 0164, +E0165: 0165, +E0170: 0170, +E0178: 0178, +E0183: 0183, +E0184: 0184, +E0185: 0185, +E0186: 0186, +E0191: 0191, +E0192: 0192, +E0193: 0193, +E0195: 0195, +E0197: 0197, +E0198: 0198, +E0199: 0199, +E0200: 0200, +E0201: 0201, +E0203: 0203, +E0204: 0204, +E0205: 0205, +E0206: 0206, +E0207: 0207, +E0208: 0208, +E0210: 0210, +E0211: 0211, +E0212: 0212, +E0214: 0214, +E0220: 0220, +E0221: 0221, +E0222: 0222, +E0223: 0223, +E0224: 0224, +E0225: 0225, +E0226: 0226, +E0227: 0227, +E0228: 0228, +E0229: 0229, +E0230: 0230, +E0231: 0231, +E0232: 0232, +E0243: 0243, +E0244: 0244, +E0251: 0251, +E0252: 0252, +E0253: 0253, +E0254: 0254, +E0255: 0255, +E0256: 0256, +E0259: 0259, +E0260: 0260, +E0261: 0261, +E0262: 0262, +E0263: 0263, +E0264: 0264, +E0267: 0267, +E0268: 0268, +E0271: 0271, +E0275: 0275, +E0276: 0276, +E0277: 0277, +E0281: 0281, +E0282: 0282, +E0283: 0283, +E0284: 0284, +E0297: 0297, +E0301: 0301, +E0302: 0302, +E0303: 0303, +E0307: 0307, +E0308: 0308, +E0309: 0309, +E0310: 0310, +E0311: 0311, +E0312: 0312, +E0316: 0316, +E0317: 0317, +E0320: 0320, +E0321: 0321, +E0322: 0322, +E0323: 0323, +E0324: 0324, +E0325: 0325, +E0326: 0326, +E0328: 0328, +E0329: 0329, +E0364: 0364, +E0365: 0365, +E0366: 0366, +E0367: 0367, +E0368: 0368, +E0369: 0369, +E0370: 0370, +E0371: 0371, +E0373: 0373, +E0374: 0374, +E0375: 0375, +E0376: 0376, +E0377: 0377, +E0378: 0378, +E0379: 0379, +E0380: 0380, +E0381: 0381, +E0382: 0382, +E0383: 0383, +E0384: 0384, +E0386: 0386, +E0387: 0387, +E0388: 0388, +E0389: 0389, +E0390: 0390, +E0391: 0391, +E0392: 0392, +E0393: 0393, +E0398: 0398, +E0399: 0399, +E0401: 0401, +E0403: 0403, +E0404: 0404, +E0405: 0405, +E0407: 0407, +E0408: 0408, +E0409: 0409, +E0411: 0411, +E0412: 0412, +E0415: 0415, +E0416: 0416, +E0422: 0422, +E0423: 0423, +E0424: 0424, +E0425: 0425, +E0426: 0426, +E0428: 0428, +E0429: 0429, +E0430: 0430, +E0431: 0431, +E0432: 0432, +E0433: 0433, +E0434: 0434, +E0435: 0435, +E0436: 0436, +E0437: 0437, +E0438: 0438, +E0439: 0439, +E0445: 0445, +E0446: 0446, +E0447: 0447, +E0448: 0448, +E0449: 0449, +E0451: 0451, +E0452: 0452, +E0453: 0453, +E0454: 0454, +E0455: 0455, +E0457: 0457, +E0458: 0458, +E0459: 0459, +E0460: 0460, +E0461: 0461, +E0462: 0462, +E0463: 0463, +E0464: 0464, +E0466: 0466, +E0468: 0468, +E0469: 0469, +E0472: 0472, +E0476: 0476, +E0477: 0477, +E0478: 0478, +E0482: 0482, +E0491: 0491, +E0492: 0492, +E0493: 0493, +E0495: 0495, +E0496: 0496, +E0497: 0497, +E0498: 0498, +E0499: 0499, +E0500: 0500, +E0501: 0501, +E0502: 0502, +E0503: 0503, +E0504: 0504, +E0505: 0505, +E0506: 0506, +E0507: 0507, +E0508: 0508, +E0509: 0509, +E0510: 0510, +E0511: 0511, +E0512: 0512, +E0514: 0514, +E0515: 0515, +E0516: 0516, +E0517: 0517, +E0518: 0518, +E0519: 0519, +E0520: 0520, +E0521: 0521, +E0522: 0522, +E0523: 0523, +E0524: 0524, +E0525: 0525, +E0527: 0527, +E0528: 0528, +E0529: 0529, +E0530: 0530, +E0531: 0531, +E0532: 0532, +E0533: 0533, +E0534: 0534, +E0535: 0535, +E0536: 0536, +E0537: 0537, +E0538: 0538, +E0539: 0539, +E0541: 0541, +E0542: 0542, +E0543: 0543, +E0544: 0544, +E0545: 0545, +E0546: 0546, +E0547: 0547, +E0549: 0549, +E0550: 0550, +E0551: 0551, +E0552: 0552, +E0554: 0554, +E0556: 0556, +E0557: 0557, +E0559: 0559, +E0560: 0560, +E0561: 0561, +E0562: 0562, +E0565: 0565, +E0566: 0566, +E0567: 0567, +E0568: 0568, +E0569: 0569, +E0570: 0570, +E0571: 0571, +E0572: 0572, +E0573: 0573, +E0574: 0574, +E0575: 0575, +E0576: 0576, +E0577: 0577, +E0578: 0578, +E0579: 0579, +E0580: 0580, +E0581: 0581, +E0582: 0582, +E0583: 0583, +E0584: 0584, +E0585: 0585, +E0586: 0586, +E0587: 0587, +E0588: 0588, +E0589: 0589, +E0590: 0590, +E0591: 0591, +E0592: 0592, +E0593: 0593, +E0594: 0594, +E0595: 0595, +E0596: 0596, +E0597: 0597, +E0599: 0599, +E0600: 0600, +E0601: 0601, +E0602: 0602, +E0603: 0603, +E0604: 0604, +E0605: 0605, +E0606: 0606, +E0607: 0607, +E0608: 0608, +E0609: 0609, +E0610: 0610, +E0614: 0614, +E0615: 0615, +E0616: 0616, +E0617: 0617, +E0618: 0618, +E0619: 0619, +E0620: 0620, +E0621: 0621, +E0622: 0622, +E0623: 0623, +E0624: 0624, +E0625: 0625, +E0626: 0626, +E0627: 0627, +E0628: 0628, +E0631: 0631, +E0632: 0632, +E0633: 0633, +E0634: 0634, +E0635: 0635, +E0636: 0636, +E0637: 0637, +E0638: 0638, +E0639: 0639, +E0640: 0640, +E0641: 0641, +E0642: 0642, +E0643: 0643, +E0644: 0644, +E0646: 0646, +E0647: 0647, +E0648: 0648, +E0657: 0657, +E0658: 0658, +E0659: 0659, +E0660: 0660, +E0661: 0661, +E0662: 0662, +E0663: 0663, +E0664: 0664, +E0665: 0665, +E0666: 0666, +E0667: 0667, +E0668: 0668, +E0669: 0669, +E0670: 0670, +E0671: 0671, +E0687: 0687, +E0688: 0688, +E0689: 0689, +E0690: 0690, +E0691: 0691, +E0692: 0692, +E0693: 0693, +E0695: 0695, +E0696: 0696, +E0697: 0697, +E0698: 0698, +E0699: 0699, +E0700: 0700, +E0701: 0701, +E0703: 0703, +E0704: 0704, +E0705: 0705, +E0706: 0706, +E0708: 0708, +E0710: 0710, +E0712: 0712, +E0713: 0713, +E0714: 0714, +E0715: 0715, +E0716: 0716, +E0711: 0711, +E0717: 0717, +E0718: 0718, +E0719: 0719, +E0720: 0720, +E0722: 0722, +E0724: 0724, +E0725: 0725, +E0726: 0726, +E0727: 0727, +E0728: 0728, +E0729: 0729, +E0730: 0730, +E0731: 0731, +E0732: 0732, +E0733: 0733, +E0734: 0734, +E0735: 0735, +E0736: 0736, +E0737: 0737, +E0739: 0739, +E0740: 0740, +E0741: 0741, +E0742: 0742, +E0743: 0743, +E0744: 0744, +E0745: 0745, +E0746: 0746, +E0747: 0747, +E0748: 0748, +E0749: 0749, +E0750: 0750, +E0751: 0751, +E0752: 0752, +E0753: 0753, +E0754: 0754, +E0755: 0755, +E0756: 0756, +E0757: 0757, +E0758: 0758, +E0759: 0759, +E0760: 0760, +E0761: 0761, +E0762: 0762, +E0763: 0763, +E0764: 0764, +E0765: 0765, +E0766: 0766, +E0767: 0767, +E0768: 0768, +E0769: 0769, +E0770: 0770, +E0771: 0771, +E0772: 0772, +E0773: 0773, +E0774: 0774, +E0775: 0775, +E0776: 0776, +E0777: 0777, +E0778: 0778, +E0779: 0779, +E0780: 0780, +E0781: 0781, +E0782: 0782, +E0783: 0783, +E0784: 0784, +E0785: 0785, +E0786: 0786, +E0787: 0787, +E0788: 0788, +E0789: 0789, +E0790: 0790, +E0791: 0791, +E0792: 0792, +E0793: 0793, +E0794: 0794, +E0795: 0795, +E0796: 0796, +E0797: 0797, + ); ) } -mod error_codes; -pub use error_codes::DIAGNOSTICS; +// Undocumented removed error codes. Note that many removed error codes are kept in the list above +// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example). +// E0006, // merged with E0005 +// E0008, // cannot bind by-move into a pattern guard +// E0019, // merged into E0015 +// E0035, // merged into E0087/E0089 +// E0036, // merged into E0087/E0089 +// E0068, +// E0085, +// E0086, +// E0101, // replaced with E0282 +// E0102, // replaced with E0282 +// E0103, +// E0104, +// E0122, // bounds in type aliases are ignored, turned into proper lint +// E0123, +// E0127, +// E0129, +// E0134, +// E0135, +// E0141, +// E0153, // unused error code +// E0157, // unused error code +// E0159, // use of trait `{}` as struct constructor +// E0163, // merged into E0071 +// E0167, +// E0168, +// E0172, // non-trait found in a type sum, moved to resolve +// E0173, // manual implementations of unboxed closure traits are experimental +// E0174, +// E0182, // merged into E0229 +// E0187, // cannot infer the kind of the closure +// E0188, // can not cast an immutable reference to a mutable pointer +// E0189, // deprecated: can only cast a boxed pointer to a boxed object +// E0190, // deprecated: can only cast a &-pointer to an &-object +// E0194, // merged into E0403 +// E0196, // cannot determine a type for this closure +// E0209, // builtin traits can only be implemented on structs or enums +// E0213, // associated types are not accepted in this context +// E0215, // angle-bracket notation is not stable with `Fn` +// E0216, // parenthetical notation is only stable with `Fn` +// E0217, // ambiguous associated type, defined in multiple supertraits +// E0218, // no associated type defined +// E0219, // associated type defined in higher-ranked supertrait +// E0233, +// E0234, +// E0235, // structure constructor specifies a structure of type but +// E0236, // no lang item for range syntax +// E0237, // no lang item for range syntax +// E0238, // parenthesized parameters may only be used with a trait +// E0239, // `next` method of `Iterator` trait has unexpected type +// E0240, +// E0241, +// E0242, +// E0245, // not a trait +// E0246, // invalid recursive type +// E0247, +// E0248, // value used as a type, now reported earlier during resolution +// // as E0412 +// E0249, +// E0257, +// E0258, +// E0272, // on_unimplemented #0 +// E0273, // on_unimplemented #1 +// E0274, // on_unimplemented #2 +// E0278, // requirement is not satisfied +// E0279, +// E0280, // changed to ICE +// E0285, // overflow evaluation builtin bounds +// E0296, // replaced with a generic attribute input check +// E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0300, // unexpanded macro +// E0304, // expected signed integer constant +// E0305, // expected constant +// E0313, // removed: found unreachable +// E0314, // closure outlives stack frame +// E0315, // cannot invoke closure outside of its lifetime +// E0319, // trait impls for defaulted traits allowed just for structs/enums +// E0372, // coherence not object safe +// E0385, // {} in an aliasable location +// E0402, // cannot use an outer type parameter in this context +// E0406, // merged into 420 +// E0410, // merged into 408 +// E0413, // merged into 530 +// E0414, // merged into 530 +// E0417, // merged into 532 +// E0418, // merged into 532 +// E0419, // merged into 531 +// E0420, // merged into 532 +// E0421, // merged into 531 +// E0427, // merged into 530 +// E0445, // merged into 446 and type privacy lints +// E0456, // plugin `..` is not available for triple `..` +// E0465, // removed: merged with E0464 +// E0467, // removed +// E0470, // removed +// E0471, // constant evaluation error (in pattern) +// E0473, // dereference of reference outside its lifetime +// E0474, // captured variable `..` does not outlive the enclosing closure +// E0475, // index of slice outside its lifetime +// E0479, // the type `..` (provided as the value of a type parameter) is... +// E0480, // lifetime of method receiver does not outlive the method call +// E0481, // lifetime of function argument does not outlive the function call +// E0483, // lifetime of operand does not outlive the operation +// E0484, // reference is not valid at the time of borrow +// E0485, // automatically reference is not valid at the time of borrow +// E0486, // type of expression contains references that are not valid during.. +// E0487, // unsafe use of destructor: destructor might be called while... +// E0488, // lifetime of variable does not enclose its declaration +// E0489, // type/lifetime parameter not in scope here +// E0490, // removed: unreachable +// E0526, // shuffle indices are not constant +// E0540, // multiple rustc_deprecated attributes +// E0548, // replaced with a generic attribute input check +// E0553, // multiple rustc_const_unstable attributes +// E0555, // replaced with a generic attribute input check +// E0558, // replaced with a generic attribute input check +// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 +// E0564, // only named lifetimes are allowed in `impl Trait`, +// // but `{}` was found in the type `{}` +// E0598, // lifetime of {} is too short to guarantee its contents can be... +// E0611, // merged into E0616 +// E0612, // merged into E0609 +// E0613, // Removed (merged with E0609) +// E0629, // missing 'feature' (rustc_const_unstable) +// E0630, // rustc_const_unstable attribute must be paired with stable/unstable +// // attribute +// E0645, // trait aliases not finished +// E0694, // an unknown tool name found in scoped attributes +// E0702, // replaced with a generic attribute input check +// E0707, // multiple elided lifetimes used in arguments of `async fn` +// E0709, // multiple different lifetimes used in arguments of `async fn` +// E0721, // `await` keyword +// E0723, // unstable feature in `const` context +// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. +// E0744, // merged into E0728 diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index fc544c31e8930..d212e18b4cd72 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -1,6 +1,5 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![feature(let_chains)] #![feature(lazy_cell)] #![feature(rustc_attrs)] #![feature(type_alias_impl_trait)] @@ -379,7 +378,7 @@ impl From> for DiagnosticMessage { } } -/// A workaround for "good path" ICEs when formatting types in disabled lints. +/// A workaround for good_path_delayed_bug ICEs when formatting types in disabled lints. /// /// Delays formatting until `.into(): DiagnosticMessage` is used. pub struct DelayDm(pub F); diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 0c1fcecb57173..a2d1fd2a92419 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -10,9 +10,11 @@ derive_setters = "0.1.6" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index f0699a56f98ef..37f568f12a797 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -9,8 +9,8 @@ use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; use crate::translation::{to_fluent_args, Translate}; use crate::{ - CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Style, SubDiagnostic, + CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, ErrCode, FluentBundle, + LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic, }; use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; use rustc_data_structures::sync::Lrc; @@ -44,15 +44,15 @@ impl Translate for AnnotateSnippetEmitter { impl Emitter for AnnotateSnippetEmitter { /// The entry point for the diagnostics generation - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, mut diag: Diagnostic) { let fluent_args = to_fluent_args(diag.args()); - let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); + let mut suggestions = diag.suggestions.unwrap_or(vec![]); + self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut primary_span, - &mut children, + &mut diag.span, + &mut diag.children, &diag.level, self.macro_backtrace, ); @@ -62,9 +62,9 @@ impl Emitter for AnnotateSnippetEmitter { &diag.messages, &fluent_args, &diag.code, - &primary_span, - &children, - suggestions, + &diag.span, + &diag.children, + &suggestions, ); } @@ -85,7 +85,11 @@ fn source_string(file: Lrc, line: &Line) -> String { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::DelayedBug(_) | Level::Fatal | Level::Error => AnnotationType::Error, + Level::Bug + | Level::Fatal + | Level::Error + | Level::DelayedBug + | Level::GoodPathDelayedBug => AnnotationType::Error, Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help | Level::OnceHelp => AnnotationType::Help, @@ -127,7 +131,7 @@ impl AnnotateSnippetEmitter { level: &Level, messages: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, - code: &Option, + code: &Option, msp: &MultiSpan, _children: &[SubDiagnostic], _suggestions: &[CodeSuggestion], @@ -178,6 +182,7 @@ impl AnnotateSnippetEmitter { .collect::>() }) .collect(); + let code = code.map(|code| code.to_string()); let snippet = Snippet { title: Some(Annotation { label: Some(&message), diff --git a/compiler/rustc_errors/src/codes.rs b/compiler/rustc_errors/src/codes.rs new file mode 100644 index 0000000000000..947cf27ca7957 --- /dev/null +++ b/compiler/rustc_errors/src/codes.rs @@ -0,0 +1,39 @@ +//! This module defines the following. +//! - The `ErrCode` type. +//! - A constant for every error code, with a name like `E0123`. +//! - A static table `DIAGNOSTICS` pairing every error code constant with its +//! long description text. + +use std::fmt; + +rustc_index::newtype_index! { + #[max = 9999] // Because all error codes have four digits. + #[orderable] + #[encodable] + #[debug_format = "ErrCode({})"] + pub struct ErrCode {} +} + +impl fmt::Display for ErrCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "E{:04}", self.as_u32()) + } +} + +macro_rules! define_error_code_constants_and_diagnostics_table { + ($($name:ident: $num:literal,)*) => ( + $( + pub const $name: $crate::ErrCode = $crate::ErrCode::from_u32($num); + )* + pub static DIAGNOSTICS: &[($crate::ErrCode, &str)] = &[ + $( ( + $name, + include_str!( + concat!("../../rustc_error_codes/src/error_codes/", stringify!($name), ".md") + ) + ), )* + ]; + ) +} + +rustc_error_codes::error_codes!(define_error_code_constants_and_diagnostics_table); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 4934bc2450c79..1763c355069a9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,6 +1,6 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, + CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -22,19 +22,21 @@ pub struct SuggestionsDisabled; /// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of /// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of /// diagnostic emission. -pub type DiagnosticArg<'iter, 'source> = - (&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>); +pub type DiagnosticArg<'iter> = (&'iter DiagnosticArgName, &'iter DiagnosticArgValue); /// Name of a diagnostic argument. -pub type DiagnosticArgName<'source> = Cow<'source, str>; +pub type DiagnosticArgName = Cow<'static, str>; /// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted /// to a `FluentValue` by the emitter to be used in diagnostic translation. #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] -pub enum DiagnosticArgValue<'source> { - Str(Cow<'source, str>), - Number(i128), - StrListSepByAnd(Vec>), +pub enum DiagnosticArgValue { + Str(Cow<'static, str>), + // This gets converted to a `FluentNumber`, which is an `f64`. An `i32` + // safely fits in an `f64`. Any integers bigger than that will be converted + // to strings in `into_diagnostic_arg` and stored using the `Str` variant. + Number(i32), + StrListSepByAnd(Vec>), } /// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic` @@ -42,23 +44,17 @@ pub enum DiagnosticArgValue<'source> { /// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*` /// crates to implement this. pub trait IntoDiagnosticArg { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; + fn into_diagnostic_arg(self) -> DiagnosticArgValue; } -impl<'source> IntoDiagnosticArg for DiagnosticArgValue<'source> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - match self { - DiagnosticArgValue::Str(s) => DiagnosticArgValue::Str(Cow::Owned(s.into_owned())), - DiagnosticArgValue::Number(n) => DiagnosticArgValue::Number(n), - DiagnosticArgValue::StrListSepByAnd(l) => DiagnosticArgValue::StrListSepByAnd( - l.into_iter().map(|s| Cow::Owned(s.into_owned())).collect(), - ), - } +impl IntoDiagnosticArg for DiagnosticArgValue { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + self } } -impl<'source> Into> for DiagnosticArgValue<'source> { - fn into(self) -> FluentValue<'source> { +impl Into> for DiagnosticArgValue { + fn into(self) -> FluentValue<'static> { match self { DiagnosticArgValue::Str(s) => From::from(s), DiagnosticArgValue::Number(n) => From::from(n), @@ -104,24 +100,22 @@ pub struct Diagnostic { pub(crate) level: Level, pub messages: Vec<(DiagnosticMessage, Style)>, - pub code: Option, + pub code: Option, pub span: MultiSpan, pub children: Vec, pub suggestions: Result, SuggestionsDisabled>, - args: FxHashMap, DiagnosticArgValue<'static>>, + args: FxHashMap, /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of /// `span` if there is one. Otherwise, it is `DUMMY_SP`. pub sort_span: Span, - /// If diagnostic is from Lint, custom hash function ignores children. - /// Otherwise hash is based on the all the fields. pub is_lint: Option, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. - pub emitted_at: DiagnosticLocation, + pub(crate) emitted_at: DiagnosticLocation, } #[derive(Clone, Debug, Encodable, Decodable)] @@ -170,10 +164,10 @@ impl DiagnosticStyledString { DiagnosticStyledString(vec![]) } pub fn push_normal>(&mut self, t: S) { - self.0.push(StringPart::Normal(t.into())); + self.0.push(StringPart::normal(t)); } pub fn push_highlighted>(&mut self, t: S) { - self.0.push(StringPart::Highlighted(t.into())); + self.0.push(StringPart::highlighted(t)); } pub fn push>(&mut self, t: S, highlight: bool) { if highlight { @@ -183,35 +177,34 @@ impl DiagnosticStyledString { } } pub fn normal>(t: S) -> DiagnosticStyledString { - DiagnosticStyledString(vec![StringPart::Normal(t.into())]) + DiagnosticStyledString(vec![StringPart::normal(t)]) } pub fn highlighted>(t: S) -> DiagnosticStyledString { - DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) + DiagnosticStyledString(vec![StringPart::highlighted(t)]) } pub fn content(&self) -> String { - self.0.iter().map(|x| x.content()).collect::() + self.0.iter().map(|x| x.content.as_str()).collect::() } } #[derive(Debug, PartialEq, Eq)] -pub enum StringPart { - Normal(String), - Highlighted(String), +pub struct StringPart { + content: String, + style: Style, } impl StringPart { - pub fn content(&self) -> &str { - match self { - &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s, - } + pub fn normal>(content: S) -> StringPart { + StringPart { content: content.into(), style: Style::NoStyle } + } + + pub fn highlighted>(content: S) -> StringPart { + StringPart { content: content.into(), style: Style::Highlight } } } -// Note: most of these methods are setters that return `&mut Self`. The small -// number of simple getter functions all have `get_` prefixes to distinguish -// them from the setters. impl Diagnostic { #[track_caller] pub fn new>(level: Level, message: M) -> Self { @@ -241,19 +234,16 @@ impl Diagnostic { pub fn is_error(&self) -> bool { match self.level { - Level::Bug - | Level::DelayedBug(DelayedBugKind::Normal) - | Level::Fatal - | Level::Error - | Level::FailureNote => true, + Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true, - Level::ForceWarning(_) + Level::GoodPathDelayedBug + | Level::ForceWarning(_) | Level::Warning - | Level::DelayedBug(DelayedBugKind::GoodPath) | Level::Note | Level::OnceNote | Level::Help | Level::OnceHelp + | Level::FailureNote | Level::Allow | Level::Expect(_) => false, } @@ -312,11 +302,11 @@ impl Diagnostic { #[track_caller] pub fn downgrade_to_delayed_bug(&mut self) { assert!( - self.is_error(), + matches!(self.level, Level::Error | Level::DelayedBug), "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", self.level ); - self.level = Level::DelayedBug(DelayedBugKind::Normal); + self.level = Level::DelayedBug; } /// Appends a labeled span to the diagnostic. @@ -397,19 +387,16 @@ impl Diagnostic { } else { (0, found_label.len() - expected_label.len()) }; - let mut msg: Vec<_> = - vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)]; - msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), - })); - msg.push((format!("`{expected_extra}\n"), Style::NoStyle)); - msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle)); - msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), - })); - msg.push((format!("`{found_extra}"), Style::NoStyle)); + let mut msg = vec![StringPart::normal(format!( + "{}{} `", + " ".repeat(expected_padding), + expected_label + ))]; + msg.extend(expected.0.into_iter()); + msg.push(StringPart::normal(format!("`{expected_extra}\n"))); + msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); + msg.extend(found.0.into_iter()); + msg.push(StringPart::normal(format!("`{found_extra}"))); // For now, just attach these as notes. self.highlighted_note(msg); @@ -418,9 +405,9 @@ impl Diagnostic { pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { self.highlighted_note(vec![ - (format!("`{name}` from trait: `"), Style::NoStyle), - (signature, Style::Highlight), - ("`".to_string(), Style::NoStyle), + StringPart::normal(format!("`{name}` from trait: `")), + StringPart::highlighted(signature), + StringPart::normal("`"), ]); self } @@ -432,10 +419,7 @@ impl Diagnostic { self } - fn highlighted_note>( - &mut self, - msg: Vec<(M, Style)>, - ) -> &mut Self { + fn highlighted_note(&mut self, msg: Vec) -> &mut Self { self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); self } @@ -504,7 +488,7 @@ impl Diagnostic { } /// Add a help message attached to this diagnostic with a customizable highlighted message. - pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self { + pub fn highlighted_help(&mut self, msg: Vec) -> &mut Self { self.sub_with_highlights(Level::Help, msg, MultiSpan::new()); self } @@ -893,20 +877,11 @@ impl Diagnostic { self } - pub fn code(&mut self, s: String) -> &mut Self { - self.code = Some(s); - self - } - - pub fn clear_code(&mut self) -> &mut Self { - self.code = None; + pub fn code(&mut self, code: ErrCode) -> &mut Self { + self.code = Some(code); self } - pub fn get_code(&self) -> Option<&str> { - self.code.as_deref() - } - pub fn primary_message(&mut self, msg: impl Into) -> &mut Self { self.messages[0] = (msg.into(), Style::NoStyle); self @@ -915,30 +890,23 @@ impl Diagnostic { // Exact iteration order of diagnostic arguments shouldn't make a difference to output because // they're only used in interpolation. #[allow(rustc::potential_query_instability)] - pub fn args(&self) -> impl Iterator> { + pub fn args(&self) -> impl Iterator> { self.args.iter() } pub fn arg( &mut self, - name: impl Into>, + name: impl Into, arg: impl IntoDiagnosticArg, ) -> &mut Self { self.args.insert(name.into(), arg.into_diagnostic_arg()); self } - pub fn replace_args( - &mut self, - args: FxHashMap, DiagnosticArgValue<'static>>, - ) { + pub fn replace_args(&mut self, args: FxHashMap) { self.args = args; } - pub fn messages(&self) -> &[(DiagnosticMessage, Style)] { - &self.messages - } - /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// combining it with the primary message of the diagnostic (if translatable, otherwise it just /// passes the user's string along). @@ -969,15 +937,10 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. - fn sub_with_highlights>( - &mut self, - level: Level, - messages: Vec<(M, Style)>, - span: MultiSpan, - ) { + fn sub_with_highlights(&mut self, level: Level, messages: Vec, span: MultiSpan) { let messages = messages .into_iter() - .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) + .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style)) .collect(); let sub = SubDiagnostic { level, messages, span }; self.children.push(sub); @@ -989,22 +952,24 @@ impl Diagnostic { ) -> ( &Level, &[(DiagnosticMessage, Style)], - Vec<(&Cow<'static, str>, &DiagnosticArgValue<'static>)>, - &Option, - &Option, + &Option, &MultiSpan, + &[SubDiagnostic], &Result, SuggestionsDisabled>, - Option<&[SubDiagnostic]>, + Vec<(&DiagnosticArgName, &DiagnosticArgValue)>, + &Option, ) { ( &self.level, &self.messages, - self.args().collect(), &self.code, - &self.is_lint, &self.span, + &self.children, &self.suggestions, - (if self.is_lint.is_some() { None } else { Some(&self.children) }), + self.args().collect(), + // omit self.sort_span + &self.is_lint, + // omit self.emitted_at ) } } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 87e2d295c7f4c..faff7f0b52673 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,7 +1,7 @@ use crate::diagnostic::IntoDiagnosticArg; use crate::{DiagCtxt, Level, MultiSpan, StashKey}; use crate::{ - Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, ExplicitBug, + Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrCode, ErrorGuaranteed, ExplicitBug, SubdiagnosticMessage, }; use rustc_lint_defs::Applicability; @@ -255,13 +255,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Stashes diagnostic for possible later improvement in a different, /// later stage of the compiler. The diagnostic can be accessed with /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`]. - pub fn stash(self, span: Span, key: StashKey) { - self.dcx.stash_diagnostic(span, key, self.into_diagnostic()); - } - - /// Converts the builder to a `Diagnostic` for later emission. - pub fn into_diagnostic(mut self) -> Diagnostic { - self.take_diag() + pub fn stash(mut self, span: Span, key: StashKey) { + self.dcx.stash_diagnostic(span, key, self.take_diag()); } /// Delay emission of this diagnostic as a bug. @@ -399,7 +394,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { name: String, has_future_breakage: bool, )); forward!((code, with_code)( - s: String, + code: ErrCode, )); forward!((arg, with_arg)( name: impl Into>, arg: impl IntoDiagnosticArg, @@ -439,12 +434,7 @@ impl Drop for DiagnosticBuilder<'_, G> { #[macro_export] macro_rules! struct_span_code_err { - ($dcx:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - $dcx.struct_span_err($span, format!($($message)*)).with_code($crate::error_code!($code)) + ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({ + $dcx.struct_span_err($span, format!($($message)*)).with_code($code) }) } - -#[macro_export] -macro_rules! error_code { - ($code:ident) => {{ stringify!($code).to_owned() }}; -} diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 39252dea28303..15effd3cbec9b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,7 +1,7 @@ use crate::diagnostic::DiagnosticLocation; use crate::{fluent_generated as fluent, AddToDiagnostic}; use crate::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, ErrCode, IntoDiagnostic, IntoDiagnosticArg, Level, }; use rustc_ast as ast; @@ -23,7 +23,7 @@ use std::process::ExitStatus; pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display); impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.0.to_string().into_diagnostic_arg() } } @@ -41,7 +41,7 @@ impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> { } impl<'a, T: Clone + IntoDiagnosticArg> IntoDiagnosticArg for &'a T { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.clone().into_diagnostic_arg() } } @@ -50,7 +50,7 @@ macro_rules! into_diagnostic_arg_using_display { ($( $ty:ty ),+ $(,)?) => { $( impl IntoDiagnosticArg for $ty { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -58,16 +58,25 @@ macro_rules! into_diagnostic_arg_using_display { } } +macro_rules! into_diagnostic_arg_for_number { + ($( $ty:ty ),+ $(,)?) => { + $( + impl IntoDiagnosticArg for $ty { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + // Convert to a string if it won't fit into `Number`. + if let Ok(n) = TryInto::::try_into(self) { + DiagnosticArgValue::Number(n) + } else { + self.to_string().into_diagnostic_arg() + } + } + } + )+ + } +} + into_diagnostic_arg_using_display!( ast::ParamKindOrd, - i8, - u8, - i16, - u16, - u32, - i64, - i128, - u128, std::io::Error, Box, std::num::NonZeroU32, @@ -80,22 +89,13 @@ into_diagnostic_arg_using_display!( &TargetTriple, SplitDebuginfo, ExitStatus, + ErrCode, ); -impl IntoDiagnosticArg for i32 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self.into()) - } -} - -impl IntoDiagnosticArg for u64 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self.into()) - } -} +into_diagnostic_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagnosticArg for bool { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { if self { DiagnosticArgValue::Str(Cow::Borrowed("true")) } else { @@ -105,61 +105,63 @@ impl IntoDiagnosticArg for bool { } impl IntoDiagnosticArg for char { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(format!("{self:?}"))) } } +impl IntoDiagnosticArg for Vec { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + DiagnosticArgValue::StrListSepByAnd( + self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(), + ) + } +} + impl IntoDiagnosticArg for Symbol { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_ident_string().into_diagnostic_arg() } } impl<'a> IntoDiagnosticArg for &'a str { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } impl IntoDiagnosticArg for String { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self)) } } impl<'a> IntoDiagnosticArg for Cow<'a, str> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.into_owned())) } } impl<'a> IntoDiagnosticArg for &'a Path { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) } } impl IntoDiagnosticArg for PathBuf { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) } } -impl IntoDiagnosticArg for usize { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self as i128) - } -} - impl IntoDiagnosticArg for PanicStrategy { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) } } impl IntoDiagnosticArg for hir::ConstContext { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Borrowed(match self { hir::ConstContext::ConstFn => "const_fn", hir::ConstContext::Static(_) => "static", @@ -169,49 +171,49 @@ impl IntoDiagnosticArg for hir::ConstContext { } impl IntoDiagnosticArg for ast::Expr { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(pprust::expr_to_string(&self))) } } impl IntoDiagnosticArg for ast::Path { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self))) } } impl IntoDiagnosticArg for ast::token::Token { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(pprust::token_to_string(&self)) } } impl IntoDiagnosticArg for ast::token::TokenKind { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(pprust::token_kind_to_string(&self)) } } impl IntoDiagnosticArg for type_ir::FloatTy { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Borrowed(self.name_str())) } } impl IntoDiagnosticArg for std::ffi::CString { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) } } impl IntoDiagnosticArg for rustc_data_structures::small_c_str::SmallCStr { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) } } impl IntoDiagnosticArg for ast::Visibility { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { let s = pprust::vis_to_string(&self); let s = s.trim_end().to_string(); DiagnosticArgValue::Str(Cow::Owned(s)) @@ -219,7 +221,7 @@ impl IntoDiagnosticArg for ast::Visibility { } impl IntoDiagnosticArg for rustc_lint_defs::Level { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Borrowed(self.to_cmd_flag())) } } @@ -234,7 +236,7 @@ impl From> for DiagnosticSymbolList { } impl IntoDiagnosticArg for DiagnosticSymbolList { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::StrListSepByAnd( self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(), ) @@ -242,7 +244,7 @@ impl IntoDiagnosticArg for DiagnosticSymbolList { } impl IntoDiagnosticArg for hir::def::Res { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Borrowed(self.descr())) } } @@ -328,13 +330,13 @@ pub struct DelayedAtWithoutNewline { } impl IntoDiagnosticArg for DiagnosticLocation { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::from(self.to_string())) } } impl IntoDiagnosticArg for Backtrace { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::from(self.to_string())) } } @@ -347,7 +349,7 @@ pub struct InvalidFlushedDelayedDiagnosticLevel { pub level: Level, } impl IntoDiagnosticArg for Level { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::from(self.to_string())) } } @@ -362,7 +364,7 @@ pub struct IndicateAnonymousLifetime { } impl IntoDiagnosticArg for type_ir::ClosureKind { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(self.as_str().into()) } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 23efdaea0ebb8..b9e92dbb31c64 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -17,8 +17,8 @@ use crate::styled_buffer::StyledBuffer; use crate::translation::{to_fluent_args, Translate}; use crate::{ diagnostic::DiagnosticLocation, CodeSuggestion, DiagCtxt, Diagnostic, DiagnosticMessage, - FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, - SuggestionStyle, TerminalUrl, + ErrCode, FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, + SubstitutionHighlight, SuggestionStyle, TerminalUrl, }; use rustc_lint_defs::pluralize; @@ -193,7 +193,7 @@ pub type DynEmitter = dyn Emitter + DynSend; /// Emitter trait for emitting errors. pub trait Emitter: Translate { /// Emit a structured diagnostic. - fn emit_diagnostic(&mut self, diag: &Diagnostic); + fn emit_diagnostic(&mut self, diag: Diagnostic); /// Emit a notification that an artifact has been output. /// Currently only supported for the JSON format. @@ -230,17 +230,17 @@ pub trait Emitter: Translate { /// /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, /// we format the `help` suggestion depending on the content of the - /// substitutions. In that case, we return the modified span only. + /// substitutions. In that case, we modify the span and clear the + /// suggestions. /// /// * If the current `Diagnostic` has multiple suggestions, - /// we return the original `primary_span` and the original suggestions. - fn primary_span_formatted<'a>( + /// we leave `primary_span` and the suggestions untouched. + fn primary_span_formatted( &mut self, - diag: &'a Diagnostic, + primary_span: &mut MultiSpan, + suggestions: &mut Vec, fluent_args: &FluentArgs<'_>, - ) -> (MultiSpan, &'a [CodeSuggestion]) { - let mut primary_span = diag.span.clone(); - let suggestions = diag.suggestions.as_deref().unwrap_or(&[]); + ) { if let Some((sugg, rest)) = suggestions.split_first() { let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap(); if rest.is_empty() && @@ -287,16 +287,15 @@ pub trait Emitter: Translate { primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); // We return only the modified primary_span - (primary_span, &[]) + suggestions.clear(); } else { // if there are multiple suggestions, print them all in full // to be consistent. We could try to figure out if we can // make one (or the first one) inline, but that would give // undue importance to a semi-random suggestion - (primary_span, suggestions) } } else { - (primary_span, suggestions) + // do nothing } } @@ -518,16 +517,15 @@ impl Emitter for HumanEmitter { self.sm.as_ref() } - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, mut diag: Diagnostic) { let fluent_args = to_fluent_args(diag.args()); - let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); - debug!("emit_diagnostic: suggestions={:?}", suggestions); + let mut suggestions = diag.suggestions.unwrap_or(vec![]); + self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut primary_span, - &mut children, + &mut diag.span, + &mut diag.children, &diag.level, self.macro_backtrace, ); @@ -537,9 +535,9 @@ impl Emitter for HumanEmitter { &diag.messages, &fluent_args, &diag.code, - &primary_span, - &children, - suggestions, + &diag.span, + &diag.children, + &suggestions, self.track_diagnostics.then_some(&diag.emitted_at), ); } @@ -558,7 +556,7 @@ impl Emitter for HumanEmitter { /// failures of rustc, as witnessed e.g. in issue #89358. pub struct SilentEmitter { pub fatal_dcx: DiagCtxt, - pub fatal_note: Option, + pub fatal_note: String, } impl Translate for SilentEmitter { @@ -576,13 +574,10 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, d: &Diagnostic) { - if d.level == Level::Fatal { - let mut d = d.clone(); - if let Some(ref note) = self.fatal_note { - d.note(note.clone()); - } - self.fatal_dcx.emit_diagnostic(d); + fn emit_diagnostic(&mut self, mut diag: Diagnostic) { + if diag.level == Level::Fatal { + diag.note(self.fatal_note.clone()); + self.fatal_dcx.emit_diagnostic(diag); } } } @@ -1309,7 +1304,7 @@ impl HumanEmitter { msp: &MultiSpan, msgs: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, - code: &Option, + code: &Option, level: &Level, max_line_num_len: usize, is_secondary: bool, @@ -1340,9 +1335,9 @@ impl HumanEmitter { buffer.append(0, "[", Style::Level(*level)); let code = if let TerminalUrl::Yes = self.terminal_url { let path = "https://doc.rust-lang.org/error_codes"; - Cow::Owned(format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07")) + format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07") } else { - Cow::Borrowed(code) + code.to_string() }; buffer.append(0, &code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); @@ -2076,7 +2071,7 @@ impl HumanEmitter { level: &Level, messages: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, - code: &Option, + code: &Option, span: &MultiSpan, children: &[SubDiagnostic], suggestions: &[CodeSuggestion], @@ -2118,6 +2113,7 @@ impl HumanEmitter { } if !self.short_message { for child in children { + assert!(child.level.can_be_top_or_sub().1); let span = &child.span; if let Err(err) = self.emit_messages_default_inner( span, diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 51b064f4c617a..470e3d52452cf 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -176,7 +176,7 @@ impl Translate for JsonEmitter { } impl Emitter for JsonEmitter { - fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) { + fn emit_diagnostic(&mut self, diag: crate::Diagnostic) { let data = Diagnostic::from_errors_diagnostic(diag, self); let result = self.emit(EmitTyped::Diagnostic(data)); if let Err(e) = result { @@ -201,7 +201,7 @@ impl Emitter for JsonEmitter { } FutureBreakageItem { diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic( - &diag, self, + diag, self, )), } }) @@ -340,7 +340,7 @@ struct UnusedExterns<'a, 'b, 'c> { } impl Diagnostic { - fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { + fn from_errors_diagnostic(diag: crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { let args = to_fluent_args(diag.args()); let sugg = diag.suggestions.iter().flatten().map(|sugg| { let translated_message = @@ -382,6 +382,28 @@ impl Diagnostic { Ok(()) } } + + let translated_message = je.translate_messages(&diag.messages, &args); + + let code = if let Some(code) = diag.code { + Some(DiagnosticCode { + code: code.to_string(), + explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(), + }) + } else if let Some(IsLint { name, .. }) = &diag.is_lint { + Some(DiagnosticCode { code: name.to_string(), explanation: None }) + } else { + None + }; + let level = diag.level.to_str(); + let spans = DiagnosticSpan::from_multispan(&diag.span, &args, je); + let children = diag + .children + .iter() + .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je)) + .chain(sugg) + .collect(); + let buf = BufWriter::default(); let output = buf.clone(); je.json_rendered @@ -398,30 +420,12 @@ impl Diagnostic { let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); - let translated_message = je.translate_messages(&diag.messages, &args); - - let code = if let Some(code) = &diag.code { - Some(DiagnosticCode { - code: code.to_string(), - explanation: je.registry.as_ref().unwrap().try_find_description(&code).ok(), - }) - } else if let Some(IsLint { name, .. }) = &diag.is_lint { - Some(DiagnosticCode { code: name.to_string(), explanation: None }) - } else { - None - }; - Diagnostic { message: translated_message.to_string(), code, - level: diag.level.to_str(), - spans: DiagnosticSpan::from_multispan(&diag.span, &args, je), - children: diag - .children - .iter() - .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je)) - .chain(sugg) - .collect(), + level, + spans, + children, rendered: Some(output), } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 141547b537dea..a4112d717d029 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,24 +2,26 @@ //! //! This module contains the code for creating and emitting diagnostics. +// tidy-alphabetical-start +#![allow(incomplete_features)] +#![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(rustdoc_internals)] #![feature(array_windows)] #![feature(associated_type_defaults)] #![feature(box_into_inner)] +#![feature(box_patterns)] +#![feature(error_reporter)] #![feature(extract_if)] -#![feature(if_let_guard)] #![feature(let_chains)] +#![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] -#![feature(yeet_expr)] +#![feature(rustdoc_internals)] #![feature(try_blocks)] -#![feature(box_patterns)] -#![feature(error_reporter)] -#![allow(incomplete_features)] -#![allow(internal_features)] +#![feature(yeet_expr)] +// tidy-alphabetical-end #[macro_use] extern crate rustc_macros; @@ -29,9 +31,10 @@ extern crate tracing; extern crate self as rustc_errors; +pub use codes::*; pub use diagnostic::{ - AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, - DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, + AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName, + DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic, }; pub use diagnostic_builder::{ BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic, @@ -77,6 +80,7 @@ use std::path::{Path, PathBuf}; use Level::*; pub mod annotate_snippet_emitter_writer; +pub mod codes; mod diagnostic; mod diagnostic_builder; mod diagnostic_impls; @@ -98,7 +102,6 @@ pub type PResult<'a, T> = Result>; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. -// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.) #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -421,22 +424,22 @@ pub struct DiagCtxt { struct DiagCtxtInner { flags: DiagCtxtFlags, - /// The number of lint errors that have been emitted. + /// The number of lint errors that have been emitted, including duplicates. lint_err_count: usize, - /// The number of errors that have been emitted, including duplicates. - /// - /// This is not necessarily the count that's reported to the user once - /// compilation ends. + /// The number of non-lint errors that have been emitted, including duplicates. err_count: usize, + + /// The error count shown to the user at the end. deduplicated_err_count: usize, - /// The warning count, used for a recap upon finishing + /// The warning count shown to the user at the end. deduplicated_warn_count: usize, + /// Has this diagnostic context printed any diagnostics? (I.e. has /// `self.emitter.emit_diagnostic()` been called? has_printed: bool, emitter: Box, - span_delayed_bugs: Vec, + delayed_bugs: Vec, good_path_delayed_bugs: Vec, /// This flag indicates that an expected diagnostic was emitted and suppressed. /// This is used for the `good_path_delayed_bugs` check. @@ -445,10 +448,10 @@ struct DiagCtxtInner { /// This set contains the code of all emitted diagnostics to avoid /// emitting the same diagnostic with extended help (`--teach`) twice, which /// would be unnecessary repetition. - taught_diagnostics: FxHashSet, + taught_diagnostics: FxHashSet, /// Used to suggest rustc --explain `` - emitted_diagnostic_codes: FxIndexSet, + emitted_diagnostic_codes: FxIndexSet, /// This set contains a hash of every diagnostic that has been emitted by /// this `DiagCtxt`. These hashes is used to avoid emitting the same error @@ -510,6 +513,7 @@ pub enum StashKey { MaybeForgetReturn, /// Query cycle detected, stashing in favor of a better error. Cycle, + UndeterminedMacroResolution, } fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { @@ -519,8 +523,7 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { pub static TRACK_DIAGNOSTIC: AtomicRef = AtomicRef::new(&(default_track_diagnostic as _)); -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] -pub enum DelayedBugKind { +enum DelayedBugKind { Normal, GoodPath, } @@ -553,11 +556,6 @@ impl Drop for DiagCtxtInner { self.flush_delayed(DelayedBugKind::Normal) } - // FIXME(eddyb) this explains what `good_path_delayed_bugs` are! - // They're `span_delayed_bugs` but for "require some diagnostic happened" - // instead of "require some error happened". Sadly that isn't ideal, as - // lints can be `#[allow]`'d, potentially leading to this triggering. - // Also, "good path" should be replaced with a better naming. if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() { self.flush_delayed(DelayedBugKind::GoodPath); } @@ -604,7 +602,7 @@ impl DiagCtxt { deduplicated_warn_count: 0, has_printed: false, emitter, - span_delayed_bugs: Vec::new(), + delayed_bugs: Vec::new(), good_path_delayed_bugs: Vec::new(), suppressed_expected_diag: false, taught_diagnostics: Default::default(), @@ -624,7 +622,7 @@ impl DiagCtxt { pub fn eagerly_translate<'a>( &self, message: DiagnosticMessage, - args: impl Iterator>, + args: impl Iterator>, ) -> SubdiagnosticMessage { SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args))) } @@ -633,7 +631,7 @@ impl DiagCtxt { pub fn eagerly_translate_to_string<'a>( &self, message: DiagnosticMessage, - args: impl Iterator>, + args: impl Iterator>, ) -> String { let inner = self.inner.borrow(); let args = crate::translation::to_fluent_args(args); @@ -641,7 +639,8 @@ impl DiagCtxt { } // This is here to not allow mutation of flags; - // as of this writing it's only used in tests in librustc_middle. + // as of this writing it's used in Session::consider_optimizing and + // in tests in rustc_interface. pub fn can_emit_warnings(&self) -> bool { self.inner.borrow_mut().flags.can_emit_warnings } @@ -660,7 +659,7 @@ impl DiagCtxt { inner.has_printed = false; // actually free the underlying memory (which `clear` would not do) - inner.span_delayed_bugs = Default::default(); + inner.delayed_bugs = Default::default(); inner.good_path_delayed_bugs = Default::default(); inner.taught_diagnostics = Default::default(); inner.emitted_diagnostic_codes = Default::default(); @@ -861,8 +860,7 @@ impl DiagCtxt { /// directly). #[track_caller] pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed { - DiagnosticBuilder::::new(self, DelayedBug(DelayedBugKind::Normal), msg) - .emit() + DiagnosticBuilder::::new(self, DelayedBug, msg).emit() } /// Like `delayed_bug`, but takes an additional span. @@ -875,15 +873,12 @@ impl DiagCtxt { sp: impl Into, msg: impl Into, ) -> ErrorGuaranteed { - DiagnosticBuilder::::new(self, DelayedBug(DelayedBugKind::Normal), msg) - .with_span(sp) - .emit() + DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit() } - // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's - // where the explanation of what "good path" is (also, it should be renamed). + /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`. pub fn good_path_delayed_bug(&self, msg: impl Into) { - DiagnosticBuilder::<()>::new(self, DelayedBug(DelayedBugKind::GoodPath), msg).emit() + DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit() } #[track_caller] @@ -927,11 +922,13 @@ impl DiagCtxt { self.struct_bug(msg).emit() } + /// This excludes lint errors and delayed bugs. #[inline] pub fn err_count(&self) -> usize { self.inner.borrow().err_count } + /// This excludes lint errors and delayed bugs. pub fn has_errors(&self) -> Option { self.inner.borrow().has_errors().then(|| { #[allow(deprecated)] @@ -939,30 +936,24 @@ impl DiagCtxt { }) } + /// This excludes delayed bugs. Unless absolutely necessary, prefer + /// `has_errors` to this method. pub fn has_errors_or_lint_errors(&self) -> Option { let inner = self.inner.borrow(); - let has_errors_or_lint_errors = inner.has_errors() || inner.lint_err_count > 0; - has_errors_or_lint_errors.then(|| { - #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() - }) - } - - pub fn has_errors_or_span_delayed_bugs(&self) -> Option { - let inner = self.inner.borrow(); - let has_errors_or_span_delayed_bugs = - inner.has_errors() || !inner.span_delayed_bugs.is_empty(); - has_errors_or_span_delayed_bugs.then(|| { + let result = inner.has_errors() || inner.lint_err_count > 0; + result.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } - pub fn is_compilation_going_to_fail(&self) -> Option { + /// Unless absolutely necessary, prefer `has_errors` or + /// `has_errors_or_lint_errors` to this method. + pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { let inner = self.inner.borrow(); - let will_fail = - inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty(); - will_fail.then(|| { + let result = + inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty(); + result.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) @@ -990,9 +981,13 @@ impl DiagCtxt { match (errors.len(), warnings.len()) { (0, 0) => return, - (0, _) => inner - .emitter - .emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))), + (0, _) => { + // Use `inner.emitter` directly, otherwise the warning might not be emitted, e.g. + // with a configuration like `--cap-lints allow --force-warn bare_trait_objects`. + inner + .emitter + .emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))); + } (_, 0) => { inner.emit_diagnostic(Diagnostic::new(Fatal, errors)); } @@ -1007,9 +1002,9 @@ impl DiagCtxt { let mut error_codes = inner .emitted_diagnostic_codes .iter() - .filter_map(|code| { + .filter_map(|&code| { if registry.try_find_description(code).is_ok().clone() { - Some(code.clone()) + Some(code.to_string()) } else { None } @@ -1038,10 +1033,6 @@ impl DiagCtxt { } } - pub fn take_future_breakage_diagnostics(&self) -> Vec { - std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics) - } - pub fn abort_if_errors(&self) { let mut inner = self.inner.borrow_mut(); inner.emit_stashed_diagnostics(); @@ -1055,12 +1046,12 @@ impl DiagCtxt { /// /// Used to suppress emitting the same error multiple times with extended explanation when /// calling `-Zteach`. - pub fn must_teach(&self, code: &str) -> bool { - self.inner.borrow_mut().taught_diagnostics.insert(code.to_string()) + pub fn must_teach(&self, code: ErrCode) -> bool { + self.inner.borrow_mut().taught_diagnostics.insert(code) } pub fn force_print_diagnostic(&self, db: Diagnostic) { - self.inner.borrow_mut().emitter.emit_diagnostic(&db); + self.inner.borrow_mut().emitter.emit_diagnostic(db); } pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option { @@ -1149,8 +1140,12 @@ impl DiagCtxt { self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type); } - pub fn emit_future_breakage_report(&self, diags: Vec) { - self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) + pub fn emit_future_breakage_report(&self) { + let mut inner = self.inner.borrow_mut(); + let diags = std::mem::take(&mut inner.future_breakage_diagnostics); + if !diags.is_empty() { + inner.emitter.emit_future_breakage_report(diags); + } } pub fn emit_unused_externs( @@ -1162,7 +1157,7 @@ impl DiagCtxt { let mut inner = self.inner.borrow_mut(); if loud && lint_level.is_error() { - inner.err_count += 1; + inner.lint_err_count += 1; inner.panic_if_treat_err_as_bug(); } @@ -1223,9 +1218,8 @@ impl DiagCtxtInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option { let has_errors = self.has_errors(); - let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::>(); let mut reported = None; - for diag in diags { + for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { if diag.is_lint.is_some() { @@ -1248,45 +1242,19 @@ impl DiagCtxtInner { } fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option { - // The `LintExpectationId` can be stable or unstable depending on when it was created. - // Diagnostics created before the definition of `HirId`s are unstable and can not yet - // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by - // a stable one by the `LintLevelsBuilder`. - if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() { - self.unstable_expect_diagnostics.push(diagnostic.clone()); - return None; - } - - // FIXME(eddyb) this should check for `has_errors` and stop pushing - // once *any* errors were emitted (and truncate `span_delayed_bugs` - // when an error is first emitted, also), but maybe there's a case - // in which that's not sound? otherwise this is really inefficient. - match diagnostic.level { - DelayedBug(_) if self.flags.eagerly_emit_delayed_bugs => { - diagnostic.level = Error; - } - DelayedBug(DelayedBugKind::Normal) => { - let backtrace = std::backtrace::Backtrace::capture(); - self.span_delayed_bugs - .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); - - #[allow(deprecated)] - return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); - } - DelayedBug(DelayedBugKind::GoodPath) => { - let backtrace = std::backtrace::Backtrace::capture(); - self.good_path_delayed_bugs - .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); + assert!(diagnostic.level.can_be_top_or_sub().0); + if let Some(expectation_id) = diagnostic.level.get_expectation_id() { + // The `LintExpectationId` can be stable or unstable depending on when it was created. + // Diagnostics created before the definition of `HirId`s are unstable and can not yet + // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by + // a stable one by the `LintLevelsBuilder`. + if let LintExpectationId::Unstable { .. } = expectation_id { + self.unstable_expect_diagnostics.push(diagnostic); return None; } - _ => {} - } - - // This must come after the possible promotion of `DelayedBug` to - // `Error` above. - if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() { - diagnostic.level = Bug; + self.suppressed_expected_diag = true; + self.fulfilled_expectations.insert(expectation_id.normalize()); } if diagnostic.has_future_breakage() { @@ -1297,27 +1265,51 @@ impl DiagCtxtInner { self.future_breakage_diagnostics.push(diagnostic.clone()); } - if let Some(expectation_id) = diagnostic.level.get_expectation_id() { - self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id.normalize()); + if matches!(diagnostic.level, DelayedBug | GoodPathDelayedBug) + && self.flags.eagerly_emit_delayed_bugs + { + diagnostic.level = Error; } - if diagnostic.level == Warning && !self.flags.can_emit_warnings { - if diagnostic.has_future_breakage() { + match diagnostic.level { + // This must come after the possible promotion of `DelayedBug`/`GoodPathDelayedBug` to + // `Error` above. + Fatal | Error if self.treat_next_err_as_bug() => { + diagnostic.level = Bug; + } + DelayedBug => { + // FIXME(eddyb) this should check for `has_errors` and stop pushing + // once *any* errors were emitted (and truncate `delayed_bugs` + // when an error is first emitted, also), but maybe there's a case + // in which that's not sound? otherwise this is really inefficient. + let backtrace = std::backtrace::Backtrace::capture(); + self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); + #[allow(deprecated)] + return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + } + GoodPathDelayedBug => { + let backtrace = std::backtrace::Backtrace::capture(); + self.good_path_delayed_bugs + .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); + return None; + } + Warning if !self.flags.can_emit_warnings => { + if diagnostic.has_future_breakage() { + (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); + } + return None; + } + Allow | Expect(_) => { (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); + return None; } - return None; - } - - if matches!(diagnostic.level, Expect(_) | Allow) { - (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); - return None; + _ => {} } let mut guaranteed = None; (*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| { - if let Some(ref code) = diagnostic.code { - self.emitted_diagnostic_codes.insert(code.clone()); + if let Some(code) = diagnostic.code { + self.emitted_diagnostic_codes.insert(code); } let already_emitted = { @@ -1327,11 +1319,15 @@ impl DiagCtxtInner { !self.emitted_diagnostics.insert(diagnostic_hash) }; + let is_error = diagnostic.is_error(); + let is_lint = diagnostic.is_lint.is_some(); + // Only emit the diagnostic if we've been asked to deduplicate or // haven't already emitted an equivalent diagnostic. if !(self.flags.deduplicate_diagnostics && already_emitted) { debug!(?diagnostic); debug!(?self.emitted_diagnostics); + let already_emitted_sub = |sub: &mut SubDiagnostic| { debug!(?sub); if sub.level != OnceNote && sub.level != OnceHelp { @@ -1343,7 +1339,6 @@ impl DiagCtxtInner { debug!(?diagnostic_hash); !self.emitted_diagnostics.insert(diagnostic_hash) }; - diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); if already_emitted { diagnostic.note( @@ -1351,16 +1346,17 @@ impl DiagCtxtInner { ); } - self.emitter.emit_diagnostic(&diagnostic); - if diagnostic.is_error() { + if is_error { self.deduplicated_err_count += 1; } else if matches!(diagnostic.level, ForceWarning(_) | Warning) { self.deduplicated_warn_count += 1; } self.has_printed = true; + + self.emitter.emit_diagnostic(diagnostic); } - if diagnostic.is_error() { - if diagnostic.is_lint.is_some() { + if is_error { + if is_lint { self.lint_err_count += 1; } else { self.err_count += 1; @@ -1399,12 +1395,12 @@ impl DiagCtxtInner { fn flush_delayed(&mut self, kind: DelayedBugKind) { let (bugs, note1) = match kind { DelayedBugKind::Normal => ( - std::mem::take(&mut self.span_delayed_bugs), - "no errors encountered even though `span_delayed_bug` issued", + std::mem::take(&mut self.delayed_bugs), + "no errors encountered even though delayed bugs were created", ), DelayedBugKind::GoodPath => ( std::mem::take(&mut self.good_path_delayed_bugs), - "no warnings or errors encountered even though `good_path_delayed_bugs` issued", + "no warnings or errors encountered even though good path delayed bugs were created", ), }; let note2 = "those delayed bugs will now be shown as internal compiler errors"; @@ -1423,7 +1419,7 @@ impl DiagCtxtInner { &mut out, "delayed span bug: {}\n{}\n", bug.inner - .messages() + .messages .iter() .filter_map(|(msg, _)| msg.as_str()) .collect::(), @@ -1443,8 +1439,8 @@ impl DiagCtxtInner { let mut bug = if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner }; - // "Undelay" the `DelayedBug`s (into plain `Bug`s). - if !matches!(bug.level, DelayedBug(_)) { + // "Undelay" the delayed bugs (into plain `Bug`s). + if !matches!(bug.level, DelayedBug | GoodPathDelayedBug) { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel { @@ -1510,35 +1506,59 @@ impl DelayedDiagnostic { } } +/// Level is_error EmissionGuarantee Top-level Sub Used in lints? +/// ----- -------- ----------------- --------- --- -------------- +/// Bug yes BugAbort yes - - +/// Fatal yes FatalAbort/FatalError(*) yes - - +/// Error yes ErrorGuaranteed yes - yes +/// DelayedBug yes ErrorGuaranteed yes - - +/// GoodPathDelayedBug - () yes - - +/// ForceWarning - () yes - lint-only +/// Warning - () yes yes yes +/// Note - () rare yes - +/// OnceNote - () - yes lint-only +/// Help - () rare yes - +/// OnceHelp - () - yes lint-only +/// FailureNote - () rare - - +/// Allow - () yes - lint-only +/// Expect - () yes - lint-only +/// +/// (*) `FatalAbort` normally, `FatalError` in the non-aborting "almost fatal" case that is +/// occasionally used. +/// #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] pub enum Level { /// For bugs in the compiler. Manifests as an ICE (internal compiler error) panic. - /// - /// Its `EmissionGuarantee` is `BugAbort`. Bug, - /// This is a strange one: lets you register an error without emitting it. If compilation ends - /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be - /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths - /// that should only be reached when compiling erroneous code. - /// - /// Its `EmissionGuarantee` is `ErrorGuaranteed` for `Normal` delayed bugs, and `()` for - /// `GoodPath` delayed bugs. - DelayedBug(DelayedBugKind), - /// An error that causes an immediate abort. Used for things like configuration errors, /// internal overflows, some file operation errors. - /// - /// Its `EmissionGuarantee` is `FatalAbort`, except in the non-aborting "almost fatal" case - /// that is occasionally used, where it is `FatalError`. Fatal, /// An error in the code being compiled, which prevents compilation from finishing. This is the /// most common case. - /// - /// Its `EmissionGuarantee` is `ErrorGuaranteed`. Error, + /// This is a strange one: lets you register an error without emitting it. If compilation ends + /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be + /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths + /// that should only be reached when compiling erroneous code. + DelayedBug, + + /// Like `DelayedBug`, but weaker: lets you register an error without emitting it. If + /// compilation ends without any other diagnostics being emitted (and without an expected lint + /// being suppressed), this will be emitted as a bug. Otherwise, it will be silently dropped. + /// I.e. "expect other diagnostics are emitted (or suppressed)" semantics. Useful on code paths + /// that should only be reached when emitting diagnostics, e.g. for expensive one-time + /// diagnostic formatting operations. + /// + /// FIXME(nnethercote) good path delayed bugs are semantically strange: if printed they produce + /// an ICE, but they don't satisfy `is_error` and they don't guarantee an error is emitted. + /// Plus there's the extra complication with expected (suppressed) lints. They have limited + /// use, and are used in very few places, and "good path" isn't a good name. It would be good + /// to remove them. + GoodPathDelayedBug, + /// A `force-warn` lint warning about the code being compiled. Does not prevent compilation /// from finishing. /// @@ -1547,45 +1567,28 @@ pub enum Level { ForceWarning(Option), /// A warning about the code being compiled. Does not prevent compilation from finishing. - /// - /// Its `EmissionGuarantee` is `()`. Warning, - /// A message giving additional context. Rare, because notes are more commonly attached to other - /// diagnostics such as errors. - /// - /// Its `EmissionGuarantee` is `()`. + /// A message giving additional context. Note, - /// A note that is only emitted once. Rare, mostly used in circumstances relating to lints. - /// - /// Its `EmissionGuarantee` is `()`. + /// A note that is only emitted once. OnceNote, - /// A message suggesting how to fix something. Rare, because help messages are more commonly - /// attached to other diagnostics such as errors. - /// - /// Its `EmissionGuarantee` is `()`. + /// A message suggesting how to fix something. Help, - /// A help that is only emitted once. Rare. - /// - /// Its `EmissionGuarantee` is `()`. + /// A help that is only emitted once. OnceHelp, - /// Similar to `Note`, but used in cases where compilation has failed. Rare. - /// - /// Its `EmissionGuarantee` is `()`. + /// Similar to `Note`, but used in cases where compilation has failed. When printed for human + /// consumption, it doesn't have any kind of `note:` label. FailureNote, /// Only used for lints. - /// - /// Its `EmissionGuarantee` is `()`. Allow, /// Only used for lints. - /// - /// Its `EmissionGuarantee` is `()`. Expect(LintExpectationId), } @@ -1599,7 +1602,7 @@ impl Level { fn color(self) -> ColorSpec { let mut spec = ColorSpec::new(); match self { - Bug | DelayedBug(_) | Fatal | Error => { + Bug | Fatal | Error | DelayedBug | GoodPathDelayedBug => { spec.set_fg(Some(Color::Red)).set_intense(true); } ForceWarning(_) | Warning => { @@ -1619,7 +1622,7 @@ impl Level { pub fn to_str(self) -> &'static str { match self { - Bug | DelayedBug(_) => "error: internal compiler error", + Bug | DelayedBug | GoodPathDelayedBug => "error: internal compiler error", Fatal | Error => "error", ForceWarning(_) | Warning => "warning", Note | OnceNote => "note", @@ -1639,6 +1642,19 @@ impl Level { _ => None, } } + + // Can this level be used in a top-level diagnostic message and/or a + // subdiagnostic message? + fn can_be_top_or_sub(&self) -> (bool, bool) { + match self { + Bug | DelayedBug | Fatal | Error | GoodPathDelayedBug | ForceWarning(_) + | FailureNote | Allow | Expect(_) => (true, false), + + Warning | Note | Help => (true, true), + + OnceNote | OnceHelp => (false, true), + } + } } // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite. diff --git a/compiler/rustc_errors/src/registry.rs b/compiler/rustc_errors/src/registry.rs index f26d8e7ebdc34..8834d04d9718b 100644 --- a/compiler/rustc_errors/src/registry.rs +++ b/compiler/rustc_errors/src/registry.rs @@ -1,3 +1,4 @@ +use crate::ErrCode; use rustc_data_structures::fx::FxHashMap; #[derive(Debug)] @@ -5,17 +6,17 @@ pub struct InvalidErrorCode; #[derive(Clone)] pub struct Registry { - long_descriptions: FxHashMap<&'static str, &'static str>, + long_descriptions: FxHashMap, } impl Registry { - pub fn new(long_descriptions: &[(&'static str, &'static str)]) -> Registry { + pub fn new(long_descriptions: &[(ErrCode, &'static str)]) -> Registry { Registry { long_descriptions: long_descriptions.iter().copied().collect() } } /// Returns `InvalidErrorCode` if the code requested does not exist in the /// registry. - pub fn try_find_description(&self, code: &str) -> Result<&'static str, InvalidErrorCode> { - self.long_descriptions.get(code).copied().ok_or(InvalidErrorCode) + pub fn try_find_description(&self, code: ErrCode) -> Result<&'static str, InvalidErrorCode> { + self.long_descriptions.get(&code).copied().ok_or(InvalidErrorCode) } } diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index 98eb70b5fceee..b55f78538852a 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -197,7 +197,7 @@ pub struct StyledString { pub style: Style, } -#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] pub enum Style { MainHeaderMsg, HeaderMsg, diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index ed35eb1b6c4ad..5bdac367d55e7 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -12,9 +12,9 @@ use std::error::Report; /// /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then /// passed around as a reference thereafter. -pub fn to_fluent_args<'iter, 'arg: 'iter>( - iter: impl Iterator>, -) -> FluentArgs<'arg> { +pub fn to_fluent_args<'iter>( + iter: impl Iterator>, +) -> FluentArgs<'static> { let mut args = if let Some(size) = iter.size_hint().1 { FluentArgs::with_capacity(size) } else { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 29b70f33a6c7d..657e19277a7ed 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -796,9 +796,15 @@ impl SyntaxExtension { /// | external | no | if-ext | if-ext | yes | /// | yes | yes | yes | yes | yes | fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool { - let collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) + let mut collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) .map(|v| Self::collapse_debuginfo_by_name(sess, v)) .unwrap_or(CollapseMacroDebuginfo::Unspecified); + if collapse_debuginfo_attr == CollapseMacroDebuginfo::Unspecified + && attr::contains_name(attrs, sym::rustc_builtin_macro) + { + collapse_debuginfo_attr = CollapseMacroDebuginfo::Yes; + } + let flag = sess.opts.unstable_opts.collapse_macro_debuginfo; let attr = collapse_debuginfo_attr; let ext = !is_local; diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index f9bfebee12e92..5879e025e7dbd 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -141,6 +141,7 @@ impl<'a> ExtCtxt<'a> { } else { ast::BoundConstness::Never }, + asyncness: ast::BoundAsyncness::Normal, }, ) } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index f574e81e90513..781186764fa32 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -373,7 +373,9 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if self.features.is_some_and(|features| !features.stmt_expr_attributes) { + if self.features.is_some_and(|features| !features.stmt_expr_attributes) + && !attr.span.allows_unstable(sym::stmt_expr_attributes) + { let mut err = feature_err( &self.sess, sym::stmt_expr_attributes, diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 4a1c00f0104fd..2584ff62e98e6 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -1,4 +1,5 @@ use rustc_ast::ast; +use rustc_errors::codes::*; use rustc_macros::Diagnostic; use rustc_session::Limit; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; @@ -175,7 +176,7 @@ pub(crate) struct TakesNoArguments<'a> { } #[derive(Diagnostic)] -#[diag(expand_feature_removed, code = "E0557")] +#[diag(expand_feature_removed, code = E0557)] pub(crate) struct FeatureRemoved<'a> { #[primary_span] #[label] @@ -191,7 +192,7 @@ pub(crate) struct FeatureRemovedReason<'a> { } #[derive(Diagnostic)] -#[diag(expand_feature_not_allowed, code = "E0725")] +#[diag(expand_feature_not_allowed, code = E0725)] pub(crate) struct FeatureNotAllowed { #[primary_span] pub span: Span, @@ -210,7 +211,7 @@ pub(crate) struct RecursionLimitReached<'a> { } #[derive(Diagnostic)] -#[diag(expand_malformed_feature_attribute, code = "E0556")] +#[diag(expand_malformed_feature_attribute, code = E0556)] pub(crate) struct MalformedFeatureAttribute { #[primary_span] pub span: Span, @@ -347,7 +348,7 @@ pub(crate) struct ModuleInBlockName { } #[derive(Diagnostic)] -#[diag(expand_module_file_not_found, code = "E0583")] +#[diag(expand_module_file_not_found, code = E0583)] #[help] #[note] pub(crate) struct ModuleFileNotFound { @@ -359,7 +360,7 @@ pub(crate) struct ModuleFileNotFound { } #[derive(Diagnostic)] -#[diag(expand_module_multiple_candidates, code = "E0761")] +#[diag(expand_module_multiple_candidates, code = E0761)] #[help] pub(crate) struct ModuleMultipleCandidates { #[primary_span] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index bed667048c855..2cf6a8df7c5ff 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -9,9 +9,7 @@ #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] -#![feature(rustc_attrs)] #![feature(try_blocks)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![allow(internal_features)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 1a39708ed8ed8..83e0f870c8a25 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -485,7 +485,9 @@ pub fn compile_declarative_macro( ) .pop() .unwrap(); - valid &= check_lhs_nt_follows(sess, def, &tt); + // We don't handle errors here, the driver will abort + // after parsing/expansion. we can report every error in every macro this way. + valid &= check_lhs_nt_follows(sess, def, &tt).is_ok(); return tt; } sess.dcx().span_bug(def.span, "wrong-structured lhs") @@ -589,18 +591,19 @@ pub fn compile_declarative_macro( (mk_syn_ext(expander), rule_spans) } -fn check_lhs_nt_follows(sess: &Session, def: &ast::Item, lhs: &mbe::TokenTree) -> bool { +fn check_lhs_nt_follows( + sess: &Session, + def: &ast::Item, + lhs: &mbe::TokenTree, +) -> Result<(), ErrorGuaranteed> { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let mbe::TokenTree::Delimited(.., delimited) = lhs { check_matcher(sess, def, &delimited.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; - sess.dcx().span_err(lhs.span(), msg); - false + Err(sess.dcx().span_err(lhs.span(), msg)) } - // we don't abort on errors on rejection, the driver will do that for us - // after parsing/expansion. we can report every error in every macro this way. } fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool { @@ -675,12 +678,15 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> bool { false } -fn check_matcher(sess: &Session, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool { +fn check_matcher( + sess: &Session, + def: &ast::Item, + matcher: &[mbe::TokenTree], +) -> Result<(), ErrorGuaranteed> { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); - let err = sess.dcx().err_count(); - check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix); - err == sess.dcx().err_count() + check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?; + Ok(()) } fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool { @@ -1020,11 +1026,13 @@ fn check_matcher_core<'tt>( first_sets: &FirstSets<'tt>, matcher: &'tt [mbe::TokenTree], follow: &TokenSet<'tt>, -) -> TokenSet<'tt> { +) -> Result, ErrorGuaranteed> { use mbe::TokenTree; let mut last = TokenSet::empty(); + let mut errored = Ok(()); + // 2. For each token and suffix [T, SUFFIX] in M: // ensure that T can be followed by SUFFIX, and if SUFFIX may be empty, // then ensure T can also be followed by any element of FOLLOW. @@ -1068,7 +1076,7 @@ fn check_matcher_core<'tt>( token::CloseDelim(d.delim), span.close, )); - check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix); + check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?; // don't track non NT tokens last.replace_with_irrelevant(); @@ -1100,7 +1108,7 @@ fn check_matcher_core<'tt>( // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix); + let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?; if next.maybe_empty { last.add_all(&next); } else { @@ -1206,14 +1214,15 @@ fn check_matcher_core<'tt>( )); } } - err.emit(); + errored = Err(err.emit()); } } } } } } - last + errored?; + Ok(last) } fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index e3dc73d0d851f..3ca0787ce8e1f 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -124,7 +124,7 @@ fn parse_depth<'sess>( }; if let Ok(lit_kind) = LitKind::from_token_lit(*lit) && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind - && let Ok(n_usize) = usize::try_from(n_u128) + && let Ok(n_usize) = usize::try_from(n_u128.get()) { Ok(n_usize) } else { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 6e3996b45099e..1155366db85e3 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -339,9 +339,6 @@ declare_features! ( /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (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, "1.76.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 68b6f69854dd6..019cc1c847e91 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -440,9 +440,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(optimize), ), - gated!( - ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice) - ), gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)), gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)), gated!( diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 67ee53d8ae53f..040892df4c3be 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -32,6 +32,8 @@ declare_features! ( // feature-group-start: removed features // ------------------------------------------------------------------------- + /// Allows using the `amdgpu-kernel` ABI. + (removed, abi_amdgpu_kernel, "CURRENT_RUSTC_VERSION", Some(51575), None), (removed, advanced_slice_patterns, "1.0.0", Some(62254), Some("merged into `#![feature(slice_patterns)]`")), (removed, allocator, "1.0.0", None, None), @@ -95,6 +97,9 @@ declare_features! ( /// Allows `#[doc(include = "some-file")]`. (removed, external_doc, "1.54.0", Some(44732), Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")), + /// Allows using `#[ffi_returns_twice]` on foreign functions. + (removed, ffi_returns_twice, "CURRENT_RUSTC_VERSION", Some(58314), + Some("being investigated by the ffi-unwind project group")), /// Allows generators to be cloned. (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")), /// Allows defining generators. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2f2b551e6ecf7..1fb91ff8bbc92 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -321,8 +321,6 @@ declare_features! ( // feature-group-start: actual feature gates // ------------------------------------------------------------------------- - /// Allows using the `amdgpu-kernel` ABI. - (unstable, abi_amdgpu_kernel, "1.29.0", Some(51575)), /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), /// Allows `extern "C-cmse-nonsecure-call" fn()`. @@ -467,8 +465,6 @@ declare_features! ( (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. (unstable, ffi_pure, "1.45.0", Some(58329)), - /// Allows using `#[ffi_returns_twice]` on foreign functions. - (unstable, ffi_returns_twice, "1.34.0", Some(58314)), /// Allows using `#[repr(align(...))]` on function items (unstable, fn_align, "1.53.0", Some(82232)), /// Support delegating implementation of functions to other already implemented functions. @@ -498,7 +494,7 @@ declare_features! ( /// Allow anonymous constants from an inline `const` block (unstable, inline_const, "1.49.0", Some(76001)), /// Allow anonymous constants from an inline `const` block in pattern position - (incomplete, inline_const_pat, "1.58.0", Some(76001)), + (unstable, inline_const_pat, "1.58.0", Some(76001)), /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), // Allows setting the threshold for the `large_assignments` lint. @@ -516,6 +512,9 @@ declare_features! ( (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. (unstable, marker_trait_attr, "1.30.0", Some(29864)), + /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are + /// unambiguously sound. + (incomplete, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)), /// A minimal, sound subset of specialization intended to be used by the /// standard library until the soundness issues with specialization /// are fixed. @@ -549,7 +548,9 @@ declare_features! ( /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)), /// Allows using enums in offset_of! - (unstable, offset_of_enum, "1.75.0", Some(106655)), + (unstable, offset_of_enum, "1.75.0", Some(120141)), + /// Allows using multiple nested field accesses in offset_of! + (unstable, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows macro attributes on expressions, statements and non-inline modules. @@ -582,6 +583,9 @@ declare_features! ( (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. (unstable, trait_alias, "1.24.0", Some(41517)), + /// Allows dyn upcasting trait objects via supertraits. + /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. + (unstable, trait_upcasting, "1.56.0", Some(65991)), /// Allows for transmuting between arrays with sizes that contain generic consts. (unstable, transmute_generic_consts, "1.70.0", Some(109929)), /// Allows #[repr(transparent)] on unions (RFC 2645). diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ec5f72cd664ce..ff50086ff8f98 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -248,7 +248,7 @@ pub struct InferArg { } impl InferArg { - pub fn to_ty(&self) -> Ty<'_> { + pub fn to_ty(&self) -> Ty<'static> { Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id } } } @@ -894,34 +894,23 @@ impl<'tcx> OwnerInfo<'tcx> { } #[derive(Copy, Clone, Debug, HashStable_Generic)] -pub enum MaybeOwner { - Owner(T), +pub enum MaybeOwner<'tcx> { + Owner(&'tcx OwnerInfo<'tcx>), NonOwner(HirId), /// Used as a placeholder for unused LocalDefId. Phantom, } -impl MaybeOwner { - pub fn as_owner(self) -> Option { +impl<'tcx> MaybeOwner<'tcx> { + pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> { match self { MaybeOwner::Owner(i) => Some(i), MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None, } } - pub fn map(self, f: impl FnOnce(T) -> U) -> MaybeOwner { - match self { - MaybeOwner::Owner(i) => MaybeOwner::Owner(f(i)), - MaybeOwner::NonOwner(hir_id) => MaybeOwner::NonOwner(hir_id), - MaybeOwner::Phantom => MaybeOwner::Phantom, - } - } - - pub fn unwrap(self) -> T { - match self { - MaybeOwner::Owner(i) => i, - MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => panic!("Not a HIR owner"), - } + pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> { + self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner")) } } @@ -933,7 +922,7 @@ impl MaybeOwner { /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #[derive(Debug)] pub struct Crate<'hir> { - pub owners: IndexVec>>, + pub owners: IndexVec>, // Only present when incr. comp. is enabled. pub opt_hir_hash: Option, } @@ -963,6 +952,11 @@ pub enum ClosureKind { /// usage (e.g. `let x = || { yield (); }`) or from a desugared expression /// (e.g. `async` and `gen` blocks). Coroutine(CoroutineKind), + /// This is a coroutine-closure, which is a special sugared closure that + /// returns one of the sugared coroutine (`async`/`gen`/`async gen`). It + /// additionally allows capturing the coroutine's upvars by ref, and therefore + /// needs to be specially treated during analysis and borrowck. + CoroutineClosure(CoroutineDesugaring), } /// A block of statements `{ .. }`, which may have a label (in this case the @@ -1273,7 +1267,6 @@ pub struct Arm<'hir> { /// desugaring to if-let. Only let-else supports the type annotation at present. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Let<'hir> { - pub hir_id: HirId, pub span: Span, pub pat: &'hir Pat<'hir>, pub ty: Option<&'hir Ty<'hir>>, @@ -1532,14 +1525,16 @@ pub type Lit = Spanned; #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum ArrayLen { - Infer(HirId, Span), + Infer(InferArg), Body(AnonConst), } impl ArrayLen { pub fn hir_id(&self) -> HirId { match self { - &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, .. }) => hir_id, + ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => { + *hir_id + } } } } @@ -2424,7 +2419,7 @@ impl<'hir> Ty<'hir> { TyKind::Infer => true, TyKind::Slice(ty) => ty.is_suggestable_infer_ty(), TyKind::Array(ty, length) => { - ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _)) + ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(..)) } TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), @@ -3708,6 +3703,7 @@ impl<'hir> Node<'hir> { expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n; expect_crate, &'hir Mod<'hir>, Node::Crate(n), n; expect_infer, &'hir InferArg, Node::Infer(n), n; + expect_closure, &'hir Closure<'hir>, Node::Expr(Expr { kind: ExprKind::Closure(n), .. }), n; } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 116de6fb04d99..27c834d848fc4 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -341,9 +341,6 @@ pub trait Visitor<'v>: Sized { fn visit_expr(&mut self, ex: &'v Expr<'v>) { walk_expr(self, ex) } - fn visit_let_expr(&mut self, lex: &'v Let<'v>) { - walk_let_expr(self, lex) - } fn visit_expr_field(&mut self, field: &'v ExprField<'v>) { walk_expr_field(self, field) } @@ -672,7 +669,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<' pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { match len { - &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id), + ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id), ArrayLen::Body(c) => visitor.visit_anon_const(c), } } @@ -729,7 +726,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::DropTemps(ref subexpression) => { visitor.visit_expr(subexpression); } - ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr), + ExprKind::Let(Let { span: _, pat, ty, init, is_recovered: _ }) => { + // match the visit order in walk_local + visitor.visit_expr(init); + visitor.visit_pat(pat); + walk_list!(visitor, visit_ty, ty); + } ExprKind::If(ref cond, ref then, ref else_opt) => { visitor.visit_expr(cond); visitor.visit_expr(then); @@ -806,14 +808,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) } } -pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) { - // match the visit order in walk_local - visitor.visit_expr(let_expr.init); - visitor.visit_id(let_expr.hir_id); - visitor.visit_pat(let_expr.pat); - walk_list!(visitor, visit_ty, let_expr.ty); -} - pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) { visitor.visit_id(field.hir_id); visitor.visit_ident(field.ident); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 1cc1f11b3c858..9c9e72d6e6512 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -143,8 +143,6 @@ language_item_table! { Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; - /// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize). - StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait, GenericRequirement::None; Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); @@ -208,13 +206,21 @@ language_item_table! { FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnKindHelper, sym::async_fn_kind_helper,async_fn_kind_helper, Target::Trait, GenericRequirement::Exact(1); + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); + CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); + CoroutineResume, sym::coroutine_resume, coroutine_resume, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 87de3c0870bc9..6c64d802e68f1 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -9,7 +9,6 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(variant_count)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 432c9c12cbfbc..54d0fb6ffab72 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -434,6 +434,17 @@ hir_analysis_unused_associated_type_bounds = .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. .suggestion = remove this bound +hir_analysis_unused_generic_parameter = + {$param_def_kind} `{$param_name}` is never used + .label = unused {$param_def_kind} + .const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead +hir_analysis_unused_generic_parameter_adt_help = + consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}` +hir_analysis_unused_generic_parameter_adt_no_phantom_data_help = + consider removing `{$param_name}` or referring to it in a field +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_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 diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 2ad96a2489124..e37119e7d4dc8 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -28,6 +28,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { let tcx = self.tcx(); let sized_def_id = tcx.lang_items().sized_trait(); let mut seen_negative_sized_bound = false; + let mut seen_positive_sized_bound = false; // Try to find an unbound in bounds. let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); @@ -45,6 +46,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { seen_negative_sized_bound = true; } } + hir::TraitBoundModifier::None => { + if let Some(sized_def_id) = sized_def_id + && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) + { + seen_positive_sized_bound = true; + } + } _ => {} } } @@ -82,11 +90,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); } - if seen_sized_unbound || seen_negative_sized_bound { - // There was in fact a `?Sized` or `!Sized` bound; + if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound { + // There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound; // we don't need to do anything. } else if sized_def_id.is_some() { - // There was no `?Sized` or `!Sized` bound; + // There was no `?Sized`, `!Sized` or explicit `Sized` bound; // add `Sized` if it's available. bounds.push_sized(tcx, self_ty, span); } @@ -108,14 +116,16 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` /// for more details. #[instrument(level = "debug", skip(self, ast_bounds, bounds))] - pub(crate) fn add_bounds<'hir, I: Iterator>>( + pub(crate) fn add_bounds<'hir, I: Iterator>>( &self, param_ty: Ty<'tcx>, ast_bounds: I, bounds: &mut Bounds<'tcx>, bound_vars: &'tcx ty::List, only_self_bounds: OnlySelfBounds, - ) { + ) where + 'tcx: 'hir, + { for ast_bound in ast_bounds { match ast_bound { hir::GenericBound::Trait(poly_trait_ref, modifier) => { @@ -179,7 +189,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { pub(crate) fn compute_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], + ast_bounds: &[hir::GenericBound<'tcx>], filter: PredicateFilter, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); @@ -327,7 +337,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } let projection_ty = if let ty::AssocKind::Fn = assoc_kind { - let mut emitted_bad_param_err = false; + let mut emitted_bad_param_err = None; // If we have an method return type bound, then we need to substitute // the method's early bound params with suitable late-bound params. let mut num_bound_vars = candidate.bound_vars().len(); @@ -344,46 +354,30 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ) .into(), ty::GenericParamDefKind::Type { .. } => { - if !emitted_bad_param_err { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { tcx.dcx().emit_err( crate::errors::ReturnTypeNotationIllegalParam::Type { span: path_span, param_span: tcx.def_span(param.def_id), }, - ); - emitted_bad_param_err = true; - } - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundTyKind::Param(param.def_id, param.name), - }, - ) - .into() + ) + }); + Ty::new_error(tcx, guar).into() } ty::GenericParamDefKind::Const { .. } => { - if !emitted_bad_param_err { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { tcx.dcx().emit_err( crate::errors::ReturnTypeNotationIllegalParam::Const { span: path_span, param_span: tcx.def_span(param.def_id), }, - ); - emitted_bad_param_err = true; - } + ) + }); let ty = tcx .type_of(param.def_id) .no_bound_vars() .expect("ct params cannot have early bound vars"); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(num_bound_vars), - ty, - ) - .into() + ty::Const::new_error(tcx, guar, ty).into() } }; num_bound_vars += 1; diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index bfe88df4e1a55..3c64b102bae8d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -6,11 +6,15 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::traits::error_reporting::report_object_safety_error; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{ + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, +}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; +use rustc_middle::query::Key; use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; @@ -244,7 +248,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_suggestion_verbose( assoc_name.span, fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, - suggested_name.to_string(), + suggested_name, Applicability::MaybeIncorrect, ); } @@ -461,22 +465,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return err.emit(); } - let mut bound_spans = Vec::new(); + let mut bound_spans: SortedMap> = Default::default(); let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { - let msg = format!( - "doesn't satisfy `{}`", - if obligation.len() > 50 { quiet } else { obligation } - ); + let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation }); match &self_ty.kind() { // Point at the type that couldn't satisfy the bound. - ty::Adt(def, _) => bound_spans.push((tcx.def_span(def.did()), msg)), + ty::Adt(def, _) => { + bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) + } // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { - bound_spans.push((tcx.def_span(tr.def_id), msg.clone())) + bound_spans + .get_mut_or_insert_default(tcx.def_span(tr.def_id)) + .push(msg.clone()); } ty::ExistentialPredicate::Projection(_) | ty::ExistentialPredicate::AutoTrait(_) => {} @@ -485,7 +490,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => { - bound_spans.push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))) + bound_spans + .get_mut_or_insert_default(tcx.def_span(*def_id)) + .push(format!("`{quiet}`")); } _ => {} } @@ -554,12 +561,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") ); - bound_spans.sort(); - bound_spans.dedup(); - for (span, msg) in bound_spans { + for (span, mut bounds) in bound_spans { if !tcx.sess.source_map().is_span_accessible(span) { continue; } + bounds.sort(); + bounds.dedup(); + let msg = match &bounds[..] { + [bound] => format!("doesn't satisfy {bound}"), + bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()), + [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")), + [] => unreachable!(), + }; err.span_label(span, msg); } add_def_label(&mut err); @@ -847,6 +860,56 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.set_tainted_by_errors(err.emit()); } + + /// On ambiguous associated type, look for an associated function whose name matches the + /// extended path and, if found, emit an E0223 error with a structured suggestion. + /// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195) + pub(crate) fn maybe_report_similar_assoc_fn( + &self, + span: Span, + qself_ty: Ty<'tcx>, + qself: &hir::Ty<'_>, + ) -> Result<(), ErrorGuaranteed> { + let tcx = self.tcx(); + if let Some((_, node)) = tcx.hir().parent_iter(qself.hir_id).skip(1).next() + && let hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::TypeRelative( + hir::Ty { + kind: + hir::TyKind::Path(hir::QPath::TypeRelative( + _, + hir::PathSegment { ident: ident2, .. }, + )), + .. + }, + hir::PathSegment { ident: ident3, .. }, + )), + .. + }) = node + && let Some(ty_def_id) = qself_ty.ty_def_id() + && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id) + && let name = format!("{ident2}_{ident3}") + && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx + .associated_items(inherent_impl) + .filter_by_name_unhygienic(Symbol::intern(&name)) + .next() + { + let reported = + struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type") + .with_span_suggestion_verbose( + ident2.span.to(ident3.span), + format!("there is an associated function with a similar name: `{name}`"), + name, + Applicability::MaybeIncorrect, + ) + .emit(); + self.set_tainted_by_errors(reported); + Err(reported) + } else { + Ok(()) + } + } } /// Emits an error regarding forbidden type binding associations diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index e2cd4d5f21c76..30b10446afcc9 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -5,7 +5,9 @@ use crate::astconv::{ }; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -168,7 +170,7 @@ fn generic_arg_mismatch_err( /// instantiate a `GenericArg`. /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then /// creates a suitable inference variable. -pub fn create_args_for_parent_generic_args<'tcx, 'a>( +pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>( tcx: TyCtxt<'tcx>, def_id: DefId, parent_args: &[ty::GenericArg<'tcx>], @@ -656,7 +658,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); - tcx.struct_span_lint_hir( + tcx.node_span_lint( LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].hir_id(), multispan, diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index 3761d52951709..a6ac8ecd950ea 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -1,5 +1,5 @@ use rustc_ast::TraitObjectSyntax; -use rustc_errors::{Diagnostic, StashKey}; +use rustc_errors::{codes::*, Diagnostic, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; @@ -78,23 +78,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; - let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(sig, _), - generics, - .. - })) = tcx.hir_node_by_def_id(parent_id) - else { - return false; + let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { + (sig, generics, None) + } + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + generics, + owner_id, + .. + }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), + _ => return false, }; let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return false; }; let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())]; + let mut is_downgradable = true; let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|o| match o.trait_ref.path.res { - Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id), + Res::Def(DefKind::Trait, id) => { + if Some(id) == owner { + // For recursive traits, don't downgrade the error. (#119652) + is_downgradable = false; + } + tcx.check_is_object_safe(id) + } _ => false, }) } @@ -122,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ], Applicability::MachineApplicable, ); - } else { + } else if is_downgradable { // We'll emit the object safety error already, with a structured suggestion. diag.downgrade_to_delayed_bug(); } @@ -148,8 +158,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if !is_object_safe { diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); - // We'll emit the object safety error already, with a structured suggestion. - diag.downgrade_to_delayed_bug(); + if is_downgradable { + // We'll emit the object safety error already, with a structured suggestion. + diag.downgrade_to_delayed_bug(); + } } else { let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { // There are more than one trait bound, we need surrounding parentheses. @@ -228,24 +240,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { diag.stash(self_ty.span, StashKey::TraitMissingMethod); } else { let msg = "trait objects without an explicit `dyn` are deprecated"; - tcx.struct_span_lint_hir( - BARE_TRAIT_OBJECTS, - self_ty.hir_id, - self_ty.span, - msg, - |lint| { - if self_ty.span.can_be_used_for_suggestions() - && !self.maybe_lint_impl_trait(self_ty, lint) - { - lint.multipart_suggestion_verbose( - "use `dyn`", - sugg, - Applicability::MachineApplicable, - ); - } - self.maybe_lint_blanket_trait_impl(self_ty, lint); - }, - ); + tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| { + if self_ty.span.can_be_used_for_suggestions() { + lint.multipart_suggestion_verbose( + "use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + } + self.maybe_lint_blanket_trait_impl(self_ty, lint); + }); } } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index b9e72a3b1ea93..cfd38fb48f472 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - error_code, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, FatalError, MultiSpan, + codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + FatalError, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -122,7 +122,7 @@ pub trait AstConv<'tcx> { &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; @@ -156,14 +156,14 @@ struct ConvertedBinding<'a, 'tcx> { hir_id: hir::HirId, item_name: Ident, kind: ConvertedBindingKind<'a, 'tcx>, - gen_args: &'a GenericArgs<'a>, + gen_args: &'tcx GenericArgs<'tcx>, span: Span, } #[derive(Debug)] enum ConvertedBindingKind<'a, 'tcx> { Equality(Spanned>), - Constraint(&'a [hir::GenericBound<'a>]), + Constraint(&'a [hir::GenericBound<'tcx>]), } /// New-typed boolean indicating whether explicit late-bound lifetimes @@ -215,12 +215,12 @@ pub struct GenericArgCountResult { } pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { - fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool); + fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool); fn provided_kind( &mut self, param: &ty::GenericParamDef, - arg: &GenericArg<'_>, + arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx>; fn inferred_kind( @@ -294,7 +294,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, span: Span, def_id: DefId, - item_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'tcx>, ) -> GenericArgsRef<'tcx> { let (args, _) = self.create_args_for_ast_path( span, @@ -351,7 +351,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id: DefId, parent_args: &[ty::GenericArg<'tcx>], seg: &hir::PathSegment<'_>, - generic_args: &'a hir::GenericArgs<'_>, + generic_args: &'a hir::GenericArgs<'tcx>, infer_args: bool, self_ty: Option>, constness: ty::BoundConstness, @@ -406,14 +406,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { struct SubstsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, - generic_args: &'a GenericArgs<'a>, + generic_args: &'a GenericArgs<'tcx>, span: Span, inferred_params: Vec, infer_args: bool, } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { - fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) { + fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) { if did == self.def_id { (Some(self.generic_args), self.infer_args) } else { @@ -425,11 +425,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn provided_kind( &mut self, param: &ty::GenericParamDef, - arg: &GenericArg<'_>, + arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let tcx = self.astconv.tcx(); - let mut handle_ty_args = |has_default, ty: &hir::Ty<'_>| { + let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { if has_default { tcx.check_optional_stability( param.def_id, @@ -592,7 +592,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn create_assoc_bindings_for_generic_args<'a>( &self, - generic_args: &'a hir::GenericArgs<'_>, + generic_args: &'a hir::GenericArgs<'tcx>, ) -> Vec> { // Convert associated-type bindings or constraints into a separate vector. // Example: Given this: @@ -640,7 +640,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'tcx>, parent_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { debug!( @@ -673,7 +673,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// are disallowed. Otherwise, they are pushed onto the vector given. pub fn instantiate_mono_trait_ref( &self, - trait_ref: &hir::TraitRef<'_>, + trait_ref: &hir::TraitRef<'tcx>, self_ty: Ty<'tcx>, ) -> ty::TraitRef<'tcx> { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {}); @@ -710,7 +710,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))] pub(crate) fn instantiate_poly_trait_ref( &self, - trait_ref: &hir::TraitRef<'_>, + trait_ref: &hir::TraitRef<'tcx>, span: Span, constness: ty::BoundConstness, polarity: ty::ImplPolarity, @@ -788,7 +788,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, - trait_segment: &hir::PathSegment<'_>, + trait_segment: &hir::PathSegment<'tcx>, is_impl: bool, // FIXME(effects) move all host param things in astconv to hir lowering constness: ty::BoundConstness, @@ -813,7 +813,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, - trait_segment: &'a hir::PathSegment<'a>, + trait_segment: &'a hir::PathSegment<'tcx>, is_impl: bool, constness: ty::BoundConstness, ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) { @@ -847,7 +847,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, span: Span, did: DefId, - item_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx(); let args = self.ast_path_args_for_ty(span, did, item_segment); @@ -1072,9 +1072,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(binding) = binding && let ConvertedBindingKind::Equality(_) = binding.kind { - error_code!(E0222) + E0222 } else { - error_code!(E0221) + E0221 }, ); @@ -1153,7 +1153,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span: Span, qself_ty: Ty<'tcx>, qself: &hir::Ty<'_>, - assoc_segment: &hir::PathSegment<'_>, + assoc_segment: &hir::PathSegment<'tcx>, permit_variants: bool, ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> { let tcx = self.tcx(); @@ -1373,6 +1373,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .emit() // Already reported in an earlier stage. } else { + self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?; + let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); @@ -1394,7 +1396,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound); if let Some(variant_def_id) = variant_resolution { - tcx.struct_span_lint_hir( + tcx.node_span_lint( AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, @@ -1428,7 +1430,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn lookup_inherent_assoc_ty( &self, name: Ident, - segment: &hir::PathSegment<'_>, + segment: &hir::PathSegment<'tcx>, adt_did: DefId, self_ty: Ty<'tcx>, block: hir::HirId, @@ -1630,7 +1632,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let reported = tcx .dcx() .struct_span_err(span, msg) - .with_code(rustc_errors::error_code!(E0624)) + .with_code(E0624) .with_span_label(span, format!("private {kind}")) .with_span_label(def_span, format!("{kind} defined here")) .emit(); @@ -1702,8 +1704,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'_>, - item_segment: &hir::PathSegment<'_>, + trait_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'tcx>, constness: ty::BoundConstness, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2021,7 +2023,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn res_to_ty( &self, opt_self_ty: Option>, - path: &hir::Path<'_>, + path: &hir::Path<'tcx>, hir_id: hir::HirId, permit_variants: bool, ) -> Ty<'tcx> { @@ -2311,13 +2313,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Parses the programmer's textual representation of a type into our /// internal notion of a type. - pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { self.ast_ty_to_ty_inner(ast_ty, false, false) } /// Parses the programmer's textual representation of a type into our /// internal notion of a type. This is meant to be used within a path. - pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { self.ast_ty_to_ty_inner(ast_ty, false, true) } @@ -2432,7 +2434,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. #[instrument(level = "debug", skip(self), ret)] - fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> { + fn ast_ty_to_ty_inner( + &self, + ast_ty: &hir::Ty<'tcx>, + borrowed: bool, + in_path: bool, + ) -> Ty<'tcx> { let tcx = self.tcx(); let result_ty = match &ast_ty.kind { @@ -2524,7 +2531,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } hir::TyKind::Array(ty, length) => { let length = match length { - &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), + hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span), hir::ArrayLen::Body(constant) => { ty::Const::from_anon_const(tcx, constant.def_id) } @@ -2609,7 +2616,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> { + pub fn ty_of_arg(&self, ty: &hir::Ty<'tcx>, expected_ty: Option>) -> Ty<'tcx> { match ty.kind { hir::TyKind::Infer if expected_ty.is_some() => { self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span); @@ -2625,7 +2632,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir_id: hir::HirId, unsafety: hir::Unsafety, abi: abi::Abi, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, generics: Option<&hir::Generics<'_>>, hir_ty: Option<&hir::Ty<'_>>, ) -> ty::PolyFnSig<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index f77f250cd288e..2d85ad5789ecc 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -2,7 +2,7 @@ use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBou use crate::bounds::Bounds; use crate::errors::TraitObjectDeclaredWithNoTraits; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -22,7 +22,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, span: Span, hir_id: hir::HirId, - hir_trait_bounds: &[hir::PolyTraitRef<'_>], + hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], lifetime: &hir::Lifetime, borrowed: bool, representation: DynKind, @@ -220,7 +220,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let def_id = projection_bound.projection_def_id(); def_ids.remove(&def_id); if tcx.generics_require_sized_self(def_id) { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, hir_id, *span, diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 556560945e94f..5bc904e5930ce 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -12,7 +12,9 @@ use rustc_trait_selection::traits::StructurallyNormalizeExt; #[derive(Copy, Clone, Debug)] pub enum AutoderefKind { + /// A true pointer type, such as `&T` and `*mut T`. Builtin, + /// A type which must dispatch to a `Deref` implementation. Overloaded, } @@ -83,6 +85,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { (AutoderefKind::Builtin, ty) } } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. (AutoderefKind::Overloaded, ty) } else { return None; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 03e2b0e00220e..50809a571b8dc 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -5,7 +5,7 @@ use super::compare_impl_item::check_type_bounds; use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; use super::*; use rustc_attr as attr; -use rustc_errors::{ErrorGuaranteed, MultiSpan}; +use rustc_errors::{codes::*, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -31,6 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _}; use rustc_type_ir::fold::TypeFoldable; +use std::cell::LazyCell; use std::ops::ControlFlow; pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { @@ -46,7 +47,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { .emit(); } None => { - tcx.struct_span_lint_hir( + tcx.node_span_lint( UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, @@ -183,7 +184,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { } }; if layout.abi.is_uninhabited() { - tcx.struct_span_lint_hir( + tcx.node_span_lint( UNINHABITED_STATIC, tcx.local_def_id_to_hir_id(def_id), span, @@ -520,9 +521,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } DefKind::TyAlias => { - let pty_ty = tcx.type_of(def_id).instantiate_identity(); - let generics = tcx.generics_of(def_id); - check_type_params_are_used(tcx, generics, pty_ty); + check_type_alias_type_params_are_used(tcx, def_id); } DefKind::ForeignMod => { let it = tcx.hir().expect_item(def_id); @@ -1079,7 +1078,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. if non_trivial_count > 0 || prev_non_exhaustive_1zst { - tcx.struct_span_lint_hir( + tcx.node_span_lint( REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), span, @@ -1269,28 +1268,51 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } } -pub(super) fn check_type_params_are_used<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &ty::Generics, - ty: Ty<'tcx>, -) { - debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); - - assert_eq!(generics.parent, None); +fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { + if tcx.type_alias_is_lazy(def_id) { + // Since we compute the variances for lazy type aliases and already reject bivariant + // parameters as unused, we can and should skip this check for lazy type aliases. + return; + } + let generics = tcx.generics_of(def_id); if generics.own_counts().types == 0 { return; } - let mut params_used = BitSet::new_empty(generics.params.len()); - + let ty = tcx.type_of(def_id).instantiate_identity(); if ty.references_error() { - // If there is already another error, do not emit - // an error for not using a type parameter. + // If there is already another error, do not emit an error for not using a type parameter. assert!(tcx.dcx().has_errors().is_some()); return; } + // Lazily calculated because it is only needed in case of an error. + let bounded_params = LazyCell::new(|| { + tcx.explicit_predicates_of(def_id) + .predicates + .iter() + .filter_map(|(predicate, span)| { + let bounded_ty = match predicate.kind().skip_binder() { + ty::ClauseKind::Trait(pred) => pred.trait_ref.self_ty(), + ty::ClauseKind::TypeOutlives(pred) => pred.0, + _ => return None, + }; + if let ty::Param(param) = bounded_ty.kind() { + Some((param.index, span)) + } else { + None + } + }) + // FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the + // time of writing). This is a bit fragile since we later use the span to detect elaborated + // `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized` + // since it would overwrite the span of the user-written bound. This could be fixed by + // folding the spans with `Span::to` which requires a bit of effort I think. + .collect::>() + }); + + let mut params_used = BitSet::new_empty(generics.params.len()); for leaf in ty.walk() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && let ty::Param(param) = leaf_ty.kind() @@ -1305,15 +1327,24 @@ pub(super) fn check_type_params_are_used<'tcx>( && let ty::GenericParamDefKind::Type { .. } = param.kind { let span = tcx.def_span(param.def_id); - struct_span_code_err!( - tcx.dcx(), + let param_name = Ident::new(param.name, span); + + // The corresponding predicates are post-`Sized`-elaboration. Therefore we + // * check for emptiness to detect lone user-written `?Sized` bounds + // * compare the param span to the pred span to detect lone user-written `Sized` bounds + let has_explicit_bounds = bounded_params.is_empty() + || (*bounded_params).get(¶m.index).is_some_and(|&&pred_sp| pred_sp != span); + let const_param_help = (!has_explicit_bounds).then_some(()); + + let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter { span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .with_span_label(span, "unused type parameter") - .emit(); + param_name, + param_def_kind: tcx.def_descr(param.def_id), + help: errors::UnusedGenericParameterHelp::TyAlias { param_name }, + const_param_help, + }); + diag.code(E0091); + diag.emit(); } } } 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 5b264f6f034c9..379c1154e5f26 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2,7 +2,7 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -20,6 +20,7 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_span::Span; +use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -254,7 +255,7 @@ fn compare_method_predicate_entailment<'tcx>( // checks. For the comparison to be valid, we need to // normalize the associated types in the impl/trait methods // first. However, because function types bind regions, just - // calling `normalize_associated_types_in` would have no effect on + // calling `FnCtxt::normalize` would have no effect on // any associated types appearing in the fn arguments or return // type. @@ -1382,7 +1383,7 @@ fn compare_number_of_generics<'tcx>( kind = kind, ), ); - err.code("E0049".into()); + err.code(E0049); let msg = format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 0d8de0cabd1af..3d3b21eabb383 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_span::Span; +use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{ elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt, }; @@ -283,7 +284,7 @@ fn report_mismatched_rpitit_signature<'tcx>( }); let span = unmatched_bound.unwrap_or(span); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( REFINING_IMPL_TRAIT, tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()), span, diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 3275a81c3ddc7..7b60457affa82 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -2,12 +2,13 @@ // // We don't do any drop checking during hir typeck. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, TyCtxt}; +use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; use crate::errors; @@ -188,6 +189,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => { format!("{b}: {a}", a = ty::Region::new_var(tcx, a)) } + RegionResolutionError::CannotNormalize(..) => unreachable!(), }; guar = Some( struct_span_code_err!( diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 27bb2c57a5cb7..87a1f3d342580 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -88,7 +88,7 @@ fn handle_static_mut_ref( "shared ", ) }; - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( STATIC_MUT_REF, hir_id, span, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 3fa08b2e7b58b..401e89b342691 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -8,7 +8,7 @@ use crate::errors::{ }; use hir::def_id::DefId; -use rustc_errors::{struct_span_code_err, DiagnosticMessage}; +use rustc_errors::{codes::*, struct_span_code_err, DiagnosticMessage}; use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -455,6 +455,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::black_box => (1, vec![param(0)], param(0)), + sym::is_val_statically_known => (1, vec![param(0)], tcx.types.bool), + sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index db619d5169e42..d03b02f028da1 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -270,7 +270,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if !spans.is_empty() { let (default_modifier, default_result) = reg_class.default_modifier(asm_arch).unwrap(); - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( lint::builtin::ASM_SUB_REGISTER, expr.hir_id, spans, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 28c8f846c23a9..b74431983113a 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -578,7 +578,7 @@ pub fn check_function_signature<'tcx>( fn_id: LocalDefId, ) -> rustc_span::Span { let mut args = { - let node = tcx.hir().expect_owner(fn_id); + let node = tcx.expect_hir_owner_node(fn_id); let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node)); decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span())) }; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 58046173fb1a9..885cfbd0fe224 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1,19 +1,16 @@ use crate::autoderef::Autoderef; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; +use crate::errors; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; -use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; -use rustc_infer::infer::outlives::obligations::TypeOutlives; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_middle::mir::ConstraintCategory; use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -23,9 +20,10 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError, @@ -116,7 +114,7 @@ where let errors = wfcx.select_all_or_error(); if !errors.is_empty() { let err = infcx.err_ctxt().report_fulfillment_errors(errors); - if tcx.dcx().err_count() > 0 { + if tcx.dcx().has_errors().is_some() { return Err(err); } else { // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs @@ -189,7 +187,7 @@ where } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { - let node = tcx.hir().owner(def_id); + let node = tcx.hir_owner_node(def_id); let mut res = match node { hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), hir::OwnerNode::Item(item) => check_item(tcx, item), @@ -731,10 +729,12 @@ fn ty_known_to_outlive<'tcx>( ty: Ty<'tcx>, region: ty::Region<'tcx>, ) -> bool { - resolve_regions_with_wf_tys(tcx, id, param_env, wf_tys, |infcx, region_bound_pairs| { - let origin = infer::RelateParamBound(DUMMY_SP, ty, None); - let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env); - outlives.type_must_outlive(origin, ty, region, ConstraintCategory::BoringNoLocation); + test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { + infcx.register_region_obligation(infer::RegionObligation { + sub_region: region, + sup_type: ty, + origin: infer::RelateParamBound(DUMMY_SP, ty, None), + }); }) } @@ -748,40 +748,32 @@ fn region_known_to_outlive<'tcx>( region_a: ty::Region<'tcx>, region_b: ty::Region<'tcx>, ) -> bool { - resolve_regions_with_wf_tys(tcx, id, param_env, wf_tys, |mut infcx, _| { - use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; - let origin = infer::RelateRegionParamBound(DUMMY_SP); - // `region_a: region_b` -> `region_b <= region_a` - infcx.push_sub_region_constraint( - origin, - region_b, - region_a, - ConstraintCategory::BoringNoLocation, - ); + test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { + infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP), region_b, region_a); }) } /// Given a known `param_env` and a set of well formed types, set up an /// `InferCtxt`, call the passed function (to e.g. set up region constraints /// to be tested), then resolve region and return errors -fn resolve_regions_with_wf_tys<'tcx>( +fn test_region_obligations<'tcx>( tcx: TyCtxt<'tcx>, id: LocalDefId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxIndexSet>, - add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>), + add_constraints: impl FnOnce(&InferCtxt<'tcx>), ) -> bool { // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each // call individually. let infcx = tcx.infer_ctxt().build(); + + add_constraints(&infcx); + let outlives_environment = OutlivesEnvironment::with_bounds( param_env, infcx.implied_bounds_tys(param_env, id, wf_tys), ); - let region_bound_pairs = outlives_environment.region_bound_pairs(); - - add_constraints(&infcx, region_bound_pairs); let errors = infcx.resolve_regions(&outlives_environment); debug!(?errors, "errors"); @@ -1790,7 +1782,7 @@ fn receiver_is_implemented<'tcx>( fn check_variances_for_type_defn<'tcx>( tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, - hir_generics: &hir::Generics<'_>, + hir_generics: &hir::Generics<'tcx>, ) { let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id); @@ -1876,7 +1868,7 @@ fn check_variances_for_type_defn<'tcx>( hir::ParamName::Error => {} _ => { let has_explicit_bounds = explicitly_bounded_params.contains(¶meter); - report_bivariance(tcx, hir_param, has_explicit_bounds); + report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind); } } } @@ -1886,30 +1878,38 @@ fn report_bivariance( tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>, has_explicit_bounds: bool, + item_kind: ItemKind<'_>, ) -> ErrorGuaranteed { - let span = param.span; - let param_name = param.name.ident().name; - let mut err = error_392(tcx, span, param_name); - - let suggested_marker_id = tcx.lang_items().phantom_data(); - // Help is available only in presence of lang items. - let msg = if let Some(def_id) = suggested_marker_id { - format!( - "consider removing `{}`, referring to it in a field, or using a marker such as `{}`", - param_name, - tcx.def_path_str(def_id), - ) - } else { - format!("consider removing `{param_name}` or referring to it in a field") + let param_name = param.name.ident(); + + let help = match item_kind { + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { + if let Some(def_id) = tcx.lang_items().phantom_data() { + errors::UnusedGenericParameterHelp::Adt { + param_name, + phantom_data: tcx.def_path_str(def_id), + } + } else { + errors::UnusedGenericParameterHelp::AdtNoPhantomData { param_name } + } + } + ItemKind::TyAlias(..) => errors::UnusedGenericParameterHelp::TyAlias { param_name }, + item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"), }; - err.help(msg); - if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds { - err.help(format!( - "if you intended `{param_name}` to be a const parameter, use `const {param_name}: usize` instead" - )); - } - err.emit() + let const_param_help = + matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds) + .then_some(()); + + let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter { + span: param.span, + param_name, + param_def_kind: tcx.def_descr(param.def_id.to_def_id()), + help, + const_param_help, + }); + diag.code(E0392); + diag.emit() } impl<'tcx> WfCheckingCtxt<'_, 'tcx> { @@ -1974,11 +1974,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error res } -fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> { - struct_span_code_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used") - .with_span_label(span, "unused parameter") -} - pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 36cb8f7a20228..aa5db4f6aa7bb 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -40,12 +40,6 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { } else { "unused import".to_owned() }; - tcx.struct_span_lint_hir( - lint::builtin::UNUSED_IMPORTS, - item.hir_id(), - path.span, - msg, - |_| {}, - ); + tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, msg, |_| {}); } } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 8d362f74b0a26..5a3878445937b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -25,14 +25,21 @@ use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; use std::collections::BTreeMap; -pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { +pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> { let lang_items = tcx.lang_items(); - Checker { tcx, trait_def_id } - .check(lang_items.drop_trait(), visit_implementation_of_drop) - .check(lang_items.copy_trait(), visit_implementation_of_copy) - .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty) - .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized) - .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn); + let checker = Checker { tcx, trait_def_id }; + let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); + res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); + res = res.and( + checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty), + ); + res = res.and( + checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), + ); + res.and( + checker + .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), + ) } struct Checker<'tcx> { @@ -41,33 +48,40 @@ struct Checker<'tcx> { } impl<'tcx> Checker<'tcx> { - fn check(&self, trait_def_id: Option, mut f: F) -> &Self + fn check(&self, trait_def_id: Option, mut f: F) -> Result<(), ErrorGuaranteed> where - F: FnMut(TyCtxt<'tcx>, LocalDefId), + F: FnMut(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>, { + let mut res = Ok(()); if Some(self.trait_def_id) == trait_def_id { for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) { - f(self.tcx, impl_def_id); + res = res.and(f(self.tcx, impl_def_id)); } } - self + res } } -fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { +fn visit_implementation_of_drop( + tcx: TyCtxt<'_>, + impl_did: LocalDefId, +) -> Result<(), ErrorGuaranteed> { // Destructors only work on local ADT types. match tcx.type_of(impl_did).instantiate_identity().kind() { - ty::Adt(def, _) if def.did().is_local() => return, - ty::Error(_) => return, + ty::Adt(def, _) if def.did().is_local() => return Ok(()), + ty::Error(_) => return Ok(()), _ => {} } let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); - tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }); + Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span })) } -fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { +fn visit_implementation_of_copy( + tcx: TyCtxt<'_>, + impl_did: LocalDefId, +) -> Result<(), ErrorGuaranteed> { debug!("visit_implementation_of_copy: impl_did={:?}", impl_did); let self_type = tcx.type_of(impl_did).instantiate_identity(); @@ -79,59 +93,68 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); let span = match tcx.hir().expect_item(impl_did).expect_impl() { - hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return, + hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()), hir::Impl { self_ty, .. } => self_ty.span, }; let cause = traits::ObligationCause::misc(span, impl_did); match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { - Ok(()) => {} + Ok(()) => Ok(()), Err(CopyImplementationError::InfringingFields(fields)) => { - infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span); + Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span)) } Err(CopyImplementationError::NotAnAdt) => { - tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }); + Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span })) } Err(CopyImplementationError::HasDestructor) => { - tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }); + Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span })) } } } -fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) { +fn visit_implementation_of_const_param_ty( + tcx: TyCtxt<'_>, + impl_did: LocalDefId, +) -> Result<(), ErrorGuaranteed> { let self_type = tcx.type_of(impl_did).instantiate_identity(); assert!(!self_type.has_escaping_bound_vars()); let param_env = tcx.param_env(impl_did); let span = match tcx.hir().expect_item(impl_did).expect_impl() { - hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return, + hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()), impl_ => impl_.self_ty.span, }; let cause = traits::ObligationCause::misc(span, impl_did); match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { - Ok(()) => {} + Ok(()) => Ok(()), Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { - infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span); + Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span)) } Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => { - tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }); + Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span })) } } } -fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) { +fn visit_implementation_of_coerce_unsized( + tcx: TyCtxt<'_>, + impl_did: LocalDefId, +) -> Result<(), ErrorGuaranteed> { debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); // 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).coerce_unsized_info(impl_did); + tcx.at(span).ensure().coerce_unsized_info(impl_did) } -fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) { +fn visit_implementation_of_dispatch_from_dyn( + tcx: TyCtxt<'_>, + impl_did: LocalDefId, +) -> Result<(), ErrorGuaranteed> { debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); let span = tcx.def_span(impl_did); @@ -166,26 +189,28 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok() - && mutbl_a == *mutbl_b => {} - (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), + && mutbl_a == *mutbl_b => + { + Ok(()) + } + (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => Ok(()), (&Adt(def_a, args_a), &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()); - tcx.dcx().emit_err(errors::DispatchFromDynCoercion { + return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion { span, trait_name: "DispatchFromDyn", note: true, source_path, target_path, - }); - - return; + })); } + let mut res = Ok(()); if def_a.repr().c() || def_a.repr().packed() { - tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }); + res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span })); } let fields = &def_a.non_enum_variant().fields; @@ -207,11 +232,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b) { if ok.obligations.is_empty() { - tcx.dcx().emit_err(errors::DispatchFromDynZST { + res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST { span, name: field.name, ty: ty_a, - }); + })); return false; } @@ -222,13 +247,13 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef .collect::>(); if coerced_fields.is_empty() { - tcx.dcx().emit_err(errors::DispatchFromDynSingle { + res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle { span, trait_name: "DispatchFromDyn", note: true, - }); + })); } else if coerced_fields.len() > 1 { - tcx.dcx().emit_err(errors::DispatchFromDynMulti { + res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti { span, coercions_note: true, number: coerced_fields.len(), @@ -244,7 +269,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef }) .collect::>() .join(", "), - }); + })); } else { let ocx = ObligationCtxt::new(&infcx); for field in coerced_fields { @@ -261,21 +286,25 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); + res = Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env); + res = res.and(ocx.resolve_regions_and_report_errors(impl_did, &outlives_env)); } + res } - _ => { - tcx.dcx().emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" }); - } + _ => Err(tcx + .dcx() + .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })), } } -pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo { +pub fn coerce_unsized_info<'tcx>( + tcx: TyCtxt<'tcx>, + impl_did: LocalDefId, +) -> Result { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); let span = tcx.def_span(impl_did); @@ -292,8 +321,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe let param_env = tcx.param_env(impl_did); assert!(!source.has_escaping_bound_vars()); - let err_info = CoerceUnsizedInfo { custom_kind: None }; - debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); let infcx = tcx.infer_ctxt().build(); @@ -337,14 +364,13 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe 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()); - tcx.dcx().emit_err(errors::DispatchFromDynSame { + return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame { span, trait_name: "CoerceUnsized", note: true, source_path, target_path, - }); - return err_info; + })); } // Here we are considering a case of converting @@ -419,12 +445,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe .collect::>(); if diff_fields.is_empty() { - tcx.dcx().emit_err(errors::CoerceUnsizedOneField { + return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField { span, trait_name: "CoerceUnsized", note: true, - }); - return err_info; + })); } else if diff_fields.len() > 1 { let item = tcx.hir().expect_item(impl_did); let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind { @@ -433,7 +458,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe tcx.def_span(impl_did) }; - tcx.dcx().emit_err(errors::CoerceUnsizedMulti { + return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti { span, coercions_note: true, number: diff_fields.len(), @@ -442,9 +467,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)) .collect::>() .join(", "), - }); - - return err_info; + })); } let (i, a, b) = diff_fields[0]; @@ -453,8 +476,9 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe } _ => { - tcx.dcx().emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }); - return err_info; + return Err(tcx + .dcx() + .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" })); } }; @@ -477,7 +501,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe let outlives_env = OutlivesEnvironment::new(param_env); let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env); - CoerceUnsizedInfo { custom_kind: kind } + Ok(CoerceUnsizedInfo { custom_kind: kind }) } fn infringing_fields_error( diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index abef365c3ca3c..0df5a57bc2c45 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -171,6 +171,7 @@ impl<'tcx> InherentCollect<'tcx> { } ty::FnDef(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bound(..) diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 63ea02720145e..951440d6a2d0b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 561a254e89ef7..8cf1f2c9407f6 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -6,10 +6,11 @@ // mappings. That mapping code resides here. use crate::errors; -use rustc_errors::{error_code, struct_span_code_err}; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_span::ErrorGuaranteed; use rustc_trait_selection::traits; mod builtin; @@ -18,7 +19,11 @@ mod inherent_impls_overlap; mod orphan; mod unsafety; -fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<'_>) { +fn check_impl( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, + trait_ref: ty::TraitRef<'_>, +) -> Result<(), ErrorGuaranteed> { debug!( "(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, @@ -28,18 +33,18 @@ fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef< // Skip impls where one of the self type is an error type. // This occurs with e.g., resolve failures (#30589). if trait_ref.references_error() { - return; + return Ok(()); } - enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); - enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id); + enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id) + .and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id)) } fn enforce_trait_manually_implementable( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_def_id: DefId, -) { +) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` @@ -56,21 +61,20 @@ fn enforce_trait_manually_implementable( // Maintain explicit error code for `Unsize`, since it has a useful // explanation about using `CoerceUnsized` instead. if Some(trait_def_id) == tcx.lang_items().unsize_trait() { - err.code(error_code!(E0328)); + err.code(E0328); } - err.emit(); - return; + return Err(err.emit()); } if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = tcx.trait_def(trait_def_id).specialization_kind { if !tcx.features().specialization && !tcx.features().min_specialization { - tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }); - return; + return Err(tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span })); } } + Ok(()) } /// We allow impls of marker traits to overlap, so they can't override impls @@ -79,22 +83,22 @@ fn enforce_empty_impls_for_marker_traits( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_def_id: DefId, -) { +) -> Result<(), ErrorGuaranteed> { if !tcx.trait_def(trait_def_id).is_marker { - return; + return Ok(()); } if tcx.associated_item_def_ids(trait_def_id).is_empty() { - return; + return Ok(()); } - struct_span_code_err!( + Err(struct_span_code_err!( tcx.dcx(), tcx.def_span(impl_def_id), E0715, "impls for marker traits cannot contain items" ) - .emit(); + .emit()) } pub fn provide(providers: &mut Providers) { @@ -115,23 +119,23 @@ pub fn provide(providers: &mut Providers) { }; } -fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) { +fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> { // Trigger building the specialization graph for the trait. This will detect and report any // overlap errors. - tcx.ensure().specialization_graph_of(def_id); + let mut res = tcx.ensure().specialization_graph_of(def_id); let impls = tcx.hir().trait_impls(def_id); for &impl_def_id in impls { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); - check_impl(tcx, impl_def_id, trait_ref); - check_object_overlap(tcx, impl_def_id, trait_ref); + res = res.and(check_impl(tcx, impl_def_id, trait_ref)); + res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref)); - unsafety::check_item(tcx, impl_def_id); - tcx.ensure().orphan_check_impl(impl_def_id); + res = res.and(unsafety::check_item(tcx, impl_def_id)); + res = res.and(tcx.ensure().orphan_check_impl(impl_def_id)); } - builtin::check_trait(tcx, def_id); + res.and(builtin::check_trait(tcx, def_id)) } /// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`. @@ -139,12 +143,12 @@ fn check_object_overlap<'tcx>( tcx: TyCtxt<'tcx>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<'tcx>, -) { +) -> Result<(), ErrorGuaranteed> { let trait_def_id = trait_ref.def_id; if trait_ref.references_error() { debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref); - return; + return Ok(()); } // check for overlap with the automatic `impl Trait for dyn Trait` @@ -173,7 +177,7 @@ fn check_object_overlap<'tcx>( let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids.any(|d| d == trait_def_id) { let span = tcx.def_span(impl_def_id); - struct_span_code_err!( + return Err(struct_span_code_err!( tcx.dcx(), span, E0371, @@ -189,9 +193,10 @@ fn check_object_overlap<'tcx>( tcx.def_path_str(trait_def_id) ), ) - .emit(); + .emit()); } } } } + Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index c1d0e0444b673..45641be52d2f2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -244,6 +244,7 @@ fn do_orphan_check_impl<'tcx>( | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther), ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bound(..) @@ -495,7 +496,7 @@ fn lint_auto_trait_impl<'tcx>( return; } - tcx.struct_span_lint_hir( + tcx.node_span_lint( lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, tcx.local_def_id_to_hir_id(impl_def_id), tcx.def_span(impl_def_id), diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 7b146573a1b3b..e3b5c724cdee2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -1,13 +1,14 @@ //! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; +use rustc_span::ErrorGuaranteed; -pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { let item = tcx.hir().expect_item(def_id); let impl_ = item.expect_impl(); @@ -18,7 +19,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { - struct_span_code_err!( + return Err(struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0199, @@ -31,11 +32,11 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "", rustc_errors::Applicability::MachineApplicable, ) - .emit(); + .emit()); } (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { - struct_span_code_err!( + return Err(struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0200, @@ -54,11 +55,11 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "unsafe ", rustc_errors::Applicability::MaybeIncorrect, ) - .emit(); + .emit()); } (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { - struct_span_code_err!( + return Err(struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0569, @@ -77,7 +78,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "unsafe ", rustc_errors::Applicability::MaybeIncorrect, ) - .emit(); + .emit()); } (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { @@ -92,4 +93,5 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } } + Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e557f36037b6c..fbcebb7c87c9b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -81,6 +81,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, coroutine_kind, + coroutine_for_closure, collect_mod_item_types, is_type_alias_impl_trait, ..*providers @@ -146,8 +147,8 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector { } } fn visit_array_length(&mut self, length: &'v hir::ArrayLen) { - if let &hir::ArrayLen::Infer(_, span) = length { - self.0.push(span); + if let hir::ArrayLen::Infer(inf) = length { + self.0.push(inf.span); } intravisit::walk_array_len(self, length) } @@ -348,7 +349,7 @@ impl<'tcx> ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) } } - pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + pub fn to_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { self.astconv().ast_ty_to_ty(ast_ty) } @@ -412,7 +413,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { @@ -1148,7 +1149,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( tcx: TyCtxt<'tcx>, - sig: &hir::FnSig<'_>, + sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'_>, def_id: LocalDefId, icx: &ItemCtxt<'tcx>, @@ -1352,14 +1353,14 @@ fn impl_trait_ref( let last_arg = args.args.len() - 1; assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects)); args.args = &args.args[..args.args.len() - 1]; - path_segments[last_segment].args = Some(&args); + path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args)); let path = hir::Path { span: ast_trait_ref.path.span, res: ast_trait_ref.path.res, - segments: &path_segments, + segments: tcx.hir_arena.alloc_slice(&path_segments), }; - let trait_ref = hir::TraitRef { path: &path, hir_ref_id: ast_trait_ref.hir_ref_id }; - icx.astconv().instantiate_mono_trait_ref(&trait_ref, selfty) + let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: ast_trait_ref.hir_ref_id }); + icx.astconv().instantiate_mono_trait_ref(trait_ref, selfty) } else { icx.astconv().instantiate_mono_trait_ref(ast_trait_ref, selfty) } @@ -1531,6 +1532,29 @@ fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> DefId { + let &rustc_hir::Closure { kind: hir::ClosureKind::CoroutineClosure(_), body, .. } = + tcx.hir_node_by_def_id(def_id).expect_closure() + else { + bug!() + }; + + let &hir::Expr { + kind: + hir::ExprKind::Closure(&rustc_hir::Closure { + def_id, + kind: hir::ClosureKind::Coroutine(_), + .. + }), + .. + } = tcx.hir().body(body).value + else { + bug!() + }; + + def_id.to_def_id() +} + fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { match tcx.hir_node_by_def_id(def_id) { Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index b44b2eefabbc6..1dabb6feb5e1b 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -274,7 +274,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { Defaults::FutureCompatDisallowed if tcx.features().default_type_parameter_fallback => {} Defaults::FutureCompatDisallowed => { - tcx.struct_span_lint_hir( + tcx.node_span_lint( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, param.span, @@ -349,6 +349,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ClosureKind::Coroutine(_) => { &["", "", "", "", ""][..] } + ClosureKind::CoroutineClosure(_) => &[ + "", + "", + "", + "", + "", + ][..], }; params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { 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 4f049f699e6c8..3849c0893f471 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -8,7 +8,7 @@ use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -254,7 +254,7 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou map: &mut named_variable_map, scope: &Scope::Root { opt_parent_item: None }, }; - match tcx.hir().owner(local_def_id) { + match tcx.hir_owner_node(local_def_id) { hir::OwnerNode::Item(item) => visitor.visit_item(item), hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), hir::OwnerNode::TraitItem(item) => { @@ -912,7 +912,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { continue; } self.insert_lifetime(lt, ResolvedArg::StaticLifetime); - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( lint::builtin::UNUSED_LIFETIMES, lifetime.hir_id, lifetime.ident.span, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index bfa9dc42422cb..5cdcc1bb860b2 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -530,9 +530,13 @@ pub(super) fn type_of_opaque( Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) { Node::Item(item) => match item.kind { ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { .. }, + origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false }, .. }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), + ItemKind::OpaqueTy(OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true }, + .. + }) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id), // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(&OpaqueTy { origin: @@ -586,7 +590,6 @@ fn infer_placeholder_type<'a>( // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. - // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`. if let Ok(suggestions) = &mut err.suggestions { suggestions.clear(); } 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 85093bc12b378..79cb384c5bded 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -23,6 +23,60 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> res } +/// Checks "defining uses" of opaque `impl Trait` in associated types. +/// These can only be defined by associated items of the same trait. +#[instrument(skip(tcx), level = "debug")] +pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> Ty<'_> { + let mut parent_def_id = def_id; + while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy { + // Account for `type Alias = impl Trait;` (#116031) + parent_def_id = tcx.local_parent(parent_def_id); + } + let impl_def_id = tcx.local_parent(parent_def_id); + match tcx.def_kind(impl_def_id) { + DefKind::Impl { .. } => {} + other => bug!("invalid impl trait in assoc type parent: {other:?}"), + } + + let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] }; + + for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { + let assoc = tcx.associated_item(assoc_id); + match assoc.kind { + ty::AssocKind::Const | ty::AssocKind::Fn => { + locator.check(assoc_id.expect_local(), ImplTraitSource::AssocTy) + } + // Associated types don't have bodies, so they can't constrain hidden types + ty::AssocKind::Type => {} + } + } + + if let Some(hidden) = locator.found { + // Only check against typeck if we didn't already error + if !hidden.ty.references_error() { + for concrete_type in locator.typeck_types { + if concrete_type.ty != tcx.erase_regions(hidden.ty) + && !(concrete_type, hidden).references_error() + { + hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); + } + } + } + + hidden.ty + } else { + let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType { + span: tcx.def_span(def_id), + name: tcx.item_name(parent_def_id.to_def_id()), + what: "impl", + }); + Ty::new_error(tcx, reported) + } +} + /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". /// This ensures that inference is tractable. @@ -128,9 +182,15 @@ struct TaitConstraintLocator<'tcx> { typeck_types: Vec>, } +#[derive(Debug)] +enum ImplTraitSource { + AssocTy, + TyAlias, +} + impl TaitConstraintLocator<'_> { #[instrument(skip(self), level = "debug")] - fn check(&mut self, item_def_id: LocalDefId) { + fn check(&mut self, item_def_id: LocalDefId, source: ImplTraitSource) { // Don't try to check items that cannot possibly constrain the type. if !self.tcx.has_typeck_results(item_def_id) { debug!("no constraint: no typeck results"); @@ -182,7 +242,13 @@ impl TaitConstraintLocator<'_> { continue; } constrained = true; - if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) { + let opaque_types_defined_by = match source { + ImplTraitSource::AssocTy => { + self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id) + } + ImplTraitSource::TyAlias => self.tcx.opaque_types_defined_by(item_def_id), + }; + if !opaque_types_defined_by.contains(&self.def_id) { self.tcx.dcx().emit_err(TaitForwardCompat { span: hidden_type.span, item_span: self @@ -240,7 +306,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { if let hir::ExprKind::Closure(closure) = ex.kind { - self.check(closure.def_id); + self.check(closure.def_id, ImplTraitSource::TyAlias); } intravisit::walk_expr(self, ex); } @@ -248,7 +314,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'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); + self.check(it.owner_id.def_id, ImplTraitSource::TyAlias); intravisit::walk_item(self, it); } } @@ -256,13 +322,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'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); + self.check(it.owner_id.def_id, ImplTraitSource::TyAlias); intravisit::walk_impl_item(self, it); } } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { trace!(?it.owner_id); - self.check(it.owner_id.def_id); + self.check(it.owner_id.def_id, ImplTraitSource::TyAlias); intravisit::walk_trait_item(self, it); } fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f14390b77c6e2..4eba31e327f68 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,8 +2,8 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - Level, MultiSpan, + codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, + MultiSpan, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -52,7 +52,7 @@ pub struct AssocKindMismatchWrapInBracesSugg { } #[derive(Diagnostic)] -#[diag(hir_analysis_assoc_item_not_found, code = "E0220")] +#[diag(hir_analysis_assoc_item_not_found, code = E0220)] pub struct AssocItemNotFound<'a> { #[primary_span] pub span: Span, @@ -122,7 +122,7 @@ pub enum AssocItemNotFoundSugg<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")] +#[diag(hir_analysis_unrecognized_atomic_operation, code = E0092)] pub struct UnrecognizedAtomicOperation<'a> { #[primary_span] #[label] @@ -131,7 +131,7 @@ pub struct UnrecognizedAtomicOperation<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] +#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = E0094)] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { #[primary_span] #[label] @@ -142,7 +142,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")] +#[diag(hir_analysis_unrecognized_intrinsic_function, code = E0093)] pub struct UnrecognizedIntrinsicFunction { #[primary_span] #[label] @@ -151,7 +151,7 @@ pub struct UnrecognizedIntrinsicFunction { } #[derive(Diagnostic)] -#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] +#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = E0195)] pub struct LifetimesOrBoundsMismatchOnTrait { #[primary_span] #[label] @@ -178,7 +178,7 @@ pub struct AsyncTraitImplShouldBeAsync { } #[derive(Diagnostic)] -#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")] +#[diag(hir_analysis_drop_impl_on_wrong_item, code = E0120)] pub struct DropImplOnWrongItem { #[primary_span] #[label] @@ -186,7 +186,7 @@ pub struct DropImplOnWrongItem { } #[derive(Diagnostic)] -#[diag(hir_analysis_field_already_declared, code = "E0124")] +#[diag(hir_analysis_field_already_declared, code = E0124)] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] @@ -197,7 +197,7 @@ pub struct FieldAlreadyDeclared { } #[derive(Diagnostic)] -#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")] +#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = E0184)] pub struct CopyImplOnTypeWithDtor { #[primary_span] #[label] @@ -205,14 +205,14 @@ pub struct CopyImplOnTypeWithDtor { } #[derive(Diagnostic)] -#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")] +#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)] pub struct MultipleRelaxedDefaultBounds { #[primary_span] pub spans: Vec, } #[derive(Diagnostic)] -#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")] +#[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)] pub struct CopyImplOnNonAdt { #[primary_span] #[label] @@ -228,7 +228,7 @@ pub struct ConstParamTyImplOnNonAdt { } #[derive(Diagnostic)] -#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")] +#[diag(hir_analysis_trait_object_declared_with_no_traits, code = E0224)] pub struct TraitObjectDeclaredWithNoTraits { #[primary_span] pub span: Span, @@ -237,14 +237,14 @@ pub struct TraitObjectDeclaredWithNoTraits { } #[derive(Diagnostic)] -#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")] +#[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)] pub struct AmbiguousLifetimeBound { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")] +#[diag(hir_analysis_assoc_type_binding_not_allowed, code = E0229)] pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] @@ -264,7 +264,7 @@ pub struct ParenthesizedFnTraitExpansion { } #[derive(Diagnostic)] -#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")] +#[diag(hir_analysis_typeof_reserved_keyword_used, code = E0516)] pub struct TypeofReservedKeywordUsed<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -275,7 +275,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")] +#[diag(hir_analysis_value_of_associated_struct_already_specified, code = E0719)] pub struct ValueOfAssociatedStructAlreadySpecified { #[primary_span] #[label] @@ -320,7 +320,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params); err.span(self.span); - err.code(error_code!(E0393)); + err.code(E0393); err.arg("parameterCount", self.missing_type_params.len()); err.arg( "parameters", @@ -373,7 +373,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams { } #[derive(Diagnostic)] -#[diag(hir_analysis_manual_implementation, code = "E0183")] +#[diag(hir_analysis_manual_implementation, code = E0183)] #[help] pub struct ManualImplementation { #[primary_span] @@ -421,7 +421,7 @@ pub struct SelfInImplSelf { } #[derive(Diagnostic)] -#[diag(hir_analysis_linkage_type, code = "E0791")] +#[diag(hir_analysis_linkage_type, code = E0791)] pub(crate) struct LinkageType { #[primary_span] pub span: Span, @@ -429,7 +429,7 @@ pub(crate) struct LinkageType { #[derive(Diagnostic)] #[help] -#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = "E0055")] +#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = E0055)] pub struct AutoDerefReachedRecursionLimit<'a> { #[primary_span] #[label] @@ -440,7 +440,7 @@ pub struct AutoDerefReachedRecursionLimit<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_where_clause_on_main, code = "E0646")] +#[diag(hir_analysis_where_clause_on_main, code = E0646)] pub(crate) struct WhereClauseOnMain { #[primary_span] pub span: Span, @@ -485,7 +485,7 @@ pub(crate) struct StartTargetFeature { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_not_async, code = "E0752")] +#[diag(hir_analysis_start_not_async, code = E0752)] pub(crate) struct StartAsync { #[primary_span] #[label] @@ -493,7 +493,7 @@ pub(crate) struct StartAsync { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_function_where, code = "E0647")] +#[diag(hir_analysis_start_function_where, code = E0647)] pub(crate) struct StartFunctionWhere { #[primary_span] #[label] @@ -501,7 +501,7 @@ pub(crate) struct StartFunctionWhere { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_function_parameters, code = "E0132")] +#[diag(hir_analysis_start_function_parameters, code = E0132)] pub(crate) struct StartFunctionParameters { #[primary_span] #[label] @@ -509,14 +509,14 @@ pub(crate) struct StartFunctionParameters { } #[derive(Diagnostic)] -#[diag(hir_analysis_main_function_return_type_generic, code = "E0131")] +#[diag(hir_analysis_main_function_return_type_generic, code = E0131)] pub(crate) struct MainFunctionReturnTypeGeneric { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis_main_function_async, code = "E0752")] +#[diag(hir_analysis_main_function_async, code = E0752)] pub(crate) struct MainFunctionAsync { #[primary_span] pub span: Span, @@ -525,7 +525,7 @@ pub(crate) struct MainFunctionAsync { } #[derive(Diagnostic)] -#[diag(hir_analysis_main_function_generic_parameters, code = "E0131")] +#[diag(hir_analysis_main_function_generic_parameters, code = E0131)] pub(crate) struct MainFunctionGenericParameters { #[primary_span] pub span: Span, @@ -534,7 +534,7 @@ pub(crate) struct MainFunctionGenericParameters { } #[derive(Diagnostic)] -#[diag(hir_analysis_variadic_function_compatible_convention, code = "E0045")] +#[diag(hir_analysis_variadic_function_compatible_convention, code = E0045)] pub(crate) struct VariadicFunctionCompatibleConvention<'a> { #[primary_span] #[label] @@ -587,7 +587,7 @@ pub(crate) struct TypeOf<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_pass_to_variadic_function, code = "E0617")] +#[diag(hir_analysis_pass_to_variadic_function, code = E0617)] pub(crate) struct PassToVariadicFunction<'tcx, 'a> { #[primary_span] pub span: Span, @@ -601,7 +601,7 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = "E0607")] +#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)] pub(crate) struct CastThinPointerToFatPointer<'tcx> { #[primary_span] pub span: Span, @@ -610,7 +610,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_invalid_union_field, code = "E0740")] +#[diag(hir_analysis_invalid_union_field, code = E0740)] pub(crate) struct InvalidUnionField { #[primary_span] pub field_span: Span, @@ -649,7 +649,7 @@ pub(crate) struct ReturnTypeNotationEqualityBound { } #[derive(Diagnostic)] -#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")] +#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = E0121)] pub(crate) struct PlaceholderNotAllowedItemSignatures { #[primary_span] #[label] @@ -658,7 +658,7 @@ pub(crate) struct PlaceholderNotAllowedItemSignatures { } #[derive(Diagnostic)] -#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = "E0212")] +#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = E0212)] pub(crate) struct AssociatedTypeTraitUninferredGenericParams { #[primary_span] pub span: Span, @@ -684,7 +684,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion } #[derive(Diagnostic)] -#[diag(hir_analysis_enum_discriminant_overflowed, code = "E0370")] +#[diag(hir_analysis_enum_discriminant_overflowed, code = E0370)] #[note] pub(crate) struct EnumDiscriminantOverflowed { #[primary_span] @@ -774,7 +774,7 @@ pub(crate) struct SIMDFFIHighlyExperimental { #[derive(Diagnostic)] pub enum ImplNotMarkedDefault { - #[diag(hir_analysis_impl_not_marked_default, code = "E0520")] + #[diag(hir_analysis_impl_not_marked_default, code = E0520)] #[note] Ok { #[primary_span] @@ -784,7 +784,7 @@ pub enum ImplNotMarkedDefault { ok_label: Span, ident: Symbol, }, - #[diag(hir_analysis_impl_not_marked_default_err, code = "E0520")] + #[diag(hir_analysis_impl_not_marked_default_err, code = E0520)] #[note] Err { #[primary_span] @@ -795,7 +795,7 @@ pub enum ImplNotMarkedDefault { } #[derive(Diagnostic)] -#[diag(hir_analysis_missing_trait_item, code = "E0046")] +#[diag(hir_analysis_missing_trait_item, code = E0046)] pub(crate) struct MissingTraitItem { #[primary_span] #[label] @@ -846,7 +846,7 @@ pub(crate) struct MissingTraitItemSuggestionNone { } #[derive(Diagnostic)] -#[diag(hir_analysis_missing_one_of_trait_item, code = "E0046")] +#[diag(hir_analysis_missing_one_of_trait_item, code = E0046)] pub(crate) struct MissingOneOfTraitItem { #[primary_span] #[label] @@ -857,7 +857,7 @@ pub(crate) struct MissingOneOfTraitItem { } #[derive(Diagnostic)] -#[diag(hir_analysis_missing_trait_item_unstable, code = "E0046")] +#[diag(hir_analysis_missing_trait_item_unstable, code = E0046)] #[note] pub(crate) struct MissingTraitItemUnstable { #[primary_span] @@ -872,7 +872,7 @@ pub(crate) struct MissingTraitItemUnstable { } #[derive(Diagnostic)] -#[diag(hir_analysis_transparent_enum_variant, code = "E0731")] +#[diag(hir_analysis_transparent_enum_variant, code = E0731)] pub(crate) struct TransparentEnumVariant { #[primary_span] #[label] @@ -886,7 +886,7 @@ pub(crate) struct TransparentEnumVariant { } #[derive(Diagnostic)] -#[diag(hir_analysis_transparent_non_zero_sized_enum, code = "E0690")] +#[diag(hir_analysis_transparent_non_zero_sized_enum, code = E0690)] pub(crate) struct TransparentNonZeroSizedEnum<'a> { #[primary_span] #[label] @@ -898,7 +898,7 @@ pub(crate) struct TransparentNonZeroSizedEnum<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_transparent_non_zero_sized, code = "E0690")] +#[diag(hir_analysis_transparent_non_zero_sized, code = E0690)] pub(crate) struct TransparentNonZeroSized<'a> { #[primary_span] #[label] @@ -1045,7 +1045,7 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside, code = "E0390")] +#[diag(hir_analysis_inherent_ty_outside, code = E0390)] #[help] pub struct InherentTyOutside { #[primary_span] @@ -1054,7 +1054,7 @@ pub struct InherentTyOutside { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0378")] +#[diag(hir_analysis_coerce_unsized_may, code = E0378)] pub struct DispatchFromDynCoercion<'a> { #[primary_span] pub span: Span, @@ -1066,14 +1066,14 @@ pub struct DispatchFromDynCoercion<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_repr, code = "E0378")] +#[diag(hir_analysis_dispatch_from_dyn_repr, code = E0378)] pub struct DispatchFromDynRepr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")] +#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)] #[help] pub struct InherentTyOutsideRelevant { #[primary_span] @@ -1083,7 +1083,7 @@ pub struct InherentTyOutsideRelevant { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")] +#[diag(hir_analysis_inherent_ty_outside_new, code = E0116)] #[note] pub struct InherentTyOutsideNew { #[primary_span] @@ -1092,7 +1092,7 @@ pub struct InherentTyOutsideNew { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")] +#[diag(hir_analysis_inherent_ty_outside_primitive, code = E0390)] #[help] pub struct InherentTyOutsidePrimitive { #[primary_span] @@ -1102,7 +1102,7 @@ pub struct InherentTyOutsidePrimitive { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")] +#[diag(hir_analysis_inherent_primitive_ty, code = E0390)] #[help] pub struct InherentPrimitiveTy<'a> { #[primary_span] @@ -1118,7 +1118,7 @@ pub struct InherentPrimitiveTyNote<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_dyn, code = "E0785")] +#[diag(hir_analysis_inherent_dyn, code = E0785)] #[note] pub struct InherentDyn { #[primary_span] @@ -1127,7 +1127,7 @@ pub struct InherentDyn { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_nominal, code = "E0118")] +#[diag(hir_analysis_inherent_nominal, code = E0118)] #[note] pub struct InherentNominal { #[primary_span] @@ -1136,7 +1136,7 @@ pub struct InherentNominal { } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_zst, code = "E0378")] +#[diag(hir_analysis_dispatch_from_dyn_zst, code = E0378)] #[note] pub struct DispatchFromDynZST<'a> { #[primary_span] @@ -1146,7 +1146,7 @@ pub struct DispatchFromDynZST<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0378")] +#[diag(hir_analysis_coerce_unsized_may, code = E0378)] pub struct DispatchFromDynSingle<'a> { #[primary_span] pub span: Span, @@ -1156,7 +1156,7 @@ pub struct DispatchFromDynSingle<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_multi, code = "E0378")] +#[diag(hir_analysis_dispatch_from_dyn_multi, code = E0378)] #[note] pub struct DispatchFromDynMulti { #[primary_span] @@ -1168,7 +1168,7 @@ pub struct DispatchFromDynMulti { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0376")] +#[diag(hir_analysis_coerce_unsized_may, code = E0376)] pub struct DispatchFromDynStruct<'a> { #[primary_span] pub span: Span, @@ -1176,7 +1176,7 @@ pub struct DispatchFromDynStruct<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0377")] +#[diag(hir_analysis_coerce_unsized_may, code = E0377)] pub struct DispatchFromDynSame<'a> { #[primary_span] pub span: Span, @@ -1188,7 +1188,7 @@ pub struct DispatchFromDynSame<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0374")] +#[diag(hir_analysis_coerce_unsized_may, code = E0374)] pub struct CoerceUnsizedOneField<'a> { #[primary_span] pub span: Span, @@ -1198,7 +1198,7 @@ pub struct CoerceUnsizedOneField<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_multi, code = "E0375")] +#[diag(hir_analysis_coerce_unsized_multi, code = E0375)] #[note] pub struct CoerceUnsizedMulti { #[primary_span] @@ -1211,7 +1211,7 @@ pub struct CoerceUnsizedMulti { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0378")] +#[diag(hir_analysis_coerce_unsized_may, code = E0378)] pub struct CoerceUnsizedMay<'a> { #[primary_span] pub span: Span, @@ -1219,7 +1219,7 @@ pub struct CoerceUnsizedMay<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_trait_cannot_impl_for_ty, code = "E0204")] +#[diag(hir_analysis_trait_cannot_impl_for_ty, code = E0204)] pub struct TraitCannotImplForTy { #[primary_span] pub span: Span, @@ -1241,7 +1241,7 @@ pub struct ImplForTyRequires { } #[derive(Diagnostic)] -#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")] +#[diag(hir_analysis_traits_with_defualt_impl, code = E0321)] #[note] pub struct TraitsWithDefaultImpl<'a> { #[primary_span] @@ -1252,7 +1252,7 @@ pub struct TraitsWithDefaultImpl<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cross_crate_traits, code = "E0321")] +#[diag(hir_analysis_cross_crate_traits, code = E0321)] pub struct CrossCrateTraits<'a> { #[primary_span] #[label] @@ -1262,7 +1262,7 @@ pub struct CrossCrateTraits<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")] +#[diag(hir_analysis_cross_crate_traits_defined, code = E0321)] pub struct CrossCrateTraitsDefined { #[primary_span] #[label] @@ -1271,7 +1271,7 @@ pub struct CrossCrateTraitsDefined { } #[derive(Diagnostic)] -#[diag(hir_analysis_ty_param_first_local, code = "E0210")] +#[diag(hir_analysis_ty_param_first_local, code = E0210)] #[note] pub struct TyParamFirstLocal<'a> { #[primary_span] @@ -1284,7 +1284,7 @@ pub struct TyParamFirstLocal<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_ty_param_some, code = "E0210")] +#[diag(hir_analysis_ty_param_some, code = E0210)] #[note] pub struct TyParamSome<'a> { #[primary_span] @@ -1297,7 +1297,7 @@ pub struct TyParamSome<'a> { #[derive(Diagnostic)] pub enum OnlyCurrentTraits<'a> { - #[diag(hir_analysis_only_current_traits_outside, code = "E0117")] + #[diag(hir_analysis_only_current_traits_outside, code = E0117)] Outside { #[primary_span] #[label(hir_analysis_only_current_traits_label)] @@ -1317,7 +1317,7 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] sugg: Option>, }, - #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")] + #[diag(hir_analysis_only_current_traits_primitive, code = E0117)] Primitive { #[primary_span] #[label(hir_analysis_only_current_traits_label)] @@ -1337,7 +1337,7 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] sugg: Option>, }, - #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")] + #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)] Arbitrary { #[primary_span] #[label(hir_analysis_only_current_traits_label)] @@ -1412,7 +1412,7 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_static_mut_ref, code = "E0796")] +#[diag(hir_analysis_static_mut_ref, code = E0796)] #[note] pub struct StaticMutRef { #[primary_span] @@ -1511,3 +1511,27 @@ pub struct NotSupportedDelegation<'a> { #[label] pub callee_span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_unused_generic_parameter)] +pub(crate) struct UnusedGenericParameter { + #[primary_span] + #[label] + pub span: Span, + pub param_name: Ident, + pub param_def_kind: &'static str, + #[subdiagnostic] + pub help: UnusedGenericParameterHelp, + #[help(hir_analysis_const_param_help)] + pub const_param_help: Option<()>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum UnusedGenericParameterHelp { + #[help(hir_analysis_unused_generic_parameter_adt_help)] + Adt { param_name: Ident, phantom_data: String }, + #[help(hir_analysis_unused_generic_parameter_adt_no_phantom_data_help)] + AdtNoPhantomData { param_name: Ident }, + #[help(hir_analysis_unused_generic_parameter_ty_alias_help)] + TyAlias { param_name: Ident }, +} diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 2fe08ead72b2a..c072891e2952e 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -12,7 +12,7 @@ use crate::constrained_generic_params as cgp; use min_specialization::check_min_specialization; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 08956d222d2ad..454cb97ac148b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -60,7 +60,6 @@ This API is completely unstable and subject to change. #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(is_sorted)] @@ -71,8 +70,6 @@ This API is completely unstable and subject to change. #![feature(lazy_cell)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] -#![feature(type_alias_impl_trait)] -#![recursion_limit = "256"] #[macro_use] extern crate tracing; @@ -172,19 +169,15 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.sess.time("coherence_checking", || { // Check impls constrain their parameters - let res = + let mut res = tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); - // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function - // or the compiler in general. - res.and(tcx.sess.track_errors(|| { - for &trait_def_id in tcx.all_local_trait_impls(()).keys() { - tcx.ensure().coherent_trait(trait_def_id); - } - })) + for &trait_def_id in tcx.all_local_trait_impls(()).keys() { + res = res.and(tcx.ensure().coherent_trait(trait_def_id)); + } // these queries are executed for side-effects (error reporting): - .and(tcx.ensure().crate_inherent_impls(())) - .and(tcx.ensure().crate_inherent_impls_overlap_check(())) + res.and(tcx.ensure().crate_inherent_impls(())) + .and(tcx.ensure().crate_inherent_impls_overlap_check(())) })?; if tcx.features().rustc_attrs { @@ -221,7 +214,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { /// A quasi-deprecated helper used in rustdoc and clippy to get /// the type from a HIR node. -pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { +pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { // In case there are any projections, etc., find the "environment" // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. @@ -232,7 +225,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { pub fn hir_trait_to_predicates<'tcx>( tcx: TyCtxt<'tcx>, - hir_trait: &hir::TraitRef<'_>, + hir_trait: &hir::TraitRef<'tcx>, self_ty: Ty<'tcx>, ) -> Bounds<'tcx> { // In case there are any projections, etc., find the "environment" diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs index b061d6371388f..6846e4defe5e5 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors.rs @@ -6,18 +6,18 @@ pub use self::{ missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, }; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, ErrCode}; use rustc_session::Session; pub trait StructuredDiagnostic<'tcx> { fn session(&self) -> &Session; - fn code(&self) -> String; + fn code(&self) -> ErrCode; fn diagnostic(&self) -> DiagnosticBuilder<'tcx> { let err = self.diagnostic_common(); - if self.session().teach(&self.code()) { + if self.session().teach(self.code()) { self.diagnostic_extended(err) } else { self.diagnostic_regular(err) diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs index 6f4435db41143..50b4ef623ac7e 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs @@ -1,5 +1,5 @@ use crate::{errors, structured_errors::StructuredDiagnostic}; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode}; use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Span; @@ -16,8 +16,8 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> { self.sess } - fn code(&self) -> String { - rustc_errors::error_code!(E0617) + fn code(&self) -> ErrCode { + E0617 } fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs index 19cac4a38aaab..54d54a2af93a6 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs @@ -1,5 +1,5 @@ use crate::{errors, structured_errors::StructuredDiagnostic}; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode}; use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Span; @@ -16,8 +16,8 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> { self.sess } - fn code(&self) -> String { - rustc_errors::error_code!(E0607) + fn code(&self) -> ErrCode { + E0607 } fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index ba81e7f1f8165..501915d2e7e53 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,5 +1,7 @@ use crate::structured_errors::StructuredDiagnostic; -use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, MultiSpan, +}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_session::Session; @@ -1105,8 +1107,8 @@ impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> { self.tcx.sess } - fn code(&self) -> String { - rustc_errors::error_code!(E0107) + fn code(&self) -> ErrCode { + E0107 } fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index f09594cbbc667..580cdb4a3a209 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -235,8 +235,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // leaf type -- noop } - ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) => { - bug!("Unexpected closure type in variance computation"); + ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => { + bug!("Unexpected coroutine/closure type in variance computation"); } ty::Ref(region, ty, mutbl) => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e76303bc6dfa1..9d0c5cb0f32b0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -956,7 +956,7 @@ impl<'a> State<'a> { fn print_array_length(&mut self, len: &hir::ArrayLen) { match len { - hir::ArrayLen::Infer(_, _) => self.word("_"), + hir::ArrayLen::Infer(..) => self.word("_"), hir::ArrayLen::Body(ct) => self.print_anon_const(ct), } } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 4fd9391acc368..220da19a29dc8 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -96,9 +96,6 @@ hir_typeck_lossy_provenance_ptr2int = hir_typeck_method_call_on_unknown_raw_pointee = cannot call a method on a raw pointer with an unknown pointee type -hir_typeck_missing_fn_lang_items = failed to find an overloaded call trait for closure call - .help = make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> @@ -108,8 +105,6 @@ hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for { hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide -hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters - hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expected_ty}` to `{$expr_ty}` hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}` hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}` diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d486f069989ee..fbe6f454dbc92 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -77,6 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_expr, Expectation::NoExpectation, arg_exprs, + Some(call_expr), ), _ => self.check_expr(callee_expr), }; @@ -140,33 +141,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some(CallStep::Builtin(adjusted_ty)); } - ty::Closure(def_id, args) => { + // Check whether this is a call to a closure where we + // haven't yet decided on whether the closure is fn vs + // fnmut vs fnonce. If so, we have to defer further processing. + ty::Closure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => { let def_id = def_id.expect_local(); + let closure_sig = args.as_closure().sig(); + let closure_sig = self.instantiate_binder_with_fresh_vars( + call_expr.span, + infer::FnCall, + closure_sig, + ); + let adjustments = self.adjust_steps(autoderef); + self.record_deferred_call_resolution( + def_id, + DeferredCallResolution { + call_expr, + callee_expr, + closure_ty: adjusted_ty, + adjustments, + fn_sig: closure_sig, + }, + ); + return Some(CallStep::DeferredClosure(def_id, closure_sig)); + } - // Check whether this is a call to a closure where we - // haven't yet decided on whether the closure is fn vs - // fnmut vs fnonce. If so, we have to defer further processing. - if self.closure_kind(args).is_none() { - let closure_sig = args.as_closure().sig(); - let closure_sig = self.instantiate_binder_with_fresh_vars( - call_expr.span, - infer::FnCall, - closure_sig, - ); - let adjustments = self.adjust_steps(autoderef); - self.record_deferred_call_resolution( - def_id, - DeferredCallResolution { - call_expr, - callee_expr, - adjusted_ty, - adjustments, - fn_sig: closure_sig, - closure_args: args, - }, - ); - return Some(CallStep::DeferredClosure(def_id, closure_sig)); - } + // When calling a `CoroutineClosure` that is local to the body, we will + // not know what its `closure_kind` is yet. Instead, just fill in the + // signature with an infer var for the `tupled_upvars_ty` of the coroutine, + // and record a deferred call resolution which will constrain that var + // as part of `AsyncFn*` trait confirmation. + ty::CoroutineClosure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => { + let def_id = def_id.expect_local(); + let closure_args = args.as_coroutine_closure(); + let coroutine_closure_sig = self.instantiate_binder_with_fresh_vars( + call_expr.span, + infer::FnCall, + closure_args.coroutine_closure_sig(), + ); + let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: callee_expr.span, + }); + let call_sig = self.tcx.mk_fn_sig( + [coroutine_closure_sig.tupled_inputs_ty], + coroutine_closure_sig.to_coroutine( + self.tcx, + closure_args.parent_args(), + // Inherit the kind ty of the closure, since we're calling this + // coroutine with the most relaxed `AsyncFn*` trait that we can. + // We don't necessarily need to do this here, but it saves us + // computing one more infer var that will get constrained later. + closure_args.kind_ty(), + self.tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ), + coroutine_closure_sig.c_variadic, + coroutine_closure_sig.unsafety, + coroutine_closure_sig.abi, + ); + let adjustments = self.adjust_steps(autoderef); + self.record_deferred_call_resolution( + def_id, + DeferredCallResolution { + call_expr, + callee_expr, + closure_ty: adjusted_ty, + adjustments, + fn_sig: call_sig, + }, + ); + return Some(CallStep::DeferredClosure(def_id, call_sig)); } // Hack: we know that there are traits implementing Fn for &F @@ -220,6 +265,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true), (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true), (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false), + (self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true), + ( + self.tcx.lang_items().async_fn_mut_trait(), + Ident::with_dummy_span(sym::async_call_mut), + true, + ), + ( + self.tcx.lang_items().async_fn_once_trait(), + Ident::with_dummy_span(sym::async_call_once), + false, + ), ] { let Some(trait_def_id) = opt_trait_def_id else { continue }; @@ -242,28 +298,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adjusted_ty, opt_input_type.as_ref().map(slice::from_ref), ) { - // Check for `self` receiver on the method, otherwise we can't use this as a `Fn*` trait. - if !self.tcx.associated_item(ok.value.def_id).fn_has_self_parameter { - self.dcx().span_delayed_bug( - call_expr.span, - "input to overloaded call fn is not a self receiver", - ); - return None; - } - let method = self.register_infer_ok_obligations(ok); let mut autoref = None; if borrow { // Check for &self vs &mut self in the method signature. Since this is either // the Fn or FnMut trait, it should be one of those. let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() else { - // The `fn`/`fn_mut` lang item is ill-formed, which should have - // caused an error elsewhere. - self.dcx().span_delayed_bug( - call_expr.span, - "input to call/call_mut is not a ref", - ); - return None; + bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut") }; // For initial two-phase borrow @@ -889,10 +930,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub struct DeferredCallResolution<'tcx> { call_expr: &'tcx hir::Expr<'tcx>, callee_expr: &'tcx hir::Expr<'tcx>, - adjusted_ty: Ty<'tcx>, + closure_ty: Ty<'tcx>, adjustments: Vec>, fn_sig: ty::FnSig<'tcx>, - closure_args: GenericArgsRef<'tcx>, } impl<'a, 'tcx> DeferredCallResolution<'tcx> { @@ -901,10 +941,10 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { // we should not be invoked until the closure kind has been // determined by upvar inference - assert!(fcx.closure_kind(self.closure_args).is_some()); + assert!(fcx.closure_kind(self.closure_ty).is_some()); // We may now know enough to figure out fn vs fnmut etc. - match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) { + match fcx.try_overloaded_call_traits(self.call_expr, self.closure_ty, None) { Some((autoref, method_callee)) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature @@ -937,9 +977,11 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { ); } None => { - // This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once` - // lang items are not defined (issue #86238). - fcx.dcx().emit_err(errors::MissingFnLangItems { span: self.call_expr.span }); + span_bug!( + self.call_expr.span, + "Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`", + self.closure_ty + ) } } } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index a720a858f3c13..58823ea30ce57 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -33,7 +33,7 @@ use super::FnCtxt; use crate::errors; use crate::type_error_struct; use hir::ExprKind; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{codes::*, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; @@ -133,6 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Adt(..) | ty::Never @@ -587,7 +588,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - fcx.tcx.emit_spanned_lint( + fcx.tcx.emit_node_span_lint( lint, self.expr.hir_id, self.span, @@ -900,7 +901,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - fcx.tcx.emit_spanned_lint( + fcx.tcx.emit_node_span_lint( lint::builtin::CENUM_IMPL_DROP_CAST, self.expr.hir_id, self.span, @@ -934,7 +935,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg }; - fcx.tcx.emit_spanned_lint( + fcx.tcx.emit_node_span_lint( lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, @@ -950,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg }; - fcx.tcx.emit_spanned_lint( + fcx.tcx.emit_node_span_lint( lint::builtin::FUZZY_PROVENANCE_CASTS, self.expr.hir_id, self.span, diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index c887368b2a233..aab78465f8c85 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -2,8 +2,7 @@ use std::cell::RefCell; use crate::coercion::CoerceMany; use crate::gather_locals::GatherLocalsVisitor; -use crate::CoroutineTypes; -use crate::FnCtxt; +use crate::{CoroutineTypes, Diverges, FnCtxt}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; @@ -73,9 +72,15 @@ pub(super) fn check_fn<'a, 'tcx>( let inputs_fn = fn_sig.inputs().iter().copied(); for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. - let ty: Option<&hir::Ty<'_>> = try { inputs_hir?.get(idx)? }; + let ty: Option<&hir::Ty<'_>> = inputs_hir.and_then(|h| h.get(idx)); let ty_span = ty.map(|ty| ty.span); fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); + if param.pat.is_never_pattern() { + fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always { + span: param.pat.span, + custom_note: Some("any code following a never pattern is unreachable"), + }); + } // Check that argument is Sized. if !params_can_be_unsized { @@ -105,6 +110,7 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::Return(ty) => ty.span, }; fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + fcx.is_whole_body.set(true); fcx.check_return_expr(body.value, false); // Finalize the return check by taking the LUB of the return types @@ -146,26 +152,22 @@ pub(super) fn check_fn<'a, 'tcx>( } fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) { + let span = tcx.def_span(fn_id); + let DefKind::Fn = tcx.def_kind(fn_id) else { - let span = tcx.def_span(fn_id); tcx.dcx().span_err(span, "should be a function"); return; }; let generic_counts = tcx.generics_of(fn_id).own_counts(); if generic_counts.types != 0 { - let span = tcx.def_span(fn_id); tcx.dcx().span_err(span, "should have no type parameters"); } if generic_counts.consts != 0 { - let span = tcx.def_span(fn_id); tcx.dcx().span_err(span, "should have no const parameters"); } - let Some(panic_info_did) = tcx.lang_items().panic_info() else { - tcx.dcx().err("language item required, but not found: `panic_info`"); - return; - }; + let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span)); // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` let panic_info_ty = tcx.type_of(panic_info_did).instantiate( @@ -197,11 +199,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> let _ = check_function_signature( tcx, - ObligationCause::new( - tcx.def_span(fn_id), - fn_id, - ObligationCauseCode::LangFunctionType(sym::panic_impl), - ), + ObligationCause::new(span, fn_id, ObligationCauseCode::LangFunctionType(sym::panic_impl)), fn_id.into(), expected_sig, ); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 8a035d0577f6f..a985fa201d071 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -63,7 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => (None, None), }; - let ClosureSignatures { bound_sig, liberated_sig } = + let ClosureSignatures { bound_sig, mut liberated_sig } = self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig); debug!(?bound_sig, ?liberated_sig); @@ -125,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) | hir::CoroutineKind::Coroutine(_) => { let yield_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, + kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); @@ -137,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // not a problem. hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { let yield_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, + kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); @@ -166,8 +166,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); let interior = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: body.value.span, + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, }); self.deferred_coroutine_interiors.borrow_mut().push(( expr_def_id, @@ -175,10 +175,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { interior, )); + // Coroutines that come from coroutine closures have not yet determined + // their kind ty, so make a fresh infer var which will be constrained + // later during upvar analysis. Regular coroutines always have the kind + // ty of `().` + let kind_ty = match kind { + hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => self + .next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + _ => tcx.types.unit, + }; + let coroutine_args = ty::CoroutineArgs::new( tcx, ty::CoroutineArgsParts { parent_args, + kind_ty, resume_ty, yield_ty, return_ty: liberated_sig.output(), @@ -192,6 +206,94 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(CoroutineTypes { resume_ty, yield_ty }), ) } + hir::ClosureKind::CoroutineClosure(kind) => { + // async closures always return the type ascribed after the `->` (if present), + // and yield `()`. + let (bound_return_ty, bound_yield_ty) = match kind { + hir::CoroutineDesugaring::Async => { + (bound_sig.skip_binder().output(), tcx.types.unit) + } + hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => { + todo!("`gen` and `async gen` closures not supported yet") + } + }; + // Compute all of the variables that will be used to populate the coroutine. + let resume_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let interior = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let closure_kind_ty = self.next_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish closure kind inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let closure_args = ty::CoroutineClosureArgs::new( + tcx, + ty::CoroutineClosureArgsParts { + parent_args, + closure_kind_ty, + signature_parts_ty: Ty::new_fn_ptr( + tcx, + bound_sig.map_bound(|sig| { + tcx.mk_fn_sig( + [ + resume_ty, + Ty::new_tup_from_iter(tcx, sig.inputs().iter().copied()), + ], + Ty::new_tup(tcx, &[bound_yield_ty, bound_return_ty]), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }), + ), + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty: interior, + }, + ); + + let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + + // We need to turn the liberated signature that we got from HIR, which + // looks something like `|Args...| -> T`, into a signature that is suitable + // for type checking the inner body of the closure, which always returns a + // coroutine. To do so, we use the `CoroutineClosureSignature` to compute + // the coroutine type, filling in the tupled_upvars_ty and kind_ty with infer + // vars which will get constrained during upvar analysis. + let coroutine_output_ty = tcx.liberate_late_bound_regions( + expr_def_id.to_def_id(), + closure_args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine( + tcx, + parent_args, + closure_kind_ty, + tcx.coroutine_for_closure(expr_def_id), + coroutine_upvars_ty, + ) + }), + ); + liberated_sig = tcx.mk_fn_sig( + liberated_sig.inputs().iter().copied(), + coroutine_output_ty, + liberated_sig.c_variadic, + liberated_sig.unsafety, + liberated_sig.abi, + ); + + (Ty::new_coroutine_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None) + } }; check_fn( @@ -373,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn sig_of_closure( &self, expr_def_id: LocalDefId, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, closure_kind: hir::ClosureKind, expected_sig: Option>, ) -> ClosureSignatures<'tcx> { @@ -390,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn sig_of_closure_no_expectation( &self, expr_def_id: LocalDefId, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, closure_kind: hir::ClosureKind, ) -> ClosureSignatures<'tcx> { let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind); @@ -449,7 +551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn sig_of_closure_with_expectation( &self, expr_def_id: LocalDefId, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, closure_kind: hir::ClosureKind, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { @@ -506,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn sig_of_closure_with_mismatched_number_of_arguments( &self, expr_def_id: LocalDefId, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { let expr_map_node = self.tcx.hir_node_by_def_id(expr_def_id); @@ -547,7 +649,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn merge_supplied_sig_with_expectation( &self, expr_def_id: LocalDefId, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, closure_kind: hir::ClosureKind, mut expected_sigs: ClosureSignatures<'tcx>, ) -> InferResult<'tcx, ClosureSignatures<'tcx>> { @@ -641,7 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn supplied_sig_of_closure( &self, expr_def_id: LocalDefId, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, closure_kind: hir::ClosureKind, ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; @@ -690,7 +792,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _, )) | hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) - | hir::ClosureKind::Closure => astconv.ty_infer(None, decl.output.span()), + | hir::ClosureKind::Closure + | hir::ClosureKind::CoroutineClosure(_) => { + astconv.ty_infer(None, decl.output.span()) + } }, }; @@ -843,7 +948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// all parameters are of type `ty::Error`. fn error_sig_of_closure( &self, - decl: &hir::FnDecl<'_>, + decl: &hir::FnDecl<'tcx>, guar: ErrorGuaranteed, ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index e9d373119fa4d..ca636ebcade04 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,7 +36,9 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -625,6 +627,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { )]; let mut has_unsized_tuple_coercion = false; + let mut has_trait_upcasting_coercion = None; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -692,6 +695,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // these here and emit a feature error if coercion doesn't fail // due to another reason. match impl_source { + traits::ImplSource::Builtin( + BuiltinImplSource::TraitUpcasting { .. }, + _, + ) => { + has_trait_upcasting_coercion = + Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1))); + } traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { has_unsized_tuple_coercion = true; } @@ -702,6 +712,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } + if let Some((sub, sup)) = has_trait_upcasting_coercion + && !self.tcx().features().trait_upcasting + { + // Renders better when we erase regions, since they're not really the point here. + let (sub, sup) = self.tcx.erase_regions((sub, sup)); + let mut err = feature_err( + &self.tcx.sess, + sym::trait_upcasting, + self.cause.span, + format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"), + ); + err.note(format!("required when coercing `{source}` into `{target}`")); + err.emit(); + } + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_err( &self.tcx.sess, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 9850892bd36af..b6dfc34d3ac19 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -44,7 +44,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) || self.suggest_no_capture_closure(err, expected, expr_ty) - || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty) + || self.suggest_boxing_when_appropriate( + err, + expr.peel_blocks().span, + expr.hir_id, + expected, + expr_ty, + ) || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 4f92906888796..70afb042441f9 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -3,8 +3,8 @@ use std::borrow::Cow; use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan, - SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, + MultiSpan, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -15,7 +15,7 @@ use rustc_span::{ }; #[derive(Diagnostic)] -#[diag(hir_typeck_field_multiply_specified_in_initializer, code = "E0062")] +#[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)] pub struct FieldMultiplySpecifiedInInitializer { #[primary_span] #[label] @@ -26,7 +26,7 @@ pub struct FieldMultiplySpecifiedInInitializer { } #[derive(Diagnostic)] -#[diag(hir_typeck_return_stmt_outside_of_fn_body, code = "E0572")] +#[diag(hir_typeck_return_stmt_outside_of_fn_body, code = E0572)] pub struct ReturnStmtOutsideOfFnBody { #[primary_span] pub span: Span, @@ -43,7 +43,7 @@ pub enum ReturnLikeStatementKind { } impl IntoDiagnosticArg for ReturnLikeStatementKind { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { let kind = match self { Self::Return => "return", Self::Become => "become", @@ -62,14 +62,14 @@ pub struct RustCallIncorrectArgs { } #[derive(Diagnostic)] -#[diag(hir_typeck_yield_expr_outside_of_coroutine, code = "E0627")] +#[diag(hir_typeck_yield_expr_outside_of_coroutine, code = E0627)] pub struct YieldExprOutsideOfCoroutine { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_typeck_struct_expr_non_exhaustive, code = "E0639")] +#[diag(hir_typeck_struct_expr_non_exhaustive, code = E0639)] pub struct StructExprNonExhaustive { #[primary_span] pub span: Span, @@ -77,29 +77,21 @@ pub struct StructExprNonExhaustive { } #[derive(Diagnostic)] -#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")] +#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = E0699)] pub struct MethodCallOnUnknownRawPointee { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_typeck_missing_fn_lang_items)] -#[help] -pub struct MissingFnLangItems { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")] +#[diag(hir_typeck_functional_record_update_on_non_struct, code = E0436)] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_typeck_address_of_temporary_taken, code = "E0745")] +#[diag(hir_typeck_address_of_temporary_taken, code = E0745)] pub struct AddressOfTemporaryTaken { #[primary_span] #[label] @@ -145,7 +137,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_typeck_explicit_destructor, code = "E0040")] +#[diag(hir_typeck_explicit_destructor, code = E0040)] pub struct ExplicitDestructorCall { #[primary_span] #[label] @@ -168,7 +160,7 @@ pub enum ExplicitDestructorCallSugg { } #[derive(Diagnostic)] -#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")] +#[diag(hir_typeck_missing_parentheses_in_range, code = E0689)] pub struct MissingParenthesesInRange { #[primary_span] #[label(hir_typeck_missing_parentheses_in_range)] @@ -193,14 +185,6 @@ pub struct AddMissingParenthesesInRange { pub right: Span, } -#[derive(Diagnostic)] -#[diag(hir_typeck_op_trait_generic_params)] -pub struct OpMethodGenericParams { - #[primary_span] - pub span: Span, - pub method_name: String, -} - pub struct TypeMismatchFruTypo { /// Span of the LHS of the range pub expr_span: Span, @@ -321,7 +305,7 @@ impl HelpUseLatestEdition { } #[derive(Diagnostic)] -#[diag(hir_typeck_invalid_callee, code = "E0618")] +#[diag(hir_typeck_invalid_callee, code = E0618)] pub struct InvalidCallee { #[primary_span] pub span: Span, @@ -329,7 +313,7 @@ pub struct InvalidCallee { } #[derive(Diagnostic)] -#[diag(hir_typeck_int_to_fat, code = "E0606")] +#[diag(hir_typeck_int_to_fat, code = E0606)] pub struct IntToWide<'tcx> { #[primary_span] #[label(hir_typeck_int_to_fat_label)] @@ -510,7 +494,7 @@ pub struct TrivialCast<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_typeck_no_associated_item, code = "E0599")] +#[diag(hir_typeck_no_associated_item, code = E0599)] pub struct NoAssociatedItem { #[primary_span] pub span: Span, @@ -532,7 +516,7 @@ pub struct CandidateTraitNote { } #[derive(Diagnostic)] -#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")] +#[diag(hir_typeck_cannot_cast_to_bool, code = E0054)] pub struct CannotCastToBool<'tcx> { #[primary_span] pub span: Span, @@ -549,7 +533,7 @@ pub struct CastEnumDrop<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")] +#[diag(hir_typeck_cast_unknown_pointer, code = E0641)] pub struct CastUnknownPointer { #[primary_span] pub span: Span, @@ -600,7 +584,7 @@ pub enum CannotCastToBoolHelp { } #[derive(Diagnostic)] -#[diag(hir_typeck_ctor_is_private, code = "E0603")] +#[diag(hir_typeck_ctor_is_private, code = E0603)] pub struct CtorIsPrivate { #[primary_span] pub span: Span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4b1ad28f0941d..1adde8c21b8e2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -25,8 +25,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, StashKey, + codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, + DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - self.check_expr_with_expectation_and_args(expr, expected, &[]) + self.check_expr_with_expectation_and_args(expr, expected, &[], None) } /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a @@ -187,6 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, args: &'tcx [hir::Expr<'tcx>], + call: Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { if self.tcx().sess.verbose_internals() { // make this code only run with -Zverbose-internals because it is probably slow @@ -208,10 +209,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // without the final expr (e.g. `try { return; }`). We don't want to generate an // unreachable_code lint for it since warnings for autogenerated code are confusing. let is_try_block_generated_unit_expr = match expr.kind { - ExprKind::Call(_, args) if expr.span.is_desugaring(DesugaringKind::TryBlock) => { - args.len() == 1 && args[0].span.is_desugaring(DesugaringKind::TryBlock) + ExprKind::Call(_, [arg]) => { + expr.span.is_desugaring(DesugaringKind::TryBlock) + && arg.span.is_desugaring(DesugaringKind::TryBlock) } - _ => false, }; @@ -220,13 +221,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(expr.hir_id, expr.span, "expression"); } - // Hide the outer diverging and has_errors flags. + // Whether a past expression diverges doesn't affect typechecking of this expression, so we + // reset `diverges` while checking `expr`. let old_diverges = self.diverges.replace(Diverges::Maybe); + if self.is_whole_body.replace(false) { + // If this expression is the whole body and the function diverges because of its + // arguments, we check this here to ensure the body is considered to diverge. + self.diverges.set(self.function_diverges_because_of_empty_arguments.get()) + }; + let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), - ) => self.check_expr_path(qpath, expr, args), + ) => self.check_expr_path(qpath, expr, args, call), _ => self.check_expr_kind(expr, expected), }); let ty = self.resolve_vars_if_possible(ty); @@ -293,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[], None), ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); @@ -313,7 +321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), ExprKind::Become(call) => self.check_expr_become(call, expr), - ExprKind::Let(let_expr) => self.check_expr_let(let_expr), + ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id), ExprKind::Loop(body, _, source, _) => { self.check_expr_loop(body, source, expected, expr) } @@ -507,6 +515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], + call: Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = @@ -520,10 +529,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_error(tcx, e) } Res::Def(DefKind::Variant, _) => { - let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value"); + let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, E0533, "value"); Ty::new_error(tcx, e) } - _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, + _ => { + self.instantiate_value_path( + segs, + opt_ty, + res, + call.map_or(expr.span, |e| e.span), + expr.span, + expr.hir_id, + ) + .0 + } }; if let ty::FnDef(did, _) = *ty.kind() { @@ -578,7 +597,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::BoundRegionConversionTime::FnCall, fn_sig.output(), ); - self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + self.require_type_is_sized_deferred( + output, + call.map_or(expr.span, |e| e.span), + traits::SizedCallReturnType, + ); } // We always require that the type provided as the value for @@ -932,7 +955,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_lhs_assignable( &self, lhs: &'tcx hir::Expr<'tcx>, - err_code: &'static str, + code: ErrCode, op_span: Span, adjust_err: impl FnOnce(&mut Diagnostic), ) { @@ -941,7 +964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut err = self.dcx().struct_span_err(op_span, "invalid left-hand side of assignment"); - err.code(err_code.into()); + err.code(code); err.span_label(lhs.span, "cannot assign to this expression"); self.comes_from_while_condition(lhs.hir_id, |expr| { @@ -977,7 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( lhs.span.shrink_to_hi(), "you might have meant to write a semicolon here", - ";".to_string(), + ";", Applicability::MachineApplicable, ); return true; @@ -1237,7 +1260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diag.emit(); } - self.check_lhs_assignable(lhs, "E0070", span, |err| { + self.check_lhs_assignable(lhs, E0070, span, |err| { if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) { suggest_deref_binop(err, rhs_ty); } @@ -1252,12 +1275,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> { + pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>, hir_id: HirId) -> Ty<'tcx> { // for let statements, this is done in check_stmt let init = let_expr.init; self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression"); // otherwise check exactly as a let statement - self.check_decl(let_expr.into()); + self.check_decl((let_expr, hir_id).into()); // but return a bool, for this is a boolean expression if let Some(error_guaranteed) = let_expr.is_recovered { self.set_tainted_by_errors(error_guaranteed); @@ -1315,7 +1338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_method_call( &self, expr: &'tcx hir::Expr<'tcx>, - segment: &hir::PathSegment<'_>, + segment: &'tcx hir::PathSegment<'tcx>, rcvr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, @@ -1627,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &hir::Expr<'_>, expected: Expectation<'tcx>, - qpath: &QPath<'_>, + qpath: &QPath<'tcx>, fields: &'tcx [hir::ExprField<'tcx>], base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { @@ -1943,6 +1966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let len = remaining_fields.len(); + #[allow(rustc::potential_query_instability)] let mut displayable_field_names: Vec<&str> = remaining_fields.keys().map(|ident| ident.as_str()).collect(); // sorting &str primitives here, sort_unstable is ok @@ -2981,10 +3005,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // fixed expression: if let ExprKind::Lit(lit) = idx.kind && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node - && i < types - .len() - .try_into() - .expect("expected tuple index to be < usize length") + && i.get() + < types + .len() + .try_into() + .expect("expected tuple index to be < usize length") { err.span_suggestion( brackets_span, @@ -3246,6 +3271,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let container = self.to_ty(container).normalized; + if let Some(ident_2) = fields.get(1) + && !self.tcx.features().offset_of_nested + { + rustc_session::parse::feature_err( + &self.tcx.sess, + sym::offset_of_nested, + ident_2.span, + "only a single ident or integer is stable as the field in offset_of", + ) + .emit(); + } + let mut field_indices = Vec::with_capacity(fields.len()); let mut current_container = container; let mut fields = fields.into_iter(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index a4cd9ccc984e1..60eb40bd8fe66 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -2,7 +2,7 @@ use crate::callee::{self, DeferredCallResolution}; use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; -use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, RawTy}; +use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; @@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); let msg = format!("unreachable {kind}"); - self.tcx().struct_span_lint_hir( + self.tcx().node_span_lint( lint::builtin::UNREACHABLE_CODE, id, span, @@ -373,17 +373,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn handle_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx> { - RawTy { raw: ty, normalized: self.normalize(span, ty) } - } - - pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> RawTy<'tcx> { + pub fn to_ty(&self, ast_t: &hir::Ty<'tcx>) -> LoweredTy<'tcx> { let t = self.astconv().ast_ty_to_ty(ast_t); self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None)); - self.handle_raw_ty(ast_t.span, t) + LoweredTy::from_raw(self, ast_t.span, t) } - pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let ty = self.to_ty(ast_ty); debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); @@ -396,7 +392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty.normalized } - pub(super) fn user_args_for_adt(ty: RawTy<'tcx>) -> UserArgs<'tcx> { + pub(super) fn user_args_for_adt(ty: LoweredTy<'tcx>) -> UserArgs<'tcx> { match (ty.raw.kind(), ty.normalized.kind()) { (ty::Adt(_, args), _) => UserArgs { args, user_self_ty: None }, (_, ty::Adt(adt, args)) => UserArgs { @@ -409,7 +405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> { match length { - &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), + hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span), hir::ArrayLen::Body(anon_const) => { let span = self.tcx.def_span(anon_const.def_id); let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id); @@ -801,7 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: hir::HirId, span: Span, args: Option<&'tcx [hir::Expr<'tcx>]>, - ) -> (Res, Option>, &'tcx [hir::PathSegment<'tcx>]) { + ) -> (Res, Option>, &'tcx [hir::PathSegment<'tcx>]) { debug!( "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span @@ -825,7 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We manually call `register_wf_obligation` in the success path // below. let ty = self.astconv().ast_ty_to_ty_in_path(qself); - (self.handle_raw_ty(span, ty), qself, segment) + (LoweredTy::from_raw(self, span, ty), qself, segment) } QPath::LangItem(..) => { bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`") @@ -1073,10 +1069,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, span), level = "debug")] pub fn instantiate_value_path( &self, - segments: &[hir::PathSegment<'_>], - self_ty: Option>, + segments: &'tcx [hir::PathSegment<'tcx>], + self_ty: Option>, res: Res, span: Span, + path_span: Span, hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { let tcx = self.tcx; @@ -1110,7 +1107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match container { ty::TraitContainer => callee::check_legal_trait_for_method_call( tcx, - span, + path_span, None, span, container_id, @@ -1201,8 +1198,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self); let (res, self_ctor_args) = if let Res::SelfCtor(impl_def_id) = res { - let ty = - self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).instantiate_identity()); + let ty = LoweredTy::from_raw( + self, + span, + tcx.at(span).type_of(impl_def_id).instantiate_identity(), + ); match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); @@ -1260,13 +1260,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, path_segs: &'a [PathSeg], infer_args_for_err: &'a FxHashSet, - segments: &'a [hir::PathSegment<'a>], + segments: &'tcx [hir::PathSegment<'tcx>], } impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> { fn args_for_def_id( &mut self, def_id: DefId, - ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { + ) -> (Option<&'a hir::GenericArgs<'tcx>>, bool) { if let Some(&PathSeg(_, index)) = self.path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) { @@ -1287,7 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn provided_kind( &mut self, param: &ty::GenericParamDef, - arg: &GenericArg<'_>, + arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index f42f58322dce2..d30c7a4fb3899 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -6,13 +6,15 @@ use crate::method::MethodCallee; use crate::TupleArgumentsFlag::*; use crate::{errors, Expectation::*}; use crate::{ - struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, Needs, RawTy, + struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, }; use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{pluralize, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; +use rustc_errors::{ + codes::*, pluralize, Applicability, Diagnostic, ErrCode, ErrorGuaranteed, MultiSpan, StashKey, +}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -177,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } - let mut err_code = "E0061"; + let mut err_code = E0061; // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { @@ -187,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Tuple(arg_types) => { // Argument length differs if arg_types.len() != provided_args.len() { - err_code = "E0057"; + err_code = E0057; } let expected_input_tys = match expected_input_tys { Some(expected_input_tys) => match expected_input_tys.get(0) { @@ -358,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if c_variadic && provided_arg_count < minimum_input_count { - err_code = "E0060"; + err_code = E0060; } for arg in provided_args.iter().skip(minimum_input_count) { @@ -424,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|vars| self.resolve_vars_if_possible(vars)), ); - self.report_arg_errors( + self.set_tainted_by_errors(self.report_arg_errors( compatibility_diagonal, formal_and_expected_inputs, provided_args, @@ -433,7 +435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id, call_span, call_expr, - ); + )); } } @@ -443,11 +445,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { formal_and_expected_inputs: IndexVec, Ty<'tcx>)>, provided_args: IndexVec>, c_variadic: bool, - err_code: &str, + err_code: ErrCode, fn_def_id: Option, call_span: Span, call_expr: &'tcx hir::Expr<'tcx>, - ) { + ) -> ErrorGuaranteed { // Next, let's construct the error let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind { hir::ExprKind::Call( @@ -486,10 +488,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let tcx = self.tcx; - // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` - self.set_tainted_by_errors( - tcx.dcx().span_delayed_bug(call_span, "no errors reported for args"), - ); // Get the argument span in the context of the call span so that // suggestions and labels are (more) correct when an arg is a @@ -696,8 +694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(mismatch_idx), is_method, ); - err.emit(); - return; + return err.emit(); } } } @@ -721,11 +718,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if cfg!(debug_assertions) { span_bug!(error_span, "expected errors from argument matrix"); } else { - tcx.dcx().emit_err(errors::ArgMismatchIndeterminate { span: error_span }); + return tcx.dcx().emit_err(errors::ArgMismatchIndeterminate { span: error_span }); } - return; } + let mut reported = None; errors.retain(|error| { let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error @@ -736,16 +733,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { - self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); + reported = Some(self.err_ctxt().report_and_explain_type_error(trace, *e).emit()); return false; } true }); // We're done if we found errors, but we already emitted them. - if errors.is_empty() { - return; + if let Some(reported) = reported { + assert!(errors.is_empty()); + return reported; } + assert!(!errors.is_empty()); // Okay, now that we've emitted the special errors separately, we // are only left missing/extra/swapped and mismatched arguments, both @@ -802,8 +801,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(expected_idx.as_usize()), is_method, ); - err.emit(); - return; + return err.emit(); } let mut err = if formal_and_expected_inputs.len() == provided_args.len() { @@ -1251,7 +1249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - err.emit(); + err.emit() } fn suggest_ptr_null_mut( @@ -1327,7 +1325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_struct_path( &self, - qpath: &QPath<'_>, + qpath: &QPath<'tcx>, hir_id: hir::HirId, ) -> Result<(&'tcx ty::VariantDef, Ty<'tcx>), ErrorGuaranteed> { let path_span = qpath.span(); @@ -1471,6 +1469,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check a `let` statement. pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { self.check_decl(local.into()); + if local.pat.is_never_pattern() { + self.diverges.set(Diverges::Always { + span: local.pat.span, + custom_note: Some("any code following a never pattern is unreachable"), + }); + } } pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { @@ -1783,15 +1787,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The newly resolved definition is written into `type_dependent_defs`. fn finish_resolving_struct_path( &self, - qpath: &QPath<'_>, + qpath: &QPath<'tcx>, path_span: Span, hir_id: hir::HirId, - ) -> (Res, RawTy<'tcx>) { + ) -> (Res, LoweredTy<'tcx>) { match *qpath { QPath::Resolved(ref maybe_qself, path) => { let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw); let ty = self.astconv().res_to_ty(self_ty, path, hir_id, true); - (path.res, self.handle_raw_ty(path_span, ty)) + (path.res, LoweredTy::from_raw(self, path_span, ty)) } QPath::TypeRelative(qself, segment) => { let ty = self.to_ty(qself); @@ -1802,7 +1806,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = result .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); - let ty = self.handle_raw_ty(path_span, ty); + let ty = LoweredTy::from_raw(self, path_span, ty); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. @@ -1812,7 +1816,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } QPath::LangItem(lang_item, span) => { let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id); - (res, self.handle_raw_ty(path_span, ty)) + (res, LoweredTy::from_raw(self, path_span, ty)) } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index f3d70867e375c..ad4546c09b546 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -45,14 +45,6 @@ pub struct FnCtxt<'a, 'tcx> { /// eventually). pub(super) param_env: ty::ParamEnv<'tcx>, - /// Number of errors that had been reported when we started - /// checking this function. On exit, if we find that *more* errors - /// have been reported, we will skip regionck and other work that - /// expects the types within the function to be consistent. - // FIXME(matthewjasper) This should not exist, and it's not correct - // if type checking is run in parallel. - err_count_on_creation: usize, - /// If `Some`, this stores coercion information for returned /// expressions. If `None`, this is in a context where return is /// inappropriate, such as a const expression. @@ -103,6 +95,13 @@ pub struct FnCtxt<'a, 'tcx> { /// the diverges flag is set to something other than `Maybe`. pub(super) diverges: Cell, + /// If one of the function arguments is a never pattern, this counts as diverging code. This + /// affect typechecking of the function body. + pub(super) function_diverges_because_of_empty_arguments: Cell, + + /// Whether the currently checked node is the whole body of the function. + pub(super) is_whole_body: Cell, + pub(super) enclosing_breakables: RefCell>, pub(super) inh: &'a Inherited<'tcx>, @@ -119,11 +118,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { FnCtxt { body_id, param_env, - err_count_on_creation: inh.tcx.dcx().err_count(), ret_coercion: None, ret_coercion_span: Cell::new(None), coroutine_types: None, diverges: Cell::new(Diverges::Maybe), + function_diverges_because_of_empty_arguments: Cell::new(Diverges::Maybe), + is_whole_body: Cell::new(false), enclosing_breakables: RefCell::new(EnclosingBreakables { stack: Vec::new(), by_id: Default::default(), @@ -186,10 +186,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), } } - - pub fn errors_reported_since_creation(&self) -> bool { - self.dcx().err_count() > self.err_count_on_creation - } } impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { @@ -283,7 +279,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { let trait_ref = self.instantiate_binder_with_fresh_vars( @@ -344,14 +340,30 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } -/// Represents a user-provided type in the raw form (never normalized). +/// The `ty` representation of a user-provided type. Depending on the use-site +/// we want to either use the unnormalized or the normalized form of this type. /// /// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`, /// and the API in this module, which expect `Ty` to be fully normalized. #[derive(Clone, Copy, Debug)] -pub struct RawTy<'tcx> { +pub struct LoweredTy<'tcx> { + /// The unnormalized type provided by the user. pub raw: Ty<'tcx>, /// The normalized form of `raw`, stored here for efficiency. pub normalized: Ty<'tcx>, } + +impl<'tcx> LoweredTy<'tcx> { + pub fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> { + // FIXME(-Znext-solver): We're still figuring out how to best handle + // normalization and this doesn't feel too great. We should look at this + // code again before stabilizing it. + let normalized = if fcx.next_trait_solver() { + fcx.try_structurally_resolve_type(span, raw) + } else { + fcx.normalize(span, raw) + }; + LoweredTy { raw, normalized } + } +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 81b7de7f63497..5395ffda1d134 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -11,6 +11,7 @@ use crate::ty::TypeAndMut; use core::cmp::min; use core::iter; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; +use rustc_data_structures::packed::Pu128; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -260,6 +261,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.kind && let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr) && self.can_coerce(recv_ty, expected) + && let name = method.name.as_str() + && (name.starts_with("to_") || name.starts_with("as_") || name == "into") { let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) { expr.span.with_lo(recv_span.hi()) @@ -784,7 +787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_missing_return_type( &self, err: &mut Diagnostic, - fn_decl: &hir::FnDecl<'_>, + fn_decl: &hir::FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, can_suggest: bool, @@ -995,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diagnostic, expr: &'tcx hir::Expr<'tcx>, - fn_decl: &hir::FnDecl<'_>, + fn_decl: &hir::FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, id: hir::HirId, @@ -1409,8 +1412,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let (_, suffix) = snippet.split_at(snippet.len() - 3); let value = match suffix { - "f32" => (lit - 0xf32) / (16 * 16 * 16), - "f64" => (lit - 0xf64) / (16 * 16 * 16), + "f32" => (lit.get() - 0xf32) / (16 * 16 * 16), + "f64" => (lit.get() - 0xf64) / (16 * 16 * 16), _ => return false, }; err.span_suggestions( @@ -1440,7 +1443,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Provided expression needs to be a literal `0`. - let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(0, _), span }) = expr.kind else { + let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(Pu128(0), _), span }) = expr.kind + else { return false; }; @@ -1468,7 +1472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_associated_const( &self, err: &mut Diagnostic, - expr: &hir::Expr<'_>, + expr: &hir::Expr<'tcx>, expected_ty: Ty<'tcx>, ) -> bool { let Some((DefKind::AssocFn, old_def_id)) = @@ -2038,7 +2042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_is_local = sole_field.did.is_local(); let field_is_accessible = sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) - // Skip suggestions for unstable public fields (for example `Pin::pointer`) + // Skip suggestions for unstable public fields (for example `Pin::__pointer`) && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked); if !field_is_local && !field_is_accessible { @@ -2138,46 +2142,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; - let (adt, unwrap) = match expected.kind() { + let (adt, substs, unwrap) = match expected.kind() { // In case Option is wanted, but * is provided, suggest calling new - ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { - // Unwrap option - let ty::Adt(adt, _) = args.type_at(0).kind() else { + ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + let nonzero_type = substs.type_at(0); // Unwrap option type. + let ty::Adt(adt, substs) = nonzero_type.kind() else { return false; }; - - (adt, "") + (adt, substs, "") } - // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types - ty::Adt(adt, _) => (adt, ".unwrap()"), + // In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types. + ty::Adt(adt, substs) => (adt, substs, ".unwrap()"), _ => return false, }; - let map = [ - (sym::NonZeroU8, tcx.types.u8), - (sym::NonZeroU16, tcx.types.u16), - (sym::NonZeroU32, tcx.types.u32), - (sym::NonZeroU64, tcx.types.u64), - (sym::NonZeroU128, tcx.types.u128), - (sym::NonZeroI8, tcx.types.i8), - (sym::NonZeroI16, tcx.types.i16), - (sym::NonZeroI32, tcx.types.i32), - (sym::NonZeroI64, tcx.types.i64), - (sym::NonZeroI128, tcx.types.i128), + if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + return false; + } + + // FIXME: This can be simplified once `NonZero` is stable. + let coercable_types = [ + ("NonZeroU8", tcx.types.u8), + ("NonZeroU16", tcx.types.u16), + ("NonZeroU32", tcx.types.u32), + ("NonZeroU64", tcx.types.u64), + ("NonZeroU128", tcx.types.u128), + ("NonZeroI8", tcx.types.i8), + ("NonZeroI16", tcx.types.i16), + ("NonZeroI32", tcx.types.i32), + ("NonZeroI64", tcx.types.i64), + ("NonZeroI128", tcx.types.i128), ]; - let Some((s, _)) = map.iter().find(|&&(s, t)| { - self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t) + let int_type = substs.type_at(0); + + let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { + if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None } }) else { return false; }; - let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); - err.multipart_suggestion( - format!("consider calling `{s}::new`"), + format!("consider calling `{nonzero_alias}::new`"), vec![ - (expr.span.shrink_to_lo(), format!("{path}::new(")), + (expr.span.shrink_to_lo(), format!("{nonzero_alias}::new(")), (expr.span.shrink_to_hi(), format!("){unwrap}")), ], Applicability::MaybeIncorrect, diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 52dc1e8591656..f9af357f0e79e 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -48,9 +48,9 @@ impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { } } -impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { - fn from(let_expr: &'a hir::Let<'a>) -> Self { - let hir::Let { hir_id, pat, ty, span, init, is_recovered: _ } = *let_expr; +impl<'a> From<(&'a hir::Let<'a>, hir::HirId)> for Declaration<'a> { + fn from((let_expr, hir_id): (&'a hir::Let<'a>, hir::HirId)) -> Self { + let hir::Let { pat, ty, span, init, is_recovered: _ } = *let_expr; Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } @@ -125,9 +125,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { intravisit::walk_local(self, local) } - fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { - self.declare(let_expr.into()); - intravisit::walk_let_expr(self, let_expr); + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Let(let_expr) = expr.kind { + self.declare((let_expr, expr.hir_id).into()); + } + intravisit::walk_expr(self, expr) } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index e087733130e33..2dee5093e876d 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -1,5 +1,5 @@ use hir::HirId; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_index::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 67c35d717a1ec..deb3ad2edc740 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,7 +5,6 @@ #![feature(box_patterns)] #![feature(min_specialization)] #![feature(control_flow_enum)] -#![recursion_limit = "256"] #[macro_use] extern crate tracing; @@ -49,10 +48,10 @@ use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; use crate::diverges::Diverges; use crate::expectation::Expectation; -use crate::fn_ctxt::RawTy; +use crate::fn_ctxt::LoweredTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, ErrCode, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -60,6 +59,7 @@ use rustc_hir::{HirIdMap, Node}; use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::check_abi; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::traits::ObligationInspector; use rustc_middle::query::Providers; use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -71,7 +71,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[macro_export] macro_rules! type_error_struct { - ($dcx:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + ($dcx:expr, $span:expr, $typ:expr, $code:expr, $($message:tt)*) => ({ let mut err = rustc_errors::struct_span_code_err!($dcx, $span, $code, $($message)*); if $typ.references_error() { @@ -139,7 +139,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity(); - typeck_with_fallback(tcx, def_id, fallback) + typeck_with_fallback(tcx, def_id, fallback, None) } /// Used only to get `TypeckResults` for type inference during error recovery. @@ -149,14 +149,28 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used") }; - typeck_with_fallback(tcx, def_id, fallback) + typeck_with_fallback(tcx, def_id, fallback, None) } -#[instrument(level = "debug", skip(tcx, fallback), ret)] +/// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation. +/// Inspecting obligations only works with the new trait solver. +/// This function is *only to be used* by external tools, it should not be +/// called from within rustc. Note, this is not a query, and thus is not cached. +pub fn inspect_typeck<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + inspect: ObligationInspector<'tcx>, +) -> &'tcx ty::TypeckResults<'tcx> { + let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity(); + typeck_with_fallback(tcx, def_id, fallback, Some(inspect)) +} + +#[instrument(level = "debug", skip(tcx, fallback, inspector), ret)] fn typeck_with_fallback<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, fallback: impl Fn() -> Ty<'tcx> + 'tcx, + inspector: Option>, ) -> &'tcx ty::TypeckResults<'tcx> { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". @@ -178,6 +192,9 @@ fn typeck_with_fallback<'tcx>( let param_env = tcx.param_env(def_id); let inh = Inherited::new(tcx, def_id); + if let Some(inspector) = inspector { + inh.infcx.attach_obligation_inspector(inspector); + } let mut fcx = FnCtxt::new(&inh, param_env, def_id); if let Some(hir::FnSig { header, decl, .. }) = fn_sig { @@ -358,7 +375,7 @@ fn report_unexpected_variant_res( res: Res, qpath: &hir::QPath<'_>, span: Span, - err_code: &str, + err_code: ErrCode, expected: &str, ) -> ErrorGuaranteed { let res_descr = match res { @@ -369,9 +386,9 @@ fn report_unexpected_variant_res( let err = tcx .dcx() .struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`")) - .with_code(err_code.into()); + .with_code(err_code); match res { - Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => { + Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == E0164 => { let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html"; err.with_span_label(span, "`fn` calls are not allowed in patterns") .with_help(format!("for more information, visit {patterns_url}")) @@ -427,15 +444,6 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! { diag.emit() } -/// `expected` here is the expected number of explicit generic arguments on the trait. -fn has_expected_num_generic_args(tcx: TyCtxt<'_>, trait_did: DefId, expected: usize) -> bool { - let generics = tcx.generics_of(trait_did); - generics.count() - == expected - + if generics.has_self { 1 } else { 0 } - + if generics.host_effect_index.is_some() { 1 } else { 0 } -} - pub fn provide(providers: &mut Providers) { method::provide(providers); *providers = Providers { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index b2ead3cd40b74..6f18cc51b11c1 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -50,7 +50,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment<'_>, + segment: &'tcx hir::PathSegment<'tcx>, ) -> ConfirmResult<'tcx> { debug!( "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})", @@ -68,7 +68,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment<'_>, + segment: &hir::PathSegment<'tcx>, ) -> ConfirmResult<'tcx> { let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); confirm_cx.skip_record_for_diagnostics = true; @@ -90,7 +90,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { &mut self, unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment<'_>, + segment: &hir::PathSegment<'tcx>, ) -> ConfirmResult<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. let self_ty = self.adjust_self_ty(unadjusted_self_ty, pick); @@ -346,7 +346,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn instantiate_method_args( &mut self, pick: &probe::Pick<'tcx>, - seg: &hir::PathSegment<'_>, + seg: &hir::PathSegment<'tcx>, parent_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { // Determine the values for the generic parameters of the method. @@ -370,13 +370,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { struct MethodSubstsCtxt<'a, 'tcx> { cfcx: &'a ConfirmContext<'a, 'tcx>, pick: &'a probe::Pick<'tcx>, - seg: &'a hir::PathSegment<'a>, + seg: &'a hir::PathSegment<'tcx>, } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> { fn args_for_def_id( &mut self, def_id: DefId, - ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { + ) -> (Option<&'a hir::GenericArgs<'tcx>>, bool) { if def_id == self.pick.item.def_id { if let Some(data) = self.seg.args { return (Some(data), false); @@ -388,7 +388,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn provided_kind( &mut self, param: &ty::GenericParamDef, - arg: &GenericArg<'_>, + arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index c746fb8af89a2..804d6ff2cb577 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -10,7 +10,6 @@ mod suggest; pub use self::suggest::SelfSource; pub use self::MethodError::*; -use crate::errors::OpMethodGenericParams; use crate::FnCtxt; use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage}; use rustc_hir as hir; @@ -177,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn lookup_method( &self, self_ty: Ty<'tcx>, - segment: &hir::PathSegment<'_>, + segment: &'tcx hir::PathSegment<'tcx>, span: Span, call_expr: &'tcx hir::Expr<'tcx>, self_expr: &'tcx hir::Expr<'tcx>, @@ -255,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn lookup_method_for_diagnostic( &self, self_ty: Ty<'tcx>, - segment: &hir::PathSegment<'_>, + segment: &hir::PathSegment<'tcx>, span: Span, call_expr: &'tcx hir::Expr<'tcx>, self_expr: &'tcx hir::Expr<'tcx>, @@ -385,26 +384,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type parameters or early-bound regions. let tcx = self.tcx; let Some(method_item) = self.associated_value(trait_def_id, m_name) else { - tcx.dcx().span_delayed_bug( - obligation.cause.span, - "operator trait does not have corresponding operator method", - ); - return None; + bug!("expected associated item for operator trait") }; - if method_item.kind != ty::AssocKind::Fn { - self.dcx().span_delayed_bug(tcx.def_span(method_item.def_id), "not a method"); - return None; - } - let def_id = method_item.def_id; - let generics = tcx.generics_of(def_id); - - if generics.params.len() != 0 { - tcx.dcx().emit_fatal(OpMethodGenericParams { - span: tcx.def_span(method_item.def_id), - method_name: m_name.to_string(), - }); + if method_item.kind != ty::AssocKind::Fn { + span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function"); } debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 43d258de6ca7a..0e43cb40485a5 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Inherent impls only require not relying on autoref and autoderef in order to // ensure that the trait implementation won't be used - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( prelude_or_array_lint, self_expr.hir_id, self_expr.span, @@ -127,7 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // trait implementations require full disambiguation to not clash with the new prelude // additions (i.e. convert from dot-call to fully-qualified call) - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( prelude_or_array_lint, call_expr.hir_id, call_expr.span, @@ -238,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( RUST_2021_PRELUDE_COLLISIONS, expr_id, span, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4dc802008d032..a446c7aa42bb6 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.tcx.sess.at_least_rust_2018() { self.dcx().emit_err(MethodCallOnUnknownRawPointee { span }); } else { - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( lint::builtin::TYVAR_BEHIND_RAW_POINTER, scope_expr_id, span, @@ -746,11 +746,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args); debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); - // We can't use normalize_associated_types_in as it will pollute the + // We can't use `FnCtxt::normalize` as it will pollute the // fcx's fulfillment context after this probe is over. + // // Note: we only normalize `xform_self_ty` here since the normalization // of the return type can lead to inference results that prohibit // valid candidates from being found, see issue #85671 + // // FIXME Postponing the normalization of the return type likely only hides a deeper bug, // which might be caused by the `param_env` itself. The clauses of the `param_env` // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, @@ -1380,7 +1382,7 @@ impl<'tcx> Pick<'tcx> { return; } let def_kind = self.item.kind.as_def_kind(); - tcx.struct_span_lint_hir( + tcx.node_span_lint( lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0b8a25eedafad..007df203f7117 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3,17 +3,17 @@ // ignore-tidy-filelength -use crate::errors; -use crate::errors::{CandidateTraitNote, NoAssociatedItem}; +use crate::errors::{self, CandidateTraitNote, NoAssociatedItem}; use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; use rustc_attr::parse_confusables; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; -use rustc_errors::StashKey; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -57,6 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.kind() { // Not all of these (e.g., unsafe fns) implement `FnOnce`, // so we look for these beforehand. + // FIXME(async_closures): These don't impl `FnOnce` by default. ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true, // If it's not a simple function, look for things which implement `FnOnce`. _ => { @@ -459,22 +460,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - let ty_span = match rcvr_ty.kind() { + let mut ty_span = match rcvr_ty.kind() { ty::Param(param_type) => { Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id())) } ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())), _ => None, }; - if let Some(span) = ty_span { - err.span_label( - span, - format!( - "{item_kind} `{item_name}` not found for this {}", - rcvr_ty.prefix_string(self.tcx) - ), - ); - } if let SelfSource::MethodCall(rcvr_expr) = source { self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| { @@ -547,8 +539,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - let mut bound_spans = vec![]; + let mut bound_spans: SortedMap> = Default::default(); let mut restrict_type_params = false; + let mut suggested_derive = false; let mut unsatisfied_bounds = false; if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) { let msg = "consider using `len` instead"; @@ -563,6 +556,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement" )); } + } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) { + // We special case the situation where we are looking for `_` in + // `::method` because otherwise the machinery will look for blanket + // implementations that have unsatisfied trait bounds to suggest, leading us to claim + // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord` + // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so + // that `impl Ord for T` can apply", which is not what we want. We have a type + // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict + // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling + // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates` + // suggestions. } else if !unsatisfied_predicates.is_empty() { let mut type_params = FxIndexMap::default(); @@ -642,19 +646,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false }; let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { - let msg = format!( - "doesn't satisfy `{}`", - if obligation.len() > 50 { quiet } else { obligation } - ); + let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation }); match &self_ty.kind() { // Point at the type that couldn't satisfy the bound. - ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)), + ty::Adt(def, _) => { + bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) + } // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { - bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone())) + bound_spans + .get_mut_or_insert_default(tcx.def_span(tr.def_id)) + .push(msg.clone()); } ty::ExistentialPredicate::Projection(_) | ty::ExistentialPredicate::AutoTrait(_) => {} @@ -662,8 +667,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } // Point at the closure that couldn't satisfy the bound. - ty::Closure(def_id, _) => bound_spans - .push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))), + ty::Closure(def_id, _) => { + bound_spans + .get_mut_or_insert_default(tcx.def_span(*def_id)) + .push(format!("`{quiet}`")); + } _ => {} } }; @@ -921,20 +929,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .enumerate() .collect::>(); - for ((span, add_where_or_comma), obligations) in type_params.into_iter() { - restrict_type_params = true; - // #74886: Sort here so that the output is always the same. - let obligations = obligations.into_sorted_stable_ord(); - err.span_suggestion_verbose( - span, - format!( - "consider restricting the type parameter{s} to satisfy the \ - trait bound{s}", - s = pluralize!(obligations.len()) - ), - format!("{} {}", add_where_or_comma, obligations.join(", ")), - Applicability::MaybeIncorrect, - ); + if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) { + for ((span, add_where_or_comma), obligations) in type_params.into_iter() { + restrict_type_params = true; + // #74886: Sort here so that the output is always the same. + let obligations = obligations.into_sorted_stable_ord(); + err.span_suggestion_verbose( + span, + format!( + "consider restricting the type parameter{s} to satisfy the trait \ + bound{s}", + s = pluralize!(obligations.len()) + ), + format!("{} {}", add_where_or_comma, obligations.join(", ")), + Applicability::MaybeIncorrect, + ); + } } bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically. @@ -982,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the following trait bounds were not satisfied:\n{bound_list}" )); } - self.suggest_derive(&mut err, unsatisfied_predicates); + suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates); unsatisfied_bounds = true; } @@ -1121,9 +1131,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name.span, format!( "you might have meant to use `{}`", - inherent_method.name.as_str() + inherent_method.name ), - inherent_method.name.as_str(), + inherent_method.name, Applicability::MaybeIncorrect, ); break 'outer; @@ -1170,13 +1180,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name); - bound_spans.sort(); - bound_spans.dedup(); - for (span, msg) in bound_spans.into_iter() { + for (span, mut bounds) in bound_spans { + if !tcx.sess.source_map().is_span_accessible(span) { + continue; + } + bounds.sort(); + bounds.dedup(); + let pre = if Some(span) == ty_span { + ty_span.take(); + format!( + "{item_kind} `{item_name}` not found for this {} because it ", + rcvr_ty.prefix_string(self.tcx) + ) + } else { + String::new() + }; + let msg = match &bounds[..] { + [bound] => format!("{pre}doesn't satisfy {bound}"), + bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()), + [bounds @ .., last] => { + format!("{pre}doesn't satisfy {} or {last}", bounds.join(", ")) + } + [] => unreachable!(), + }; err.span_label(span, msg); } + if let Some(span) = ty_span { + err.span_label( + span, + format!( + "{item_kind} `{item_name}` not found for this {}", + rcvr_ty.prefix_string(self.tcx) + ), + ); + } - if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params { + if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive { } else { self.suggest_traits_to_import( &mut err, @@ -1186,7 +1225,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args.map(|args| args.len() + 1), source, no_match_data.out_of_scope_traits.clone(), - unsatisfied_predicates, static_candidates, unsatisfied_bounds, expected.only_has_type(self), @@ -1301,7 +1339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); - return Some(err); + Some(err) } fn note_candidates_on_method_error( @@ -1601,23 +1639,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.ty_to_value_string(rcvr_ty.peel_refs()) }; if let SelfSource::MethodCall(_) = source { - let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) - && let Some(assoc) = self.associated_value(*impl_did, item_name) - && assoc.kind == ty::AssocKind::Fn - { + let first_arg = static_candidates.get(0).and_then(|candidate_source| { + let (assoc_did, self_ty) = match candidate_source { + CandidateSource::Impl(impl_did) => { + (*impl_did, self.tcx.type_of(*impl_did).instantiate_identity()) + } + CandidateSource::Trait(trait_did) => (*trait_did, rcvr_ty), + }; + + let assoc = self.associated_value(assoc_did, item_name)?; + if assoc.kind != ty::AssocKind::Fn { + return None; + } + + // for CandidateSource::Impl, `Self` will be instantiated to a concrete type + // but for CandidateSource::Trait, `Self` is still `Self` let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity(); sig.inputs().skip_binder().get(0).and_then(|first| { - let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity(); // if the type of first arg is the same as the current impl type, we should take the first arg into assoc function - if first.peel_refs() == impl_ty { + let first_ty = first.peel_refs(); + if first_ty == self_ty || first_ty == self.tcx.types.self_param { Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) } else { None } }) - } else { - None - }; + }); + let mut applicability = Applicability::MachineApplicable; let args = if let SelfSource::MethodCall(receiver) = source && let Some(args) = args @@ -1985,7 +2033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diag.span_suggestion_verbose( sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(), "you may have meant to call an instance method", - ".".to_string(), + ".", Applicability::MaybeIncorrect, ); } @@ -2436,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Option>, Option>, )], - ) { + ) -> bool { let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates); derives.sort(); derives.dedup(); @@ -2461,6 +2509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } + !derives_grouped.is_empty() } fn note_derefed_ty_has_method( @@ -2663,11 +2712,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inputs_len: Option, source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec, - unsatisfied_predicates: &[( - ty::Predicate<'tcx>, - Option>, - Option>, - )], static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option>, @@ -2884,19 +2928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - unsatisfied_predicates.iter().all(|(p, _, _)| { - match p.kind().skip_binder() { - // Hide traits if they are present in predicates as they can be fixed without - // having to implement them. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { - t.def_id() == info.def_id - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { - p.projection_ty.def_id == info.def_id - } - _ => false, - } - }) && (type_is_local || info.def_id.is_local()) + (type_is_local || info.def_id.is_local()) && !self.tcx.trait_is_auto(info.def_id) && self .associated_value(info.def_id, item_name) diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index ee411f8ed5f1c..9ce6189856194 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -1,10 +1,11 @@ //! Code related to processing overloaded binary and unary operators. use super::method::MethodCallee; -use super::{has_expected_num_generic_args, FnCtxt}; +use super::FnCtxt; use crate::Expectation; use rustc_ast as ast; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_data_structures::packed::Pu128; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::ObligationCauseCode; @@ -43,7 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_ty }; - self.check_lhs_assignable(lhs, "E0067", op.span, |err| { + self.check_lhs_assignable(lhs, E0067, op.span, |err| { if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { if self .lookup_op_method( @@ -834,7 +835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Expr { kind: hir::ExprKind::Lit(Spanned { - node: ast::LitKind::Int(1, _), + node: ast::LitKind::Int(Pu128(1), _), .. }), .. @@ -886,25 +887,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, op, opname, trait_did ); - // Catches cases like #83893, where a lang item is declared with the - // wrong number of generic arguments. Should have yielded an error - // elsewhere by now, but we have to catch it here so that we do not - // index `other_tys` out of bounds (if the lang item has too many - // generic arguments, `other_tys` is too short). - if !has_expected_num_generic_args( - self.tcx, - trait_did, - match op { - // Binary ops have a generic right-hand side, unary ops don't - Op::Binary(..) => 1, - Op::Unary(..) => 0, - }, - ) { - self.dcx() - .span_delayed_bug(span, "operator didn't have the right number of generic args"); - return Err(vec![]); - } - let opname = Ident::with_dummy_span(opname); let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); let input_types = opt_rhs_ty.as_slice(); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index fe8c36dbe069d..fcf4b59e93fcd 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,10 +1,10 @@ use crate::gather_locals::DeclOrigin; -use crate::{errors, FnCtxt, RawTy}; +use crate::{errors, FnCtxt, LoweredTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -178,8 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match pat.kind { PatKind::Wild | PatKind::Err(_) => expected, - // FIXME(never_patterns): check the type is uninhabited. If that is not possible within - // typeck, do that in a later phase. + // We allow any type here; we ensure that the type is uninhabited during match checking. PatKind::Never => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), @@ -577,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if (lhs, rhs).references_error() { err.downgrade_to_delayed_bug(); } - if self.tcx.sess.teach(&err.get_code().unwrap()) { + if self.tcx.sess.teach(err.code.unwrap()) { err.note( "In a match expression, only numbers and characters can be matched \ against a range. This is because the compiler checks that the range \ @@ -848,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { type_str ); err.span_label(span, format!("type `{type_str}` cannot be dereferenced")); - if self.tcx.sess.teach(&err.get_code().unwrap()) { + if self.tcx.sess.teach(err.code.unwrap()) { err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ); } return Err(err.emit()); @@ -859,7 +858,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_struct( &self, pat: &'tcx Pat<'tcx>, - qpath: &hir::QPath<'_>, + qpath: &hir::QPath<'tcx>, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, @@ -892,7 +891,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'tcx>, qpath: &hir::QPath<'_>, - path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), + path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), expected: Ty<'tcx>, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { @@ -908,7 +907,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { let expected = "unit struct, unit variant or constant"; - let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected); + let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0533, expected); return Ty::new_error(tcx, e); } Res::SelfCtor(..) @@ -924,7 +923,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the path. let (pat_ty, pat_res) = - self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); + self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); if let Some(err) = self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) { @@ -1062,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let report_unexpected_res = |res: Res| { let expected = "tuple struct or tuple variant"; - let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0164", expected); + let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0164, expected); on_error(e); e }; @@ -1079,7 +1078,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the path. let (pat_ty, res) = - self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); + self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); if !pat_ty.is_fn() { let e = report_unexpected_res(res); return Ty::new_error(tcx, e); @@ -1670,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if tcx.sess.teach(&err.get_code().unwrap()) { + if tcx.sess.teach(err.code.unwrap()) { err.note( "This error indicates that a struct pattern attempted to \ extract a nonexistent field from a struct. Struct fields \ @@ -1841,7 +1840,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &unmentioned_fields.iter().map(|(_, i)| i).collect::>(), ); - self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| { + self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| { lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); lint.help( "ensure that all fields are mentioned explicitly by adding the suggested fields", diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index d626176377283..1eaaf30043b44 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -1,5 +1,5 @@ use crate::method::MethodCallee; -use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp}; +use crate::{FnCtxt, PlaceOp}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -209,20 +209,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - // If the lang item was declared incorrectly, stop here so that we don't - // run into an ICE (#83893). The error is reported where the lang item is - // declared. - if !has_expected_num_generic_args( - self.tcx, - imm_tr, - match op { - PlaceOp::Deref => 0, - PlaceOp::Index => 1, - }, - ) { - return None; - } - self.lookup_method_in_trait( self.misc(span), Ident::with_dummy_span(imm_op), @@ -249,20 +235,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - // If the lang item was declared incorrectly, stop here so that we don't - // run into an ICE (#83893). The error is reported where the lang item is - // declared. - if !has_expected_num_generic_args( - self.tcx, - mut_tr, - match op { - PlaceOp::Deref => 0, - PlaceOp::Index => 1, - }, - ) { - return None; - } - self.lookup_method_in_trait( self.misc(span), Ident::with_dummy_span(mut_op), diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index f6b05e1b35a6c..c4773a885218a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -170,9 +170,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); - let (closure_def_id, args) = match *ty.kind() { - ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)), - ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args)), + let (closure_def_id, args, infer_kind) = match *ty.kind() { + ty::Closure(def_id, args) => { + (def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none()) + } + ty::CoroutineClosure(def_id, args) => { + (def_id, UpvarArgs::CoroutineClosure(args), self.closure_kind(ty).is_none()) + } + ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false), ty::Error(_) => { // #51714: skip analysis when we have already encountered type errors return; @@ -188,18 +193,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let closure_def_id = closure_def_id.expect_local(); - let infer_kind = if let UpvarArgs::Closure(closure_args) = args { - self.closure_kind(closure_args).is_none().then_some(closure_args) - } else { - None - }; - assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id); let mut delegate = InferBorrowKind { closure_def_id, capture_information: Default::default(), fake_reads: Default::default(), }; + + // As noted in `lower_coroutine_body_with_moved_arguments`, we default the capture mode + // to `ByRef` for the `async {}` block internal to async fns/closure. This means + // that we would *not* be moving all of the parameters into the async block by default. + // + // We force all of these arguments to be captured by move before we do expr use analysis. + // + // FIXME(async_closures): This could be cleaned up. It's a bit janky that we're just + // moving all of the `LocalSource::AsyncFn` locals here. + if let Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Fn | hir::CoroutineSource::Closure, + )) = self.tcx.coroutine_kind(closure_def_id) + { + let hir::ExprKind::Block(block, _) = body.value.kind else { + bug!(); + }; + for stmt in block.stmts { + let hir::StmtKind::Local(hir::Local { + init: Some(init), + source: hir::LocalSource::AsyncFn, + pat, + .. + }) = stmt.kind + else { + bug!(); + }; + let hir::PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), _, _, _) = + pat.kind + else { + // Complex pattern, skip the non-upvar local. + continue; + }; + let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = init.kind else { + bug!(); + }; + let hir::def::Res::Local(local_id) = path.res else { + bug!(); + }; + let place = self.place_for_root_variable(closure_def_id, local_id); + delegate.capture_information.push(( + place, + ty::CaptureInfo { + capture_kind_expr_id: Some(init.hir_id), + path_expr_id: Some(init.hir_id), + capture_kind: UpvarCapture::ByValue, + }, + )); + } + } + euv::ExprUseVisitor::new( &mut delegate, &self.infcx, @@ -257,10 +307,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let before_feature_tys = self.final_upvar_tys(closure_def_id); - if let Some(closure_args) = infer_kind { + if infer_kind { // Unify the (as yet unbound) type variable in the closure // args with the kind we inferred. - let closure_kind_ty = closure_args.as_closure().kind_ty(); + let closure_kind_ty = match args { + UpvarArgs::Closure(args) => args.as_closure().kind_ty(), + UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().kind_ty(), + UpvarArgs::Coroutine(_) => unreachable!("coroutines don't have an inferred kind"), + }; self.demand_eqtype( span, Ty::from_closure_kind(self.tcx, closure_kind), @@ -282,6 +336,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // For coroutine-closures, we additionally must compute the + // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref + // version of the coroutine-closure's output coroutine. + if let UpvarArgs::CoroutineClosure(args) = args { + let closure_env_region: ty::Region<'_> = ty::Region::new_bound( + self.tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(0), + kind: ty::BoundRegionKind::BrEnv, + }, + ); + let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter( + self.tcx, + self.typeck_results + .borrow() + .closure_min_captures_flattened( + self.tcx.coroutine_for_closure(closure_def_id).expect_local(), + ) + // Skip the captures that are just moving the closure's args + // into the coroutine. These are always by move, and we append + // those later in the `CoroutineClosureSignature` helper functions. + .skip( + args.as_coroutine_closure() + .coroutine_closure_sig() + .skip_binder() + .tupled_inputs_ty + .tuple_fields() + .len(), + ) + .map(|captured_place| { + let upvar_ty = captured_place.place.ty(); + let capture = captured_place.info.capture_kind; + // Not all upvars are captured by ref, so use + // `apply_capture_kind_on_capture_ty` to ensure that we + // compute the right captured type. + apply_capture_kind_on_capture_ty( + self.tcx, + upvar_ty, + capture, + Some(closure_env_region), + ) + }), + ); + let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( + self.tcx, + ty::Binder::bind_with_vars( + self.tcx.mk_fn_sig( + [], + tupled_upvars_ty_for_borrow, + false, + hir::Unsafety::Normal, + rustc_target::spec::abi::Abi::Rust, + ), + self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region( + ty::BoundRegionKind::BrEnv, + )]), + ), + ); + self.demand_eqtype( + span, + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + coroutine_captures_by_ref_ty, + ); + + // Additionally, we can now constrain the coroutine's kind type. + let ty::Coroutine(_, coroutine_args) = + *self.typeck_results.borrow().expr_ty(body.value).kind() + else { + bug!(); + }; + self.demand_eqtype( + span, + coroutine_args.as_coroutine().kind_ty(), + Ty::from_closure_kind(self.tcx, closure_kind), + ); + } + self.log_closure_min_capture_info(closure_def_id, span); // Now that we've analyzed the closure, we know how each @@ -551,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Go through each entry in the current list of min_captures - // - if ancestor is found, update it's capture kind to account for current place's + // - if ancestor is found, update its capture kind to account for current place's // capture information. // // - if descendant is found, remove it from the list, and update the current place's @@ -754,7 +886,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); let closure_head_span = self.tcx.def_span(closure_def_id); - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_hir_id, closure_head_span, diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 6f909a0cc9db4..aa6f184a2d7d1 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -131,7 +131,7 @@ impl<'tcx> IfThisChanged<'tcx> { None => DepNode::from_def_path_hash( self.tcx, def_path_hash, - dep_kinds::hir_owner_nodes, + dep_kinds::opt_hir_owner_nodes, ), Some(n) => { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 367a15e144304..82f02b7d47aac 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -5,7 +5,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 842cc9fae9b4d..14cc8c260e218 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -57,8 +57,8 @@ const BASE_FN: &[&str] = &[ /// DepNodes for Hir, which is pretty much everything const BASE_HIR: &[&str] = &[ - // hir_owner_nodes should be computed for all nodes - label_strs::hir_owner_nodes, + // opt_hir_owner_nodes should be computed for all nodes + label_strs::opt_hir_owner_nodes, ]; /// `impl` implementation of struct/trait diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index e18b1365d9c02..2578f284dee7a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -312,7 +312,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone(); - if let Some(_) = sess.dcx().has_errors_or_span_delayed_bugs() { + if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() { // If there have been any errors during compilation, we don't want to // publish this session directory. Rather, we'll just delete it. diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 08b7d08bcc006..ff0c58d09de2d 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -31,8 +31,8 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { if sess.opts.incremental.is_none() { return; } - // This is going to be deleted in finalize_session_directory, so let's not create it - if let Some(_) = sess.dcx().has_errors_or_span_delayed_bugs() { + // This is going to be deleted in finalize_session_directory, so let's not create it. + if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() { return; } @@ -87,7 +87,7 @@ pub fn save_work_product_index( return; } // This is going to be deleted in finalize_session_directory, so let's not create it - if let Some(_) = sess.dcx().has_errors_or_span_delayed_bugs() { + if sess.dcx().has_errors_or_lint_errors().is_some() { return; } diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index dfa3ced9dc149..12f8e42c78f94 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -284,7 +284,7 @@ impl BitSet { not_already } - fn last_set_in(&self, range: impl RangeBounds) -> Option { + pub fn last_set_in(&self, range: impl RangeBounds) -> Option { let (start, end) = inclusive_start_end(range, self.domain_size)?; let (start_word_index, _) = word_index_and_mask(start); let (end_word_index, end_mask) = word_index_and_mask(end); @@ -1299,7 +1299,7 @@ impl SparseBitSet { } impl SparseBitSet { - fn last_set_in(&self, range: impl RangeBounds) -> Option { + pub fn last_set_in(&self, range: impl RangeBounds) -> Option { let mut last_leq = None; for e in self.iter() { if range.contains(e) { diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index d3cf267dc9d79..0c1180b3e9800 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -236,6 +236,12 @@ impl IntervalSet { I: Step, { assert_eq!(self.domain, other.domain); + if self.map.len() < other.map.len() { + let backup = self.clone(); + self.map.clone_from(&other.map); + return self.union(&backup); + } + let mut did_insert = false; for range in other.iter_intervals() { did_insert |= self.insert_range(range); diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 185e0c7d69890..854841206b89b 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,16 +2,9 @@ #![deny(rustc::diagnostic_outside_of_impl)] #![cfg_attr( feature = "nightly", - feature( - allow_internal_unstable, - extend_one, - min_specialization, - new_uninit, - step_trait, - stmt_expr_attributes, - test - ) + feature(extend_one, min_specialization, new_uninit, step_trait, test) )] +#![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(feature = "nightly", allow(internal_features))] pub mod bit_set; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 66c5cc774b224..d876174e620f4 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -12,10 +12,13 @@ use std::vec; use crate::{Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. +/// Its purpose is to avoid mixing indexes. /// /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// +/// This allows to index the IndexVec with the new index type. +/// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -25,11 +28,13 @@ pub struct IndexVec { } impl IndexVec { + /// Constructs a new, empty `IndexVec`. #[inline] pub const fn new() -> Self { IndexVec::from_raw(Vec::new()) } + /// Constructs a new `IndexVec` from a `Vec`. #[inline] pub const fn from_raw(raw: Vec) -> Self { IndexVec { raw, _marker: PhantomData } @@ -59,6 +64,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } + /// Creates a new IndexVec with n copies of the `elem`. #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where @@ -85,6 +91,7 @@ impl IndexVec { IndexSlice::from_raw_mut(&mut self.raw) } + /// Pushes an element to the array returning the index where it was pushed to. #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index ede8416125d6a..0b25628b9e195 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -104,7 +104,7 @@ impl Parse for Newtype { #gate_rustc_only impl ::rustc_serialize::Encodable for #name { fn encode(&self, e: &mut E) { - e.emit_u32(self.private); + e.emit_u32(self.as_u32()); } } } @@ -164,7 +164,7 @@ impl Parse for Newtype { #[inline] fn eq(l: &Option, r: &Option) -> bool { if #max_val < u32::MAX { - l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1) + l.map(|i| i.as_u32()).unwrap_or(#max_val+1) == r.map(|i| i.as_u32()).unwrap_or(#max_val+1) } else { match (l, r) { (Some(l), Some(r)) => r == l, @@ -188,7 +188,7 @@ impl Parse for Newtype { #[cfg_attr(#gate_rustc_only_cfg, rustc_layout_scalar_valid_range_end(#max))] #[cfg_attr(#gate_rustc_only_cfg, rustc_pass_by_value)] #vis struct #name { - private: u32, + private_use_as_methods_instead: u32, } #(#consts)* @@ -238,7 +238,7 @@ impl Parse for Newtype { /// Prefer using `from_u32`. #[inline] #vis const unsafe fn from_u32_unchecked(value: u32) -> Self { - Self { private: value } + Self { private_use_as_methods_instead: value } } /// Extracts the value of this index as a `usize`. @@ -250,7 +250,7 @@ impl Parse for Newtype { /// Extracts the value of this index as a `u32`. #[inline] #vis const fn as_u32(self) -> u32 { - self.private + self.private_use_as_methods_instead } /// Extracts the value of this index as a `usize`. diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index aee99063e0396..0a128218c9229 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,7 +1,7 @@ use hir::GenericParamKind; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, - IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, + DiagnosticStyledString, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, }; use rustc_hir as hir; use rustc_hir::FnRetTy; @@ -33,7 +33,7 @@ pub struct OpaqueHiddenTypeDiag { } #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0282")] +#[diag(infer_type_annotations_needed, code = E0282)] pub struct AnnotationRequired<'a> { #[primary_span] pub span: Span, @@ -51,7 +51,7 @@ pub struct AnnotationRequired<'a> { // Copy of `AnnotationRequired` for E0283 #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0283")] +#[diag(infer_type_annotations_needed, code = E0283)] pub struct AmbiguousImpl<'a> { #[primary_span] pub span: Span, @@ -69,7 +69,7 @@ pub struct AmbiguousImpl<'a> { // Copy of `AnnotationRequired` for E0284 #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0284")] +#[diag(infer_type_annotations_needed, code = E0284)] pub struct AmbiguousReturn<'a> { #[primary_span] pub span: Span, @@ -421,7 +421,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { } #[derive(Diagnostic)] -#[diag(infer_lifetime_mismatch, code = "E0623")] +#[diag(infer_lifetime_mismatch, code = E0623)] pub struct LifetimeMismatch<'a> { #[primary_span] pub span: Span, @@ -495,7 +495,7 @@ pub struct MismatchedStaticLifetime<'a> { #[derive(Diagnostic)] pub enum ExplicitLifetimeRequired<'a> { - #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")] + #[diag(infer_explicit_lifetime_required_with_ident, code = E0621)] WithIdent { #[primary_span] #[label] @@ -511,7 +511,7 @@ pub enum ExplicitLifetimeRequired<'a> { #[skip_arg] new_ty: Ty<'a>, }, - #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")] + #[diag(infer_explicit_lifetime_required_with_param_type, code = E0621)] WithParamType { #[primary_span] #[label] @@ -534,7 +534,7 @@ pub enum TyOrSig<'tcx> { } impl IntoDiagnosticArg for TyOrSig<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { match self { TyOrSig::Ty(ty) => ty.into_diagnostic_arg(), TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(), @@ -819,7 +819,7 @@ impl AddToDiagnostic for DynTraitConstraintSuggestion { } #[derive(Diagnostic)] -#[diag(infer_but_calling_introduces, code = "E0772")] +#[diag(infer_but_calling_introduces, code = E0772)] pub struct ButCallingIntroduces { #[label(infer_label1)] pub param_ty_span: Span, @@ -871,14 +871,14 @@ impl AddToDiagnostic for MoreTargeted { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - diag.code(rustc_errors::error_code!(E0772)); + diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); diag.arg("ident", self.ident); } } #[derive(Diagnostic)] -#[diag(infer_but_needs_to_satisfy, code = "E0759")] +#[diag(infer_but_needs_to_satisfy, code = E0759)] pub struct ButNeedsToSatisfy { #[primary_span] pub sp: Span, @@ -904,7 +904,7 @@ pub struct ButNeedsToSatisfy { } #[derive(Diagnostic)] -#[diag(infer_outlives_content, code = "E0312")] +#[diag(infer_outlives_content, code = E0312)] pub struct OutlivesContent<'a> { #[primary_span] pub span: Span, @@ -913,7 +913,7 @@ pub struct OutlivesContent<'a> { } #[derive(Diagnostic)] -#[diag(infer_outlives_bound, code = "E0476")] +#[diag(infer_outlives_bound, code = E0476)] pub struct OutlivesBound<'a> { #[primary_span] pub span: Span, @@ -922,7 +922,7 @@ pub struct OutlivesBound<'a> { } #[derive(Diagnostic)] -#[diag(infer_fulfill_req_lifetime, code = "E0477")] +#[diag(infer_fulfill_req_lifetime, code = E0477)] pub struct FulfillReqLifetime<'a> { #[primary_span] pub span: Span, @@ -932,7 +932,7 @@ pub struct FulfillReqLifetime<'a> { } #[derive(Diagnostic)] -#[diag(infer_lf_bound_not_satisfied, code = "E0478")] +#[diag(infer_lf_bound_not_satisfied, code = E0478)] pub struct LfBoundNotSatisfied<'a> { #[primary_span] pub span: Span, @@ -941,7 +941,7 @@ pub struct LfBoundNotSatisfied<'a> { } #[derive(Diagnostic)] -#[diag(infer_ref_longer_than_data, code = "E0491")] +#[diag(infer_ref_longer_than_data, code = E0491)] pub struct RefLongerThanData<'a> { #[primary_span] pub span: Span, @@ -1117,7 +1117,7 @@ pub enum PlaceholderRelationLfNotSatisfied { } #[derive(Diagnostic)] -#[diag(infer_opaque_captures_lifetime, code = "E0700")] +#[diag(infer_opaque_captures_lifetime, code = E0700)] pub struct OpaqueCapturesLifetime<'tcx> { #[primary_span] pub span: Span, @@ -1378,73 +1378,73 @@ pub enum TypeErrorAdditionalDiags { #[derive(Diagnostic)] pub enum ObligationCauseFailureCode { - #[diag(infer_oc_method_compat, code = "E0308")] + #[diag(infer_oc_method_compat, code = E0308)] MethodCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_type_compat, code = "E0308")] + #[diag(infer_oc_type_compat, code = E0308)] TypeCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_const_compat, code = "E0308")] + #[diag(infer_oc_const_compat, code = E0308)] ConstCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_try_compat, code = "E0308")] + #[diag(infer_oc_try_compat, code = E0308)] TryCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_match_compat, code = "E0308")] + #[diag(infer_oc_match_compat, code = E0308)] MatchCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_if_else_different, code = "E0308")] + #[diag(infer_oc_if_else_different, code = E0308)] IfElseDifferent { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_no_else, code = "E0317")] + #[diag(infer_oc_no_else, code = E0317)] NoElse { #[primary_span] span: Span, }, - #[diag(infer_oc_no_diverge, code = "E0308")] + #[diag(infer_oc_no_diverge, code = E0308)] NoDiverge { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_fn_main_correct_type, code = "E0580")] + #[diag(infer_oc_fn_main_correct_type, code = E0580)] FnMainCorrectType { #[primary_span] span: Span, }, - #[diag(infer_oc_fn_start_correct_type, code = "E0308")] + #[diag(infer_oc_fn_start_correct_type, code = E0308)] FnStartCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_fn_lang_correct_type, code = "E0308")] + #[diag(infer_oc_fn_lang_correct_type, code = E0308)] FnLangCorrectType { #[primary_span] span: Span, @@ -1452,33 +1452,33 @@ pub enum ObligationCauseFailureCode { subdiags: Vec, lang_item_name: Symbol, }, - #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] + #[diag(infer_oc_intrinsic_correct_type, code = E0308)] IntrinsicCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_method_correct_type, code = "E0308")] + #[diag(infer_oc_method_correct_type, code = E0308)] MethodCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_closure_selfref, code = "E0644")] + #[diag(infer_oc_closure_selfref, code = E0644)] ClosureSelfref { #[primary_span] span: Span, }, - #[diag(infer_oc_cant_coerce, code = "E0308")] + #[diag(infer_oc_cant_coerce, code = E0308)] CantCoerce { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec, }, - #[diag(infer_oc_generic, code = "E0308")] + #[diag(infer_oc_generic, code = E0308)] Generic { #[primary_span] span: Span, diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 8e45cc6d80e92..331e3633e908d 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -108,7 +108,7 @@ pub enum SuffixKind { } impl IntoDiagnosticArg for PrefixKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { let kind = match self { Self::Empty => "empty", Self::RefValidFor => "ref_valid_for", @@ -130,7 +130,7 @@ impl IntoDiagnosticArg for PrefixKind { } impl IntoDiagnosticArg for SuffixKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { let kind = match self { Self::Empty => "empty", Self::Continues => "continues", diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index e60e3ffeaa72c..0f1af81d9f04c 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -90,6 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { universe: self.universe.clone(), intercrate, next_trait_solver: self.next_trait_solver, + obligation_inspector: self.obligation_inspector.clone(), } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e4b37f05b778f..156a4f7101763 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -414,6 +414,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bool @@ -480,7 +481,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } ty::ConstKind::Infer(InferConst::EffectVar(vid)) => { match self.infcx.unwrap().probe_effect_var(vid) { - Some(value) => return self.fold_const(value.as_const(self.tcx)), + Some(value) => return self.fold_const(value), None => { return self.canonicalize_const_var( CanonicalVarInfo { kind: CanonicalVarKind::Effect }, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 386fdb09ba5d5..1f68a5a9c6179 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,6 +24,7 @@ use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; use rustc_index::IndexVec; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, List, Ty, TyCtxt}; @@ -152,7 +153,12 @@ impl<'tcx> InferCtxt<'tcx> { ) .into(), CanonicalVarKind::Effect => { - let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; + let vid = self + .inner + .borrow_mut() + .effect_unification_table() + .new_key(EffectVarValue::Unknown) + .vid; ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) .into() } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 875e94fcd9f16..59bed38ec2af1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -60,7 +60,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - error_code, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, + codes::*, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, }; use rustc_hir as hir; @@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -117,9 +118,9 @@ fn escape_literal(s: &str) -> String { /// field is only populated during an in-progress typeck. /// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`. /// -/// You must only create this if you intend to actually emit an error. -/// This provides a lot of utility methods which should not be used -/// during the happy path. +/// You must only create this if you intend to actually emit an error (or +/// perhaps a warning, though preferably not.) It provides a lot of utility +/// methods which should not be used during the happy path. pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub typeck_results: Option>>, @@ -133,9 +134,10 @@ pub struct TypeErrCtxt<'a, 'tcx> { impl Drop for TypeErrCtxt<'_, '_> { fn drop(&mut self) { - if let Some(_) = self.dcx().has_errors_or_span_delayed_bugs() { - // ok, emitted an error. + if self.dcx().has_errors().is_some() { + // Ok, emitted an error. } else { + // Didn't emit an error; maybe it was created but not yet emitted. self.infcx .tcx .sess @@ -517,6 +519,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } + + RegionResolutionError::CannotNormalize(clause, origin) => { + let clause: ty::Clause<'tcx> = + clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx); + self.tcx + .dcx() + .struct_span_err(origin.span(), format!("cannot normalize `{clause}`")) + .emit(); + } } } } @@ -558,7 +569,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionResolutionError::GenericBoundFailure(..) => true, RegionResolutionError::ConcreteFailure(..) | RegionResolutionError::SubSupConflict(..) - | RegionResolutionError::UpperBoundUniverseConflict(..) => false, + | RegionResolutionError::UpperBoundUniverseConflict(..) + | RegionResolutionError::CannotNormalize(..) => false, }; let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { @@ -573,6 +585,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), + RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(), }); errors } @@ -2361,9 +2374,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .dcx() .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); err.code(match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), - ty::ReStatic => error_code!(E0310), - _ => error_code!(E0311), + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309, + ty::ReStatic => E0310, + _ => E0311, }); '_explain: { @@ -2545,7 +2558,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { add_lt_suggs, new_lt: &new_lt, }; - match self.tcx.hir().expect_owner(lifetime_scope) { + match self.tcx.expect_hir_owner_node(lifetime_scope) { hir::OwnerNode::Item(i) => visitor.visit_item(i), hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i), hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i), @@ -2829,7 +2842,11 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => Error0644, + TypeError::CyclicTy(ty) + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => + { + Error0644 + } TypeError::IntrinsicCast => Error0308, _ => Error0308, }, @@ -2876,7 +2893,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => { + TypeError::CyclicTy(ty) + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => + { ObligationCauseFailureCode::ClosureSelfref { span } } TypeError::IntrinsicCast => { @@ -2913,7 +2932,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { use crate::traits::ObligationCauseCode::*; let kind = match self.0.code() { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 03c8e08aa01ac..c637ab31cd214 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -5,7 +5,7 @@ use crate::errors::{ use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{DiagnosticBuilder, IntoDiagnosticArg}; +use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -43,12 +43,12 @@ pub enum TypeAnnotationNeeded { E0284, } -impl Into for TypeAnnotationNeeded { - fn into(self) -> String { +impl Into for TypeAnnotationNeeded { + fn into(self) -> ErrCode { match self { - Self::E0282 => rustc_errors::error_code!(E0282), - Self::E0283 => rustc_errors::error_code!(E0283), - Self::E0284 => rustc_errors::error_code!(E0284), + Self::E0282 => E0282, + Self::E0283 => E0283, + Self::E0284 => E0284, } } } @@ -134,7 +134,7 @@ impl InferenceDiagnosticsParentData { } impl IntoDiagnosticArg for UnderspecifiedArgKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { let kind = match self { Self::Type { .. } => "type", Self::Const { is_parameter: true } => "const_with_param", @@ -883,7 +883,10 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { GenericArgKind::Type(ty) => { if matches!( ty.kind(), - ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Coroutine(..) + ty::Alias(ty::Opaque, ..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) ) { // Opaque types can't be named by the user right now. // diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index e1a83c86318e9..b3b83c8ab957f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -30,7 +30,7 @@ impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T> where T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>, { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { rustc_errors::DiagnosticArgValue::Str(self.to_string().into()) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index a7d1c2ca66695..c8fd4e3a69286 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let hir::OwnerNode::Item(Item { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. - }) = tcx.hir().owner(impl_did) + }) = tcx.hir_owner_node(impl_did) { Some((impl_item.ident, self_ty)) } else { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index afb3c5c1e5656..f884ca83073df 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -195,7 +195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } diag.help("type parameters must be constrained to match other types"); - if tcx.sess.teach(&diag.get_code().unwrap()) { + if tcx.sess.teach(diag.code.unwrap()) { diag.help( "given a type parameter `T` and a method `foo`: ``` @@ -228,7 +228,10 @@ impl Trait for X { #traits-as-parameters", ); } - (ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => { + ( + ty::Param(p), + ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..), + ) => { let generics = tcx.generics_of(body_owner_def_id); if let Some(param) = generics.opt_type_param(p, tcx) { let p_span = tcx.def_span(param.def_id); @@ -294,8 +297,78 @@ impl Trait for X { ); } } - (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) - if alias.def_id.is_local() + (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias)) + if let Some(def_id) = t.principal_def_id() + && tcx.explicit_item_bounds(alias.def_id).skip_binder().iter().any( + |(pred, _span)| match pred.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) + if trait_predicate.polarity + == ty::ImplPolarity::Positive => + { + trait_predicate.def_id() == def_id + } + _ => false, + }, + ) => + { + diag.help(format!( + "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \ + change the expected type as well", + values.found, values.expected, + )); + } + (ty::Dynamic(t, _, ty::DynKind::Dyn), _) + if let Some(def_id) = t.principal_def_id() => + { + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, values.found, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.help(format!( + "`{}` implements `{trait_name}` so you could box the found value \ + and coerce it to the trait object `Box`, you \ + will have to change the expected type as well", + values.found, + )); + } + } + (_, ty::Dynamic(t, _, ty::DynKind::Dyn)) + if let Some(def_id) = t.principal_def_id() => + { + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, values.expected, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.help(format!( + "`{}` implements `{trait_name}` so you could change the expected \ + type to `Box`", + values.expected, + )); + } + } + (ty::Dynamic(t, _, ty::DynKind::DynStar), _) + if let Some(def_id) = t.principal_def_id() => + { + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, values.found, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.help(format!( + "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \ + not enabled; that feature it is currently incomplete", + values.found, + )); + } + } + (_, ty::Alias(ty::Opaque, opaque_ty)) + | (ty::Alias(ty::Opaque, opaque_ty), _) => { + if opaque_ty.def_id.is_local() && matches!( tcx.def_kind(body_owner_def_id), DefKind::Fn @@ -303,21 +376,74 @@ impl Trait for X { | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst - ) => - { - if tcx.is_type_alias_impl_trait(alias.def_id) { - if !tcx + ) + && tcx.is_type_alias_impl_trait(opaque_ty.def_id) + && !tcx .opaque_types_defined_by(body_owner_def_id.expect_local()) - .contains(&alias.def_id.expect_local()) - { - 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", + .contains(&opaque_ty.def_id.expect_local()) + { + 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", + ); + } + // If two if arms can be coerced to a trait object, provide a structured + // suggestion. + let ObligationCauseCode::IfExpression(cause) = cause.code() else { + return; + }; + let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) else { + return; + }; + let Some(then) = blk.expr else { + return; + }; + let hir::Node::Block(blk) = self.tcx.hir_node(cause.else_id) else { + return; + }; + let Some(else_) = blk.expr else { + return; + }; + let expected = match values.found.kind() { + ty::Alias(..) => values.expected, + _ => values.found, + }; + let preds = tcx.explicit_item_bounds(opaque_ty.def_id); + for (pred, _span) in preds.skip_binder() { + let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder() + else { + continue; + }; + if trait_predicate.polarity != ty::ImplPolarity::Positive { + continue; + } + let def_id = trait_predicate.def_id(); + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, expected, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.multipart_suggestion( + format!( + "`{expected}` implements `{trait_name}` so you can box \ + both arms and coerce to the trait object \ + `Box`", + ), + vec![ + (then.span.shrink_to_lo(), "Box::new(".to_string()), + ( + then.span.shrink_to_hi(), + format!(") as Box", tcx.def_path_str(def_id)), + ), + (else_.span.shrink_to_lo(), "Box::new(".to_string()), + (else_.span.shrink_to_hi(), ")".to_string()), + ], + MachineApplicable, ); } } @@ -330,6 +456,38 @@ impl Trait for X { ); } } + (ty::Adt(_, _), ty::Adt(def, args)) + if let ObligationCauseCode::IfExpression(cause) = cause.code() + && let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) + && let Some(then) = blk.expr + && def.is_box() + && let boxed_ty = args.type_at(0) + && let ty::Dynamic(t, _, _) = boxed_ty.kind() + && let Some(def_id) = t.principal_def_id() + && let mut impl_def_ids = vec![] + && let _ = + tcx.for_each_relevant_impl(def_id, values.expected, |did| { + impl_def_ids.push(did) + }) + && let [_] = &impl_def_ids[..] => + { + // We have divergent if/else arms where the expected value is a type that + // implements the trait of the found boxed trait object. + diag.multipart_suggestion( + format!( + "`{}` implements `{}` so you can box it to coerce to the trait \ + object `{}`", + values.expected, + tcx.item_name(def_id), + values.found, + ), + vec![ + (then.span.shrink_to_lo(), "Box::new(".to_string()), + (then.span.shrink_to_hi(), ")".to_string()), + ], + MachineApplicable, + ); + } _ => {} } debug!( @@ -342,7 +500,7 @@ impl Trait for X { } CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. - if ty.is_closure() || ty.is_coroutine() { + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() { diag.note( "closures cannot capture themselves or take themselves as argument;\n\ this error may be the result of a recent compiler bug-fix,\n\ @@ -523,7 +681,7 @@ impl Trait for X { https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); } - if tcx.sess.teach(&diag.get_code().unwrap()) { + if tcx.sess.teach(diag.code.unwrap()) { diag.help( "given an associated type `T` and a method `foo`: ``` diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index d256994d8d1fd..2d5fa1b5c7001 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -151,13 +151,8 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty()) } ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { - let opt_ct = self - .infcx - .inner - .borrow_mut() - .effect_unification_table() - .probe_value(v) - .map(|effect| effect.as_const(self.infcx.tcx)); + let opt_ct = + self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known(); self.freshen_const( opt_ct, ty::InferConst::EffectVar(v), 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 0562c6ccfcf75..6137506d4a994 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -98,6 +98,8 @@ pub enum RegionResolutionError<'tcx> { SubregionOrigin<'tcx>, // cause of the constraint Region<'tcx>, // the placeholder `'b` ), + + CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>), } impl<'tcx> RegionResolutionError<'tcx> { @@ -106,7 +108,8 @@ impl<'tcx> RegionResolutionError<'tcx> { RegionResolutionError::ConcreteFailure(origin, _, _) | RegionResolutionError::GenericBoundFailure(origin, _, _) | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _) - | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin, + | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) + | RegionResolutionError::CannotNormalize(_, origin) => origin, } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 002aad19c4981..2d8b47a9cc057 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -8,12 +8,15 @@ pub use self::ValuePairs::*; pub use relate::combine::ObligationEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::undo_log::UndoLogs; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use self::opaque_types::OpaqueTypeStorage; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; -use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt}; +use crate::traits::{ + self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, TraitEngineExt, +}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -23,8 +26,8 @@ use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; -use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::{select, DefiningAnchor}; @@ -276,7 +279,8 @@ pub struct InferCtxt<'tcx> { /// The set of predicates on which errors have been reported, to /// avoid reporting the same error twice. - pub reported_trait_errors: RefCell>>>, + pub reported_trait_errors: + RefCell>, ErrorGuaranteed)>>, pub reported_signature_mismatch: RefCell)>>, @@ -334,6 +338,8 @@ pub struct InferCtxt<'tcx> { pub intercrate: bool, next_trait_solver: bool, + + pub obligation_inspector: Cell>>, } impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { @@ -708,6 +714,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, next_trait_solver, + obligation_inspector: Cell::new(None), } } } @@ -812,7 +819,7 @@ impl<'tcx> InferCtxt<'tcx> { (0..table.len()) .map(|i| ty::EffectVid::from_usize(i)) - .filter(|&vid| table.probe_value(vid).is_none()) + .filter(|&vid| table.probe_value(vid).is_unknown()) .map(|v| { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) }) @@ -1230,7 +1237,8 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; + let effect_vid = + self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid; let ty = self .tcx .type_of(param.def_id) @@ -1410,8 +1418,8 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn probe_effect_var(&self, vid: EffectVid) -> Option> { - self.inner.borrow_mut().effect_unification_table().probe_value(vid) + pub fn probe_effect_var(&self, vid: EffectVid) -> Option> { + self.inner.borrow_mut().effect_unification_table().probe_value(vid).known() } /// Attempts to resolve all type/region/const variables in @@ -1532,9 +1540,13 @@ impl<'tcx> InferCtxt<'tcx> { /// Obtains the latest type of the given closure; this may be a /// closure in the current function, in which case its /// `ClosureKind` may not yet be known. - pub fn closure_kind(&self, closure_args: GenericArgsRef<'tcx>) -> Option { - let closure_kind_ty = closure_args.as_closure().kind_ty(); - let closure_kind_ty = self.shallow_resolve(closure_kind_ty); + pub fn closure_kind(&self, closure_ty: Ty<'tcx>) -> Option { + let unresolved_kind_ty = match *closure_ty.kind() { + ty::Closure(_, args) => args.as_closure().kind_ty(), + ty::CoroutineClosure(_, args) => args.as_coroutine_closure().kind_ty(), + _ => bug!("unexpected type {closure_ty}"), + }; + let closure_kind_ty = self.shallow_resolve(unresolved_kind_ty); closure_kind_ty.to_opt_closure_kind() } @@ -1718,6 +1730,15 @@ impl<'tcx> InferCtxt<'tcx> { } } } + + /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver. + pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) { + debug_assert!( + self.obligation_inspector.get().is_none(), + "shouldn't override a set obligation inspector" + ); + self.obligation_inspector.set(Some(inspector)); + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { @@ -1878,7 +1899,8 @@ impl<'a, 'tcx> TypeFolder> for ShallowResolver<'a, 'tcx> { .borrow_mut() .effect_unification_table() .probe_value(vid) - .map_or(ct, |val| val.as_const(self.infcx.tcx)), + .known() + .unwrap_or(ct), _ => ct, } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index db46b39ce25fc..5ee0a606a5f57 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -456,6 +456,17 @@ where args.as_closure().sig_as_fn_ptr_ty().visit_with(self); } + ty::CoroutineClosure(_, args) => { + // Skip lifetime parameters of the enclosing item(s) + + for upvar in args.as_coroutine_closure().upvar_tys() { + upvar.visit_with(self); + } + + // FIXME(async_closures): Is this the right signature to visit here? + args.as_coroutine_closure().signature_parts_ty().visit_with(self); + } + ty::Coroutine(_, args) => { // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index fc3d8375873b0..7dd1ec3254220 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -103,6 +103,11 @@ fn compute_components<'tcx>( compute_components(tcx, tupled_ty, out, visited); } + ty::CoroutineClosure(_, args) => { + let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); + } + ty::Coroutine(_, args) => { // Same as the closure case let tupled_ty = args.as_coroutine().tupled_upvars_ty(); diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 6379f84aa252f..a4f9316b5020f 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,10 +1,10 @@ //! Various code related to computing outlives relations. use self::env::OutlivesEnvironment; use super::region_constraints::RegionConstraintData; -use super::{InferCtxt, RegionResolutionError}; +use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; -use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::ty; pub mod components; @@ -41,12 +41,25 @@ impl<'tcx> InferCtxt<'tcx> { /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use /// `resolve_vars_if_possible` as well as `fully_resolve`. + /// + /// If you are in a crate that has access to `rustc_trait_selection`, + /// then it's probably better to use `resolve_regions`, + /// which knows how to normalize registered region obligations. #[must_use] - pub fn resolve_regions( + pub fn resolve_regions_with_normalize( &self, outlives_env: &OutlivesEnvironment<'tcx>, + deeply_normalize_ty: impl Fn( + ty::PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) -> Result, NoSolution>, ) -> Vec> { - self.process_registered_region_obligations(outlives_env); + match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { + Ok(()) => {} + Err((clause, origin)) => { + return vec![RegionResolutionError::CannotNormalize(clause, origin)]; + } + }; let (var_infos, data) = { let mut inner = self.inner.borrow_mut(); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index d7a3bfcbc41b6..7208f17fb340f 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,8 +68,10 @@ use crate::infer::{ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::GenericArgKind; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; +use rustc_span::DUMMY_SP; use smallvec::smallvec; use super::env::OutlivesEnvironment; @@ -123,26 +125,73 @@ impl<'tcx> InferCtxt<'tcx> { /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// right before lexical region resolution. - #[instrument(level = "debug", skip(self, outlives_env))] - pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) { + #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] + pub fn process_registered_region_obligations( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + mut deeply_normalize_ty: impl FnMut( + PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) + -> Result, NoSolution>, + ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> { assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); - let my_region_obligations = self.take_registered_region_obligations(); + let normalized_caller_bounds: Vec<_> = outlives_env + .param_env + .caller_bounds() + .iter() + .filter_map(|clause| { + let outlives = clause.as_type_outlives_clause()?; + Some( + deeply_normalize_ty( + outlives, + SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP), + ) + // FIXME(-Znext-solver): How do we accurately report an error span here :( + .map_err(|NoSolution| { + (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)) + }), + ) + }) + .try_collect()?; - for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - debug!(?sup_type, ?sub_region, ?origin); - let sup_type = self.resolve_vars_if_possible(sup_type); + // Must loop since the process of normalizing may itself register region obligations. + for iteration in 0.. { + let my_region_obligations = self.take_registered_region_obligations(); + if my_region_obligations.is_empty() { + break; + } - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - outlives_env.region_bound_pairs(), - None, - outlives_env.param_env, - ); - let category = origin.to_constraint_category(); - outlives.type_must_outlive(origin, sup_type, sub_region, category); + if !self.tcx.recursion_limit().value_within_limit(iteration) { + bug!( + "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}" + ); + } + + for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { + let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); + let ty::OutlivesPredicate(sup_type, sub_region) = + deeply_normalize_ty(outlives, origin.clone()) + .map_err(|NoSolution| (outlives, origin.clone()))? + .no_bound_vars() + .expect("started with no bound vars, should end with no bound vars"); + + debug!(?sup_type, ?sub_region, ?origin); + + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + outlives_env.region_bound_pairs(), + None, + &normalized_caller_bounds, + ); + let category = origin.to_constraint_category(); + outlives.type_must_outlive(origin, sup_type, sub_region, category); + } } + + Ok(()) } } @@ -190,7 +239,7 @@ where tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], ) -> Self { Self { delegate, @@ -199,7 +248,7 @@ where tcx, region_bound_pairs, implicit_region_bound, - param_env, + caller_bounds, ), } } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 7a85268492b43..5d2f51c689b95 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -23,7 +23,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> { /// Outside of borrowck the only way to prove `T: '?0` is by /// setting `'?0` to `'empty`. implicit_region_bound: Option>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], } impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { @@ -31,9 +31,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], ) -> Self { - Self { tcx, region_bound_pairs, implicit_region_bound, param_env } + Self { tcx, region_bound_pairs, implicit_region_bound, caller_bounds } } #[instrument(level = "debug", skip(self))] @@ -219,8 +219,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // To start, collect bounds from user environment. Note that // parameter environments are already elaborated, so we don't // have to worry about that. - let c_b = self.param_env.caller_bounds(); - let param_bounds = self.collect_outlives_from_clause_list(erased_ty, c_b.into_iter()); + let param_bounds = self.caller_bounds.iter().copied().filter(move |outlives_predicate| { + super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) + }); // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list @@ -307,22 +308,4 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) } - - /// Searches through a predicate list for a predicate `T: 'a`. - /// - /// Careful: does not elaborate predicates, and just uses `==` - /// when comparing `ty` for equality, so `ty` must be something - /// that does not involve inference variables and where you - /// otherwise want a precise match. - fn collect_outlives_from_clause_list( - &self, - erased_ty: Ty<'tcx>, - clauses: impl Iterator>, - ) -> impl Iterator, ty::Region<'tcx>>>> - { - let tcx = self.tcx; - clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| { - super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) - }) - } } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 9e1dab12b4d43..13c17ee1cd2b8 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -165,9 +165,9 @@ impl<'tcx> InferCtxt<'tcx> { // // This probe is probably not strictly necessary but it seems better to be safe and not accidentally find // ourselves with a check to find bugs being required for code to compile because it made inference progress. - let compatible_types = self.probe(|_| { + self.probe(|_| { if a.ty() == b.ty() { - return Ok(()); + return; } // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the @@ -177,32 +177,18 @@ impl<'tcx> InferCtxt<'tcx> { relation.param_env().and((a.ty(), b.ty())), &mut OriginalQueryValues::default(), ); - self.tcx.check_tys_might_be_eq(canonical).map_err(|_| { + self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| { + // The error will only be reported later. If we emit an ErrorGuaranteed + // here, then we will never get to the code that actually emits the error. self.tcx.dcx().delayed_bug(format!( "cannot relate consts of different types (a={a:?}, b={b:?})", - )) - }) + )); + // We treat these constants as if they were of the same type, so that any + // such constants being used in impls make these impls match barring other mismatches. + // This helps with diagnostics down the road. + }); }); - // If the consts have differing types, just bail with a const error with - // the expected const's type. Specifically, we don't want const infer vars - // to do any type shapeshifting before and after resolution. - if let Err(guar) = compatible_types { - // HACK: equating both sides with `[const error]` eagerly prevents us - // from leaving unconstrained inference vars during things like impl - // matching in the solver. - let a_error = ty::Const::new_error(self.tcx, guar, a.ty()); - if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { - return self.unify_const_variable(vid, a_error, relation.param_env()); - } - let b_error = ty::Const::new_error(self.tcx, guar, b.ty()); - if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { - return self.unify_const_variable(vid, b_error, relation.param_env()); - } - - return Ok(if relation.a_is_expected() { a_error } else { b_error }); - } - match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)), @@ -216,11 +202,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::ConstKind::Infer(InferConst::EffectVar(a_vid)), ty::ConstKind::Infer(InferConst::EffectVar(b_vid)), ) => { - self.inner - .borrow_mut() - .effect_unification_table() - .unify_var_var(a_vid, b_vid) - .map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?; + self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); return Ok(a); } @@ -247,19 +229,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { - return self.unify_effect_variable( - relation.a_is_expected(), - vid, - EffectVarValue::Const(b), - ); + return Ok(self.unify_effect_variable(vid, b)); } (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => { - return self.unify_effect_variable( - !relation.a_is_expected(), - vid, - EffectVarValue::Const(a), - ); + return Ok(self.unify_effect_variable(vid, a)); } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) @@ -380,18 +354,12 @@ impl<'tcx> InferCtxt<'tcx> { Ok(Ty::new_float(self.tcx, val)) } - fn unify_effect_variable( - &self, - vid_is_expected: bool, - vid: ty::EffectVid, - val: EffectVarValue<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { + fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> { self.inner .borrow_mut() .effect_unification_table() - .unify_var_value(vid, Some(val)) - .map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?; - Ok(val.as_const(self.tcx)) + .union_value(vid, EffectVarValue::Known(val)); + val } } @@ -593,11 +561,3 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } - -fn effect_unification_error<'tcx>( - _tcx: TyCtxt<'tcx>, - _a_is_expected: bool, - (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>), -) -> TypeError<'tcx> { - bug!("unexpected effect unification error") -} diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 959b09031277c..d5999331dfab6 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -237,14 +237,13 @@ impl<'tcx> TypeFolder> for EagerResolver<'_, 'tcx> { } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool); - match self.infcx.probe_effect_var(vid) { - Some(c) => c.as_const(self.infcx.tcx), - None => ty::Const::new_infer( + self.infcx.probe_effect_var(vid).unwrap_or_else(|| { + ty::Const::new_infer( self.infcx.tcx, ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)), self.infcx.tcx.types.bool, - ), - } + ) + }) } _ => { if c.has_infer() { diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 221b78048cbc3..e2dd4b49e1a4b 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -18,12 +18,11 @@ #![allow(internal_features)] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(extend_one)] #![feature(let_chains)] #![feature(if_let_guard)] +#![feature(iterator_try_collect)] #![feature(min_specialization)] -#![feature(never_type)] #![feature(try_blocks)] #![recursion_limit = "512"] // For rustdoc diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 6f218019dee5a..eabc1b953af1c 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,7 +2,7 @@ use super::ObjectSafetyViolation; use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Map; diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index fdae093aac8b4..72ec07375ac0e 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -13,12 +13,15 @@ use std::hash::{Hash, Hasher}; use hir::def_id::LocalDefId; use rustc_hir as hir; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; pub use self::ImplSource::*; pub use self::SelectionError::*; +use crate::infer::InferCtxt; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; @@ -116,6 +119,11 @@ pub type PredicateObligations<'tcx> = Vec>; pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; +/// A callback that can be provided to `inspect_typeck`. Invoked on evaluation +/// of root obligations. +pub type ObligationInspector<'tcx> = + fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result); + pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 319e81758094d..a238eacda44ba 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -libloading = "0.7.1" +libloading = "0.8.0" rustc-rayon = { version = "0.5.0", optional = true } rustc-rayon-core = { version = "0.5.0", optional = true } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5ca8809099675..8a4705e0056e1 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -45,20 +45,19 @@ pub struct Compiler { pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { - let sess = ParseSess::with_silent_emitter(Some(format!( + let sess = ParseSess::with_silent_emitter(format!( "this error occurred on the command line: `--cfg={s}`" - ))); + )); let filename = FileName::cfg_spec_source_code(&s); macro_rules! error { ($reason: expr) => { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - dcx.struct_fatal(format!( + dcx.fatal(format!( concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s - )) - .emit(); + )); }; } @@ -108,20 +107,19 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() }; for s in specs { - let sess = ParseSess::with_silent_emitter(Some(format!( + let sess = ParseSess::with_silent_emitter(format!( "this error occurred on the command line: `--check-cfg={s}`" - ))); + )); let filename = FileName::cfg_spec_source_code(&s); macro_rules! error { ($reason:expr) => { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - dcx.struct_fatal(format!( + dcx.fatal(format!( concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s )) - .emit() }; } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index cfa46447845a2..69414a1379515 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,11 +1,9 @@ -#![feature(box_patterns)] #![feature(decl_macro)] -#![feature(internal_output_capture)] -#![feature(thread_spawn_unchecked)] +#![feature(error_iter)] #![feature(lazy_cell)] #![feature(let_chains)] +#![feature(thread_spawn_unchecked)] #![feature(try_blocks)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 555c822ad6d68..2d4963a8b901a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -98,6 +98,7 @@ fn assert_same_hash(x: &Options, y: &Options) { assert_same_clone(y); } +#[track_caller] fn assert_different_hash(x: &Options, y: &Options) { assert_ne!(x.dep_tracking_hash(true), y.dep_tracking_hash(true)); assert_ne!(x.dep_tracking_hash(false), y.dep_tracking_hash(false)); @@ -713,7 +714,6 @@ fn test_unstable_options_tracking_hash() { untracked!(unpretty, Some("expanded".to_string())); untracked!(unstable_options, true); untracked!(validate_mir, true); - untracked!(verbose_internals, true); untracked!(write_long_types_to_disk, false); // tidy-alphabetical-end @@ -845,6 +845,7 @@ fn test_unstable_options_tracking_hash() { }; } tracked_no_crate_hash!(no_codegen, true); + tracked_no_crate_hash!(verbose_internals, true); } #[test] diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 9fd44e46b316e..76b9e8de75fb0 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -162,15 +162,21 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( } fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn { + fn format_err(e: &(dyn std::error::Error + 'static)) -> String { + e.sources().map(|e| format!(": {e}")).collect() + } let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { - let err = format!("couldn't load codegen backend {path:?}: {err}"); + let err = format!("couldn't load codegen backend {path:?}{}", format_err(&err)); early_dcx.early_fatal(err); }); let backend_sym = unsafe { lib.get::(b"__rustc_codegen_backend") } .unwrap_or_else(|e| { - let err = format!("couldn't load codegen backend: {e}"); - early_dcx.early_fatal(err); + let e = format!( + "`__rustc_codegen_backend` symbol lookup in the codegen backend failed{}", + format_err(&e) + ); + early_dcx.early_fatal(e); }); // Intentionally leak the dynamic library. We can't ever unload it diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 43dfd34a6ff74..f6c9289b529c7 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -20,8 +20,9 @@ //! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -// We want to be able to build this crate with a stable compiler, so no -// `#![feature]` attributes should be added. +// We want to be able to build this crate with a stable compiler, +// so no `#![feature]` attributes should be added. +#![deny(unstable_features)] mod cursor; pub mod unescape; diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 0a632c4d12ad5..03d178eb266a4 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -80,12 +80,12 @@ impl EscapeError { } } -/// Takes a contents of a literal (without quotes) and produces a sequence of -/// escaped characters or errors. +/// Takes the contents of a unicode-only (non-mixed-utf8) literal (without +/// quotes) and produces a sequence of escaped characters or errors. /// /// Values are returned by invoking `callback`. For `Char` and `Byte` modes, /// the callback will be called exactly once. -pub fn unescape_literal(src: &str, mode: Mode, callback: &mut F) +pub fn unescape_unicode(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range, Result), { @@ -97,50 +97,63 @@ where } Str | ByteStr => unescape_non_raw_common(src, mode, callback), RawStr | RawByteStr => check_raw_common(src, mode, callback), - CStr | RawCStr => unreachable!(), + RawCStr => check_raw_common(src, mode, &mut |r, mut result| { + if let Ok('\0') = result { + result = Err(EscapeError::NulInCStr); + } + callback(r, result) + }), + CStr => unreachable!(), } } -/// A unit within CStr. Must not be a nul character. -pub enum CStrUnit { - Byte(u8), +/// Used for mixed utf8 string literals, i.e. those that allow both unicode +/// chars and high bytes. +pub enum MixedUnit { + /// Used for ASCII chars (written directly or via `\x00`..`\x7f` escapes) + /// and Unicode chars (written directly or via `\u` escapes). + /// + /// For example, if '¥' appears in a string it is represented here as + /// `MixedUnit::Char('¥')`, and it will be appended to the relevant byte + /// string as the two-byte UTF-8 sequence `[0xc2, 0xa5]` Char(char), + + /// Used for high bytes (`\x80`..`\xff`). + /// + /// For example, if `\xa5` appears in a string it is represented here as + /// `MixedUnit::HighByte(0xa5)`, and it will be appended to the relevant + /// byte string as the single byte `0xa5`. + HighByte(u8), } -impl From for CStrUnit { - fn from(value: u8) -> Self { - CStrUnit::Byte(value) +impl From for MixedUnit { + fn from(c: char) -> Self { + MixedUnit::Char(c) } } -impl From for CStrUnit { - fn from(value: char) -> Self { - CStrUnit::Char(value) +impl From for MixedUnit { + fn from(n: u8) -> Self { + if n.is_ascii() { MixedUnit::Char(n as char) } else { MixedUnit::HighByte(n) } } } -pub fn unescape_c_string(src: &str, mode: Mode, callback: &mut F) +/// Takes the contents of a mixed-utf8 literal (without quotes) and produces +/// a sequence of escaped characters or errors. +/// +/// Values are returned by invoking `callback`. +pub fn unescape_mixed(src: &str, mode: Mode, callback: &mut F) where - F: FnMut(Range, Result), + F: FnMut(Range, Result), { match mode { - CStr => { - unescape_non_raw_common(src, mode, &mut |r, mut result| { - if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result { - result = Err(EscapeError::NulInCStr); - } - callback(r, result) - }); - } - RawCStr => { - check_raw_common(src, mode, &mut |r, mut result| { - if let Ok('\0') = result { - result = Err(EscapeError::NulInCStr); - } - callback(r, result.map(CStrUnit::Char)) - }); - } - Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(), + CStr => unescape_non_raw_common(src, mode, &mut |r, mut result| { + if let Ok(MixedUnit::Char('\0')) = result { + result = Err(EscapeError::NulInCStr); + } + callback(r, result) + }), + Char | Byte | Str | RawStr | ByteStr | RawByteStr | RawCStr => unreachable!(), } } @@ -181,29 +194,29 @@ impl Mode { } } - /// Non-byte literals should have `\xXX` escapes that are within the ASCII range. - fn ascii_escapes_should_be_ascii(self) -> bool { + /// Are `\x80`..`\xff` allowed? + fn allow_high_bytes(self) -> bool { match self { - Char | Str => true, - Byte | ByteStr | CStr => false, + Char | Str => false, + Byte | ByteStr | CStr => true, RawStr | RawByteStr | RawCStr => unreachable!(), } } - /// Whether characters within the literal must be within the ASCII range. + /// Are unicode (non-ASCII) chars allowed? #[inline] - fn chars_should_be_ascii(self) -> bool { + fn allow_unicode_chars(self) -> bool { match self { - Byte | ByteStr | RawByteStr => true, - Char | Str | RawStr | CStr | RawCStr => false, + Byte | ByteStr | RawByteStr => false, + Char | Str | RawStr | CStr | RawCStr => true, } } - /// Byte literals do not allow unicode escape. - fn is_unicode_escape_disallowed(self) -> bool { + /// Are unicode escapes (`\u`) allowed? + fn allow_unicode_escapes(self) -> bool { match self { - Byte | ByteStr => true, - Char | Str | CStr => false, + Byte | ByteStr => false, + Char | Str | CStr => true, RawByteStr | RawStr | RawCStr => unreachable!(), } } @@ -217,20 +230,19 @@ impl Mode { } } -fn scan_escape + From>( +fn scan_escape + From>( chars: &mut Chars<'_>, mode: Mode, ) -> Result { // Previous character was '\\', unescape what follows. - let res = match chars.next().ok_or(EscapeError::LoneSlash)? { - '"' => b'"', - 'n' => b'\n', - 'r' => b'\r', - 't' => b'\t', - '\\' => b'\\', - '\'' => b'\'', - '0' => b'\0', - + let res: char = match chars.next().ok_or(EscapeError::LoneSlash)? { + '"' => '"', + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + '\\' => '\\', + '\'' => '\'', + '0' => '\0', 'x' => { // Parse hexadecimal character code. @@ -240,25 +252,23 @@ fn scan_escape + From>( let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?; let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?; - let value = hi * 16 + lo; - - if mode.ascii_escapes_should_be_ascii() && !is_ascii(value) { - return Err(EscapeError::OutOfRangeHexEscape); - } + let value = (hi * 16 + lo) as u8; - value as u8 + return if !mode.allow_high_bytes() && !value.is_ascii() { + Err(EscapeError::OutOfRangeHexEscape) + } else { + // This may be a high byte, but that will only happen if `T` is + // `MixedUnit`, because of the `allow_high_bytes` check above. + Ok(T::from(value as u8)) + }; } - - 'u' => return scan_unicode(chars, mode.is_unicode_escape_disallowed()).map(Into::into), + 'u' => return scan_unicode(chars, mode.allow_unicode_escapes()).map(T::from), _ => return Err(EscapeError::InvalidEscape), }; - Ok(res.into()) + Ok(T::from(res)) } -fn scan_unicode( - chars: &mut Chars<'_>, - is_unicode_escape_disallowed: bool, -) -> Result { +fn scan_unicode(chars: &mut Chars<'_>, allow_unicode_escapes: bool) -> Result { // We've parsed '\u', now we have to parse '{..}'. if chars.next() != Some('{') { @@ -286,7 +296,7 @@ fn scan_unicode( // Incorrect syntax has higher priority for error reporting // than unallowed value for a literal. - if is_unicode_escape_disallowed { + if !allow_unicode_escapes { return Err(EscapeError::UnicodeEscapeInByte); } @@ -312,12 +322,8 @@ fn scan_unicode( } #[inline] -fn ascii_check(c: char, chars_should_be_ascii: bool) -> Result { - if chars_should_be_ascii && !c.is_ascii() { - Err(EscapeError::NonAsciiCharInByte) - } else { - Ok(c) - } +fn ascii_check(c: char, allow_unicode_chars: bool) -> Result { + if allow_unicode_chars || c.is_ascii() { Ok(c) } else { Err(EscapeError::NonAsciiCharInByte) } } fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result { @@ -326,7 +332,7 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result scan_escape(chars, mode), '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar), '\r' => Err(EscapeError::BareCarriageReturn), - _ => ascii_check(c, mode.chars_should_be_ascii()), + _ => ascii_check(c, mode.allow_unicode_chars()), }?; if chars.next().is_some() { return Err(EscapeError::MoreThanOneChar); @@ -336,12 +342,12 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result + From>(src: &str, mode: Mode, callback: &mut F) +fn unescape_non_raw_common + From>(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range, Result), { let mut chars = src.chars(); - let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop + let allow_unicode_chars = mode.allow_unicode_chars(); // get this outside the loop // The `start` and `end` computation here is complicated because // `skip_ascii_whitespace` makes us to skip over chars without counting @@ -366,7 +372,7 @@ where } '"' => Err(EscapeError::EscapeOnlyChar), '\r' => Err(EscapeError::BareCarriageReturn), - _ => ascii_check(c, chars_should_be_ascii).map(Into::into), + _ => ascii_check(c, allow_unicode_chars).map(T::from), }; let end = src.len() - chars.as_str().len(); callback(start..end, res); @@ -408,7 +414,7 @@ where F: FnMut(Range, Result), { let mut chars = src.chars(); - let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop + let allow_unicode_chars = mode.allow_unicode_chars(); // get this outside the loop // The `start` and `end` computation here matches the one in // `unescape_non_raw_common` for consistency, even though this function @@ -417,7 +423,7 @@ where let start = src.len() - chars.as_str().len() - c.len_utf8(); let res = match c { '\r' => Err(EscapeError::BareCarriageReturnInRawString), - _ => ascii_check(c, chars_should_be_ascii), + _ => ascii_check(c, allow_unicode_chars), }; let end = src.len() - chars.as_str().len(); callback(start..end, res); @@ -430,7 +436,3 @@ pub fn byte_from_char(c: char) -> u8 { debug_assert!(res <= u8::MAX as u32, "guaranteed because of ByteStr"); res as u8 } - -fn is_ascii(x: u32) -> bool { - x <= 0x7F -} diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs index 1c25b03fdb22e..5b99495f47581 100644 --- a/compiler/rustc_lexer/src/unescape/tests.rs +++ b/compiler/rustc_lexer/src/unescape/tests.rs @@ -100,7 +100,7 @@ fn test_unescape_char_good() { fn test_unescape_str_warn() { fn check(literal: &str, expected: &[(Range, Result)]) { let mut unescaped = Vec::with_capacity(literal.len()); - unescape_literal(literal, Mode::Str, &mut |range, res| unescaped.push((range, res))); + unescape_unicode(literal, Mode::Str, &mut |range, res| unescaped.push((range, res))); assert_eq!(unescaped, expected); } @@ -124,7 +124,7 @@ fn test_unescape_str_warn() { fn test_unescape_str_good() { fn check(literal_text: &str, expected: &str) { let mut buf = Ok(String::with_capacity(literal_text.len())); - unescape_literal(literal_text, Mode::Str, &mut |range, c| { + unescape_unicode(literal_text, Mode::Str, &mut |range, c| { if let Ok(b) = &mut buf { match c { Ok(c) => b.push(c), @@ -241,7 +241,7 @@ fn test_unescape_byte_good() { fn test_unescape_byte_str_good() { fn check(literal_text: &str, expected: &[u8]) { let mut buf = Ok(Vec::with_capacity(literal_text.len())); - unescape_literal(literal_text, Mode::ByteStr, &mut |range, c| { + unescape_unicode(literal_text, Mode::ByteStr, &mut |range, c| { if let Ok(b) = &mut buf { match c { Ok(c) => b.push(byte_from_char(c)), @@ -264,7 +264,7 @@ fn test_unescape_byte_str_good() { fn test_unescape_raw_str() { fn check(literal: &str, expected: &[(Range, Result)]) { let mut unescaped = Vec::with_capacity(literal.len()); - unescape_literal(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res))); + unescape_unicode(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res))); assert_eq!(unescaped, expected); } @@ -276,7 +276,7 @@ fn test_unescape_raw_str() { fn test_unescape_raw_byte_str() { fn check(literal: &str, expected: &[(Range, Result)]) { let mut unescaped = Vec::with_capacity(literal.len()); - unescape_literal(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res))); + unescape_unicode(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res))); assert_eq!(unescaped, expected); } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index b6fa2f1f22163..5652a34103b09 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -148,7 +148,7 @@ lint_builtin_unsafe_impl = implementation of an `unsafe` trait lint_builtin_unsafe_trait = declaration of an `unsafe` trait -lint_builtin_unstable_features = unstable feature +lint_builtin_unstable_features = use of an unstable feature lint_builtin_unused_doc_comment = unused doc comment .label = rustdoc does not generate documentation for {$kind} @@ -240,7 +240,10 @@ lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of lint_identifier_non_ascii_char = identifier contains non-ASCII characters -lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints +lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> + [one] an uncommon Unicode codepoint + *[other] uncommon Unicode codepoints +}: {$codepoints} lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level @@ -345,6 +348,9 @@ lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple lint_node_source = `forbid` level set here .note = {$reason} +lint_non_binding_let_multi_drop_fn = + consider immediately dropping the value using `drop(..)` after the `let` statement + lint_non_binding_let_multi_suggestion = consider immediately dropping the value diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 814991cd8c971..3a5c585366a31 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } else { None }; - cx.emit_spanned_lint( + cx.emit_span_lint( ARRAY_INTO_ITER, call.ident.span, ArrayIntoIterDiag { target, suggestion: call.ident.span, sub }, diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index 512136473617c..5f7a3137d52d4 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { def.owner_id.def_id, " + Send", ); - cx.tcx.emit_spanned_lint( + cx.tcx.emit_node_span_lint( ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5e1f2ed11ac95..f10d3d4a68a76 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -72,7 +72,7 @@ use crate::nonstandard_style::{method_context, MethodLateContext}; use std::fmt::Write; -// hardwired lints from librustc_middle +// hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; declare_lint! { @@ -121,7 +121,7 @@ impl EarlyLintPass for WhileTrue { "{}loop", label.map_or_else(String::new, |label| format!("{}: ", label.ident,)) ); - cx.emit_spanned_lint( + cx.emit_span_lint( WHILE_TRUE, condition_span, BuiltinWhileTrue { suggestion: condition_span, replace }, @@ -162,7 +162,7 @@ impl BoxPointers { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() { - cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); + cx.emit_span_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); } } } @@ -265,7 +265,7 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { if cx.tcx.find_field_index(ident, variant) == Some(cx.typeck_results().field_index(fieldpat.hir_id)) { - cx.emit_spanned_lint( + cx.emit_span_lint( NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, BuiltinNonShorthandFieldPatterns { @@ -334,7 +334,7 @@ impl UnsafeCode { return; } - cx.emit_spanned_lint(UNSAFE_CODE, span, decorate); + cx.emit_span_lint(UNSAFE_CODE, span, decorate); } } @@ -509,7 +509,7 @@ impl MissingDoc { 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_spanned_lint( + cx.emit_span_lint( MISSING_DOCS, cx.tcx.def_span(def_id), BuiltinMissingDoc { article, desc }, @@ -710,7 +710,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { ) .is_ok() { - cx.emit_spanned_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl); + cx.emit_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl); } } } @@ -795,7 +795,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { .next() .is_some(); if !has_impl { - cx.emit_spanned_lint( + cx.emit_span_lint( MISSING_DEBUG_IMPLEMENTATIONS, item.span, BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug }, @@ -874,7 +874,7 @@ impl EarlyLintPass for AnonymousParameters { } else { ("", Applicability::HasPlaceholders) }; - cx.emit_spanned_lint( + cx.emit_span_lint( ANONYMOUS_PARAMETERS, arg.pat.span, BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip }, @@ -921,7 +921,7 @@ impl EarlyLintPass for DeprecatedAttr { BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span } } }; - cx.emit_spanned_lint( + cx.emit_span_lint( DEPRECATED, attr.span, BuiltinDeprecatedAttrLink { name, reason, link, suggestion }, @@ -931,7 +931,7 @@ impl EarlyLintPass for DeprecatedAttr { } } if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { - cx.emit_spanned_lint( + cx.emit_span_lint( DEPRECATED, attr.span, BuiltinDeprecatedAttrUsed { @@ -973,7 +973,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & BuiltinUnusedDocCommentSub::BlockHelp } }; - cx.emit_spanned_lint( + cx.emit_span_lint( UNUSED_DOC_COMMENTS, span, BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub }, @@ -1107,7 +1107,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - cx.emit_spanned_lint( + cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span }, @@ -1138,7 +1138,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to - cx.emit_spanned_lint( + cx.emit_span_lint( NO_MANGLE_CONST_ITEMS, it.span, BuiltinConstNoMangle { suggestion }, @@ -1201,7 +1201,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if from_mutbl < to_mutbl { - cx.emit_spanned_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes); + cx.emit_span_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes); } } @@ -1233,10 +1233,30 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } declare_lint! { - /// The `unstable_features` is deprecated and should no longer be used. + /// The `unstable_features` lint detects uses of `#![feature]`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unstable_features)] + /// #![feature(test)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In larger nightly-based projects which + /// + /// * consist of a multitude of crates where a subset of crates has to compile on + /// stable either unconditionally or depending on a `cfg` flag to for example + /// allow stable users to depend on them, + /// * don't use nightly for experimental features but for, e.g., unstable options only, + /// + /// this lint may come in handy to enforce policies of these kinds. UNSTABLE_FEATURES, Allow, - "enabling unstable features (deprecated. do not use)" + "enabling unstable features" } declare_lint_pass!( @@ -1246,11 +1266,11 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { - if attr.has_name(sym::feature) { - if let Some(items) = attr.meta_item_list() { - for item in items { - cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); - } + if attr.has_name(sym::feature) + && let Some(items) = attr.meta_item_list() + { + for item in items { + cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); } } } @@ -1303,7 +1323,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { - cx.emit_spanned_lint( + cx.emit_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess }, @@ -1369,7 +1389,7 @@ impl UnreachablePub { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.def_span(def_id); - cx.emit_spanned_lint( + cx.emit_span_lint( UNREACHABLE_PUB, def_span, BuiltinUnreachablePub { @@ -1498,7 +1518,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { suggested_changing_assoc_types = true; SuggestChangingAssocTypes { ty: hir_ty } }); - cx.emit_spanned_lint( + cx.emit_span_lint( TYPE_ALIAS_BOUNDS, where_spans, BuiltinTypeAliasWhereClause { @@ -1514,7 +1534,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { suggested_changing_assoc_types = true; SuggestChangingAssocTypes { ty: hir_ty } }); - cx.emit_spanned_lint( + cx.emit_span_lint( TYPE_ALIAS_BOUNDS, inline_spans, BuiltinTypeAliasGenericBounds { suggestion, sub }, @@ -1613,7 +1633,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { | ClauseKind::ConstEvaluatable(..) => continue, }; if predicate.is_global() { - cx.emit_spanned_lint( + cx.emit_span_lint( TRIVIAL_BOUNDS, span, BuiltinTrivialBounds { predicate_kind_name, predicate }, @@ -1731,7 +1751,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { replace, }); } else { - cx.emit_spanned_lint( + cx.emit_span_lint( ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise { @@ -1749,7 +1769,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { replace: replace.to_string(), }); } else { - cx.emit_spanned_lint( + cx.emit_span_lint( ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise { @@ -1875,7 +1895,7 @@ impl KeywordIdents { return; } - cx.emit_spanned_lint( + cx.emit_span_lint( KEYWORD_IDENTS, ident.span, BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span }, @@ -2183,7 +2203,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { lint_spans.sort_unstable(); lint_spans.dedup(); - cx.emit_spanned_lint( + cx.emit_span_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), BuiltinExplicitOutlives { @@ -2270,13 +2290,13 @@ impl EarlyLintPass for IncompleteInternalFeatures { let help = HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); - cx.emit_spanned_lint( + cx.emit_span_lint( INCOMPLETE_FEATURES, span, BuiltinIncompleteFeatures { name, note, help }, ); } else { - cx.emit_spanned_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name }); + cx.emit_span_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name }); } }); } @@ -2592,7 +2612,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit, }; let sub = BuiltinUnpermittedTypeInitSub { err }; - cx.emit_spanned_lint( + cx.emit_span_lint( INVALID_VALUE, expr.span, BuiltinUnpermittedTypeInit { @@ -2680,7 +2700,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if is_null_ptr(cx, expr_deref) { - cx.emit_spanned_lint( + cx.emit_span_lint( DEREF_NULLPTR, expr.span, BuiltinDerefNullptr { label: expr.span }, @@ -2829,7 +2849,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { let target_spans: MultiSpan = if spans.len() > 0 { spans.into() } else { (*template_span).into() }; - cx.lookup_with_diagnostics( + cx.span_lint_with_diagnostics( NAMED_ASM_LABELS, Some(target_spans), fluent::lint_builtin_asm_labels, @@ -2905,12 +2925,12 @@ impl EarlyLintPass for SpecialModuleName { } match item.ident.name.as_str() { - "lib" => cx.emit_spanned_lint( + "lib" => cx.emit_span_lint( SPECIAL_MODULE_NAME, item.span, BuiltinSpecialModuleNameUsed::Lib, ), - "main" => cx.emit_spanned_lint( + "main" => cx.emit_span_lint( SPECIAL_MODULE_NAME, item.span, BuiltinSpecialModuleNameUsed::Main, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index ffd8f1b3c79c5..1c480ec8f53b1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -326,11 +326,9 @@ impl LintStore { /// True if this symbol represents a lint group name. pub fn is_lint_group(&self, lint_name: Symbol) -> bool { - debug!( - "is_lint_group(lint_name={:?}, lint_groups={:?})", - lint_name, - self.lint_groups.keys().collect::>() - ); + #[allow(rustc::potential_query_instability)] + let lint_groups = self.lint_groups.keys().collect::>(); + debug!("is_lint_group(lint_name={:?}, lint_groups={:?})", lint_name, lint_groups); let lint_name_str = lint_name.as_str(); self.lint_groups.contains_key(lint_name_str) || { let warnings_name_str = crate::WARNINGS.name_lower(); @@ -374,8 +372,12 @@ impl LintStore { None => { // 1. The tool is currently running, so this lint really doesn't exist. // FIXME: should this handle tools that never register a lint, like rustfmt? - debug!("lints={:?}", self.by_name.keys().collect::>()); + #[allow(rustc::potential_query_instability)] + let lints = self.by_name.keys().collect::>(); + debug!("lints={:?}", lints); let tool_prefix = format!("{tool_name}::"); + + #[allow(rustc::potential_query_instability)] return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { self.no_lint_suggestion(&complete_name, tool_name.as_str()) } else { @@ -530,9 +532,9 @@ pub trait LintContext { /// Emit a lint at the appropriate level, with an optional associated span and an existing /// diagnostic. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] - fn lookup_with_diagnostics( + fn span_lint_with_diagnostics( &self, lint: &'static Lint, span: Option>, @@ -541,7 +543,7 @@ pub trait LintContext { diagnostic: BuiltinLintDiagnostics, ) { // We first generate a blank diagnostic. - self.lookup(lint, span, msg, |db| { + self.opt_span_lint(lint, span, msg, |db| { // Now, set up surrounding context. diagnostics::builtin(self.sess(), diagnostic, db); // Rewrap `db`, and pass control to the user. @@ -553,9 +555,9 @@ pub trait LintContext { // set the span in their `decorate` function (preferably using set_span). /// Emit a lint at the appropriate level, with an optional associated span. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] - fn lookup>( + fn opt_span_lint>( &self, lint: &'static Lint, span: Option, @@ -565,42 +567,42 @@ pub trait LintContext { /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, /// typically generated by `#[derive(LintDiagnostic)]`). - fn emit_spanned_lint>( + fn emit_span_lint>( &self, lint: &'static Lint, span: S, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.lookup(lint, Some(span), decorator.msg(), |diag| { + self.opt_span_lint(lint, Some(span), decorator.msg(), |diag| { decorator.decorate_lint(diag); }); } /// Emit a lint at the appropriate level, with an associated span. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] - fn struct_span_lint>( + fn span_lint>( &self, lint: &'static Lint, span: S, msg: impl Into, decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { - self.lookup(lint, Some(span), msg, decorate); + self.opt_span_lint(lint, Some(span), msg, decorate); } /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically /// generated by `#[derive(LintDiagnostic)]`). fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) { - self.lookup(lint, None as Option, decorator.msg(), |diag| { + self.opt_span_lint(lint, None as Option, decorator.msg(), |diag| { decorator.decorate_lint(diag); }); } /// Emit a lint at the appropriate level, with no associated span. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] fn lint( &self, @@ -608,7 +610,7 @@ pub trait LintContext { msg: impl Into, decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { - self.lookup(lint, None as Option, msg, decorate); + self.opt_span_lint(lint, None as Option, msg, decorate); } /// This returns the lint level for the given lint at the current location. @@ -666,7 +668,7 @@ impl<'tcx> LintContext for LateContext<'tcx> { } #[rustc_lint_diagnostics] - fn lookup>( + fn opt_span_lint>( &self, lint: &'static Lint, span: Option, @@ -676,8 +678,8 @@ impl<'tcx> LintContext for LateContext<'tcx> { let hir_id = self.last_node_with_lint_attrs; match span { - Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg, decorate), - None => self.tcx.struct_lint_node(lint, hir_id, msg, decorate), + Some(s) => self.tcx.node_span_lint(lint, hir_id, s, msg, decorate), + None => self.tcx.node_lint(lint, hir_id, msg, decorate), } } @@ -693,14 +695,14 @@ impl LintContext for EarlyContext<'_> { } #[rustc_lint_diagnostics] - fn lookup>( + fn opt_span_lint>( &self, lint: &'static Lint, span: Option, msg: impl Into, decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { - self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate) + self.builder.opt_span_lint(lint, span.map(|s| s.into()), msg, decorate) } fn get_lint_level(&self, lint: &'static Lint) -> Level { diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 312874db3f54e..0fa61c5d87e77 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -185,8 +185,26 @@ pub(super) fn builtin( db.note("see the asm section of Rust By Example for more information"); } BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => { + #[allow(rustc::potential_query_instability)] let possibilities: Vec = sess.parse_sess.check_config.expecteds.keys().copied().collect(); + + let mut names_possibilities: Vec<_> = if value.is_none() { + // We later sort and display all the possibilities, so the order here does not matter. + #[allow(rustc::potential_query_instability)] + sess.parse_sess + .check_config + .expecteds + .iter() + .filter_map(|(k, v)| match v { + ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k), + _ => None, + }) + .collect() + } else { + Vec::new() + }; + let is_from_cargo = std::env::var_os("CARGO").is_some(); let mut is_feature_cfg = name == sym::feature; @@ -261,17 +279,30 @@ pub(super) fn builtin( } is_feature_cfg |= best_match == sym::feature; - } else if !possibilities.is_empty() { - let mut possibilities = - possibilities.iter().map(Symbol::as_str).collect::>(); - possibilities.sort(); - let possibilities = possibilities.join("`, `"); + } else { + if !names_possibilities.is_empty() && names_possibilities.len() <= 3 { + names_possibilities.sort(); + for cfg_name in names_possibilities.iter() { + db.span_suggestion( + name_span, + "found config with similar value", + format!("{cfg_name} = \"{name}\""), + Applicability::MaybeIncorrect, + ); + } + } + if !possibilities.is_empty() { + let mut possibilities = + possibilities.iter().map(Symbol::as_str).collect::>(); + possibilities.sort(); + let possibilities = possibilities.join("`, `"); - // The list of expected names can be long (even by default) and - // so the diagnostic produced can take a lot of space. To avoid - // cloging the user output we only want to print that diagnostic - // once. - db.help_once(format!("expected names are: `{possibilities}`")); + // The list of expected names can be long (even by default) and + // so the diagnostic produced can take a lot of space. To avoid + // cloging the user output we only want to print that diagnostic + // once. + db.help_once(format!("expected names are: `{possibilities}`")); + } } let inst = if let Some((value, _value_span)) = value { diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 98bafc0f2637e..9bc81d2c46aa1 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -5,6 +5,7 @@ use crate::{ use rustc_hir as hir; use rustc_middle::ty; +use rustc_session::lint::FutureIncompatibilityReason; use rustc_span::sym; use rustc_trait_selection::traits::supertraits; @@ -12,6 +13,9 @@ declare_lint! { /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. /// + /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized. + /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// /// ### Example /// /// ```rust,compile_fail @@ -40,10 +44,15 @@ declare_lint! { /// /// ### Explanation /// - /// The implicit dyn upcasting coercion take priority over those `Deref` impls. + /// The dyn upcasting coercion feature adds new coercion rules, taking priority + /// over certain other coercion rules, which will cause some behavior change. pub DEREF_INTO_DYN_SUPERTRAIT, Warn, - "`Deref` implementation usage with a supertrait trait object for output are shadow by implicit coercion", + "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, + reference: "issue #89460 ", + }; } declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]); @@ -78,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { .find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) .map(|label| SupertraitAsDerefTargetLabel { label }); let span = tcx.def_span(item.owner_id.def_id); - cx.emit_spanned_lint( + cx.emit_span_lint( DEREF_INTO_DYN_SUPERTRAIT, span, SupertraitAsDerefTarget { diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 390a1620a2a5b..9a31aa062f01a 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -149,28 +149,28 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint( + cx.emit_span_lint( DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span }, ); } sym::mem_forget if arg_ty.is_ref() => { - cx.emit_spanned_lint( + cx.emit_span_lint( FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span }, ); } sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint( + cx.emit_span_lint( DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span }, ); } sym::mem_forget if is_copy => { - cx.emit_spanned_lint( + cx.emit_span_lint( FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }, @@ -180,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { if let ty::Adt(adt, _) = arg_ty.kind() && adt.is_manually_drop() => { - cx.emit_spanned_lint( + cx.emit_span_lint( UNDROPPED_MANUALLY_DROPS, expr.span, UndroppedManuallyDropsDiag { diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 70af6572246f4..5ae080d470235 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -45,7 +45,13 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { fn inlined_check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint; - self.context.lookup_with_diagnostics(lint_id.lint, Some(span), msg, |_| {}, diagnostic); + self.context.span_lint_with_diagnostics( + lint_id.lint, + Some(span), + msg, + |_| {}, + diagnostic, + ); } } diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index 05fe64830d17e..a67f1b62fb0d6 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -53,7 +53,7 @@ fn enforce_mem_discriminant( ) { let ty_param = cx.typeck_results().node_args(func_expr.hir_id).type_at(0); if is_non_enum(ty_param) { - cx.emit_spanned_lint( + cx.emit_span_lint( ENUM_INTRINSICS_NON_ENUMS, expr_span, EnumIntrinsicsMemDiscriminate { ty_param, note: args_span }, @@ -64,11 +64,7 @@ fn enforce_mem_discriminant( fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) { let ty_param = cx.typeck_results().node_args(func_expr.hir_id).type_at(0); if is_non_enum(ty_param) { - cx.emit_spanned_lint( - ENUM_INTRINSICS_NON_ENUMS, - span, - EnumIntrinsicsMemVariant { ty_param }, - ); + cx.emit_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, EnumIntrinsicsMemVariant { ty_param }); } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 841d282a09942..3bd0c1b803199 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,11 +1,11 @@ use crate::fluent_generated as fluent; -use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; +use rustc_errors::{codes::*, AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(lint_overruled_attribute, code = "E0453")] +#[diag(lint_overruled_attribute, code = E0453)] pub struct OverruledAttribute<'a> { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ impl AddToDiagnostic for OverruledAttributeSub { } #[derive(Diagnostic)] -#[diag(lint_malformed_attribute, code = "E0452")] +#[diag(lint_malformed_attribute, code = E0452)] pub struct MalformedAttribute { #[primary_span] pub span: Span, @@ -67,7 +67,7 @@ pub enum MalformedAttributeSub { } #[derive(Diagnostic)] -#[diag(lint_unknown_tool_in_scoped_lint, code = "E0710")] +#[diag(lint_unknown_tool_in_scoped_lint, code = E0710)] pub struct UnknownToolInScopedLint { #[primary_span] pub span: Option, @@ -78,7 +78,7 @@ pub struct UnknownToolInScopedLint { } #[derive(Diagnostic)] -#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")] +#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = E0783)] pub struct BuiltinEllipsisInclusiveRangePatterns { #[primary_span] pub span: Span, @@ -95,13 +95,13 @@ pub struct RequestedLevel<'a> { } #[derive(Diagnostic)] -#[diag(lint_unsupported_group, code = "E0602")] +#[diag(lint_unsupported_group, code = E0602)] pub struct UnsupportedGroup { pub lint_group: String, } #[derive(Diagnostic)] -#[diag(lint_check_name_unknown_tool, code = "E0602")] +#[diag(lint_check_name_unknown_tool, code = E0602)] pub struct CheckNameUnknownTool<'a> { pub tool_name: Symbol, #[subdiagnostic] diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 2b6290e8a0067..40db765da53a9 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -29,7 +29,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { { let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); let note = expectation.is_unfulfilled_lint_expectations.then_some(()); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNFULFILLED_LINT_EXPECTATIONS, *hir_id, expectation.emission_span, diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index ea922785a954b..cb7feea16b538 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { end_span: pat.span.between(arg.span), }; - cx.emit_spanned_lint( + cx.emit_span_lint( FOR_LOOPS_OVER_FALLIBLES, arg.span, ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion }, diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index ecb7a157f39bb..b995f38f23c6e 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -161,7 +161,7 @@ impl ClashingExternDeclarations { sub, } }; - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( CLASHING_EXTERN_DECLARATIONS, this_fi.hir_id(), mismatch_label, diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index 7c1af6bee1dd6..054cfe92a3a48 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -74,7 +74,7 @@ impl HiddenUnicodeCodepoints { HiddenUnicodeCodepointsDiagSub::NoEscape { spans } }; - cx.emit_spanned_lint( + cx.emit_span_lint( TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub }, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index e3405aa2e5595..eb2490a47d09d 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -43,7 +43,7 @@ impl LateLintPass<'_> for DefaultHashTypes { Some(sym::HashSet) => "FxHashSet", _ => return, }; - cx.emit_spanned_lint( + cx.emit_span_lint( DEFAULT_HASH_TYPES, path.span, DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) }, @@ -91,7 +91,7 @@ impl LateLintPass<'_> for QueryStability { if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args) { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { - cx.emit_spanned_lint( + cx.emit_span_lint( POTENTIAL_QUERY_INSTABILITY, span, QueryInstability { query: cx.tcx.item_name(def_id) }, @@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { { let span = path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()); - cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span }); + cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span }); } } @@ -186,19 +186,19 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { match span { Some(span) => { - cx.emit_spanned_lint( + cx.emit_span_lint( USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span }, ); } - None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), + None => cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), } } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, path) { - cx.emit_spanned_lint( + cx.emit_span_lint( USAGE_OF_QUALIFIED_TY, path.span, TyQualified { ty, suggestion: path.span }, @@ -285,7 +285,7 @@ impl EarlyLintPass for LintPassImpl { && call_site.ctxt().outer_expn_data().kind != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass) { - cx.emit_spanned_lint( + cx.emit_span_lint( LINT_PASS_IMPL_WITHOUT_MACRO, lint_pass.path.span, LintPassByHand, @@ -327,7 +327,7 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { if is_doc_keyword(keyword) { return; } - cx.emit_spanned_lint( + cx.emit_span_lint( EXISTING_DOC_KEYWORD, attr.span, NonExistentDocKeyword { keyword }, @@ -405,7 +405,7 @@ impl LateLintPass<'_> for Diagnostics { } debug!(?found_impl); if !found_parent_with_attr && !found_impl { - cx.emit_spanned_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl); + cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl); } let mut found_diagnostic_message = false; @@ -421,7 +421,7 @@ impl LateLintPass<'_> for Diagnostics { } debug!(?found_diagnostic_message); if !found_parent_with_attr && !found_diagnostic_message { - cx.emit_spanned_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag); + cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag); } } } @@ -490,7 +490,7 @@ impl EarlyLintPass for Diagnostics { }) { return; } - cx.emit_spanned_lint( + cx.emit_span_lint( UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL, stmt.span, UntranslatableDiagnosticTrivial, @@ -528,7 +528,7 @@ impl LateLintPass<'_> for BadOptAccess { && let Some(lit) = item.lit() && let ast::LitKind::Str(val, _) = lit.kind { - cx.emit_spanned_lint( + cx.emit_span_lint( BAD_OPT_ACCESS, expr.span, BadOptAccessDiag { msg: val.as_str() }, @@ -553,7 +553,7 @@ impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { expr.kind { if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) { - cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); + cx.emit_span_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); } } } diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 0b91b77a9f24b..081e3e875302b 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { let valid_up_to = utf8_error.valid_up_to(); let is_unchecked_variant = diag_item.as_str().contains("unchecked"); - cx.emit_spanned_lint( + cx.emit_span_lint( if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { @@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { .map(|e| match &e.kind { ExprKind::Lit(Spanned { node: lit, .. }) => match lit { LitKind::Byte(b) => Some(*b), - LitKind::Int(b, _) => Some(*b as u8), + LitKind::Int(b, _) => Some(b.get() as u8), _ => None, }, _ => None, diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index bdace8e01f6c5..c552b9832553a 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -5,7 +5,7 @@ use crate::{ use rustc_errors::MultiSpan; use rustc_hir as hir; use rustc_middle::ty; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; declare_lint! { /// The `let_underscore_drop` lint checks for statements which don't bind @@ -105,51 +105,66 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { - if !matches!(local.pat.kind, hir::PatKind::Wild) { - return; - } - if matches!(local.source, rustc_hir::LocalSource::AsyncFn) { return; } - if let Some(init) = local.init { - let init_ty = cx.typeck_results().expr_ty(init); + + let mut top_level = true; + + // We recursively walk through all patterns, so that we can catch cases where the lock is nested in a pattern. + // For the basic `let_underscore_drop` lint, we only look at the top level, since there are many legitimate reasons + // to bind a sub-pattern to an `_`, if we're only interested in the rest. + // But with locks, we prefer having the chance of "false positives" over missing cases, since the effects can be + // quite catastrophic. + local.pat.walk_always(|pat| { + let is_top_level = top_level; + top_level = false; + + if !matches!(pat.kind, hir::PatKind::Wild) { + return; + } + + let ty = cx.typeck_results().pat_ty(pat); + // If the type has a trivial Drop implementation, then it doesn't // matter that we drop the value immediately. - if !init_ty.needs_drop(cx.tcx, cx.param_env) { + if !ty.needs_drop(cx.tcx, cx.param_env) { return; } - let is_sync_lock = match init_ty.kind() { + // Lint for patterns like `mutex.lock()`, which returns `Result` as well. + let potential_lock_type = match ty.kind() { + ty::Adt(adt, args) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => { + args.type_at(0) + } + _ => ty, + }; + let is_sync_lock = match potential_lock_type.kind() { ty::Adt(adt, _) => SYNC_GUARD_SYMBOLS .iter() .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), _ => false, }; + let can_use_init = is_top_level.then_some(local.init).flatten(); + let sub = NonBindingLetSub { - suggestion: local.pat.span, - multi_suggestion_start: local.span.until(init.span), - multi_suggestion_end: init.span.shrink_to_hi(), + suggestion: pat.span, + // We can't suggest `drop()` when we're on the top level. + drop_fn_start_end: can_use_init + .map(|init| (local.span.until(init.span), init.span.shrink_to_hi())), is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)), }; if is_sync_lock { - let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); + let mut span = MultiSpan::from_span(pat.span); span.push_span_label( - local.pat.span, + pat.span, "this lock is not assigned to a binding and is immediately dropped".to_string(), ); - span.push_span_label( - init.span, - "this binding will immediately drop the value assigned to it".to_string(), - ); - cx.emit_spanned_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub }); - } else { - cx.emit_spanned_lint( - LET_UNDERSCORE_DROP, - local.span, - NonBindingLet::DropType { sub }, - ); + cx.emit_span_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub }); + // Only emit let_underscore_drop for top-level `_` patterns. + } else if can_use_init.is_some() { + cx.emit_span_lint(LET_UNDERSCORE_DROP, local.span, NonBindingLet::DropType { sub }); } - } + }); } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index b98b1a2935c04..40fb12b21070b 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -24,7 +24,7 @@ use rustc_hir::HirId; use rustc_index::IndexVec; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource, + lint_level, reveal_actual_level, LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, }; use rustc_middle::query::Providers; @@ -181,7 +181,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe // Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do // a standard visit. // FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's. - _ => match tcx.hir().owner(owner) { + _ => match tcx.hir_owner_node(owner) { hir::OwnerNode::Item(item) => levels.visit_item(item), hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item), hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item), @@ -682,7 +682,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { sub, }); } else { - self.emit_spanned_lint( + self.emit_span_lint( FORBIDDEN_LINT_GROUPS, src.span().into(), OverruledAttributeLint { @@ -925,7 +925,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } Err((Some(ids), ref new_lint_name)) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; - self.emit_spanned_lint( + self.emit_span_lint( lint, sp.into(), DeprecatedLintName { @@ -976,13 +976,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); let lint = RenamedLint { name: name.as_str(), suggestion }; - self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); + self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } CheckLintNameResult::Removed(ref reason) => { let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); let lint = RemovedLint { name: name.as_str(), reason }; - self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); + self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } CheckLintNameResult::NoLint(suggestion) => { @@ -995,7 +995,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { UnknownLintSuggestion::WithSpan { suggestion: sp, replace, from_rustc } }); let lint = UnknownLint { name, suggestion }; - self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint); + self.emit_span_lint(UNKNOWN_LINTS, sp.into(), lint); } } // If this lint was renamed, apply the new lint instead of ignoring the attribute. @@ -1041,7 +1041,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue; }; - self.emit_spanned_lint( + self.emit_span_lint( UNUSED_ATTRIBUTES, lint_attr_span.into(), IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name }, @@ -1062,7 +1062,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { if self.lint_added_lints { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS); - struct_lint_level( + lint_level( self.sess, lint, level, @@ -1096,10 +1096,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] #[track_caller] - pub(crate) fn struct_lint( + pub(crate) fn opt_span_lint( &self, lint: &'static Lint, span: Option, @@ -1107,18 +1107,18 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let (level, src) = self.lint_level(lint); - struct_lint_level(self.sess, lint, level, src, span, msg, decorate) + lint_level(self.sess, lint, level, src, span, msg, decorate) } #[track_caller] - pub fn emit_spanned_lint( + pub fn emit_span_lint( &self, lint: &'static Lint, span: MultiSpan, decorate: impl for<'a> DecorateLint<'a, ()>, ) { let (level, src) = self.lint_level(lint); - struct_lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| { + lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| { decorate.decorate_lint(lint); }); } @@ -1126,7 +1126,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { #[track_caller] pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> DecorateLint<'a, ()>) { let (level, src) = self.lint_level(lint); - struct_lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| { + lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| { decorate.decorate_lint(lint); }); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a9996e4a155bf..1c03de410ee7d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -32,13 +32,11 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] -#![feature(iter_intersperse)] #![feature(iter_order_by)] #![feature(let_chains)] +#![cfg_attr(not(bootstrap), feature(trait_upcasting))] #![feature(min_specialization)] -#![feature(never_type)] #![feature(rustc_attrs)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] @@ -518,6 +516,15 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see PR #118649 \ for more information", ); + store.register_removed( + "illegal_floating_point_literal_pattern", + "no longer a warning, float patterns behave the same as `==`", + ); + store.register_removed( + "nontrivial_structural_match", + "no longer needed, see RFC #3535 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 73db5790c2b3b..f916deb4a46d1 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,8 +5,8 @@ use std::num::NonZeroU32; use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, DiagnosticMessage, - DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle, + codes::*, AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, + DiagnosticMessage, DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; @@ -532,7 +532,6 @@ pub enum BuiltinSpecialModuleNameUsed { // deref_into_dyn_supertrait.rs #[derive(LintDiagnostic)] #[diag(lint_supertrait_as_deref_target)] -#[help] pub struct SupertraitAsDerefTarget<'a> { pub self_ty: Ty<'a>, pub supertrait_principal: PolyExistentialTraitRef<'a>, @@ -930,8 +929,7 @@ pub enum NonBindingLet { pub struct NonBindingLetSub { pub suggestion: Span, - pub multi_suggestion_start: Span, - pub multi_suggestion_end: Span, + pub drop_fn_start_end: Option<(Span, Span)>, pub is_assign_desugar: bool, } @@ -940,21 +938,31 @@ impl AddToDiagnostic for NonBindingLetSub { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - let prefix = if self.is_assign_desugar { "let " } else { "" }; - diag.span_suggestion_verbose( - self.suggestion, - fluent::lint_non_binding_let_suggestion, - format!("{prefix}_unused"), - Applicability::MachineApplicable, - ); - diag.multipart_suggestion( - fluent::lint_non_binding_let_multi_suggestion, - vec![ - (self.multi_suggestion_start, "drop(".to_string()), - (self.multi_suggestion_end, ")".to_string()), - ], - Applicability::MachineApplicable, - ); + let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; + + if can_suggest_binding { + let prefix = if self.is_assign_desugar { "let " } else { "" }; + diag.span_suggestion_verbose( + self.suggestion, + fluent::lint_non_binding_let_suggestion, + format!("{prefix}_unused"), + Applicability::MachineApplicable, + ); + } else { + diag.span_help(self.suggestion, fluent::lint_non_binding_let_suggestion); + } + if let Some(drop_fn_start_end) = self.drop_fn_start_end { + diag.multipart_suggestion( + fluent::lint_non_binding_let_multi_suggestion, + vec![ + (drop_fn_start_end.0, "drop(".to_string()), + (drop_fn_start_end.1, ")".to_string()), + ], + Applicability::MachineApplicable, + ); + } else { + diag.help(fluent::lint_non_binding_let_multi_drop_fn); + } } } @@ -1057,7 +1065,7 @@ pub enum UnknownLintSuggestion { } #[derive(LintDiagnostic)] -#[diag(lint_unknown_lint, code = "E0602")] +#[diag(lint_unknown_lint, code = E0602)] pub struct UnknownLintFromCommandLine<'a> { pub name: String, #[subdiagnostic] @@ -1099,7 +1107,10 @@ pub struct IdentifierNonAsciiChar; #[derive(LintDiagnostic)] #[diag(lint_identifier_uncommon_codepoints)] -pub struct IdentifierUncommonCodepoints; +pub struct IdentifierUncommonCodepoints { + pub codepoints: Vec, + pub codepoints_len: usize, +} #[derive(LintDiagnostic)] #[diag(lint_confusable_identifier_pair)] diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 7c692fee33389..07980cfb6fa0f 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { let fn_ty = cx.tcx.fn_sig(id).skip_binder(); let ret_ty = fn_ty.output().skip_binder(); if is_unit_type(ret_ty) { - cx.emit_spanned_lint( + cx.emit_span_lint( MAP_UNIT_FN, span, MappingToUnit { @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { let cl_ty = subs.as_closure().sig(); let ret_ty = cl_ty.output().skip_binder(); if is_unit_type(ret_ty) { - cx.emit_spanned_lint( + cx.emit_span_lint( MAP_UNIT_FN, span, MappingToUnit { diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 5b63b19c53c8a..9cfdaf0ce2ff6 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -57,7 +57,7 @@ fn lint_cstring_as_ptr( if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { if let ty::Adt(adt, _) = args.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { - cx.emit_spanned_lint( + cx.emit_span_lint( TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr { as_ptr: as_ptr_span, unwrap: unwrap.span }, diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index dfefaf82fd7da..69d623b547b58 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .into_iter() .filter_map(|(pred, _)| pred.as_trait_clause()); if direct_super_traits_iter.count() > 1 { - cx.emit_spanned_lint( + cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, cx.tcx.def_span(def_id), crate::lints::MultipleSupertraitUpcastable { ident: item.ident }, diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 3405dd3a9169c..f78b32ce5e77b 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -186,11 +186,21 @@ impl EarlyLintPass for NonAsciiIdents { continue; } has_non_ascii_idents = true; - cx.emit_spanned_lint(NON_ASCII_IDENTS, sp, IdentifierNonAsciiChar); + cx.emit_span_lint(NON_ASCII_IDENTS, sp, IdentifierNonAsciiChar); if check_uncommon_codepoints && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) { - cx.emit_spanned_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints); + let codepoints: Vec<_> = symbol_str + .chars() + .filter(|c| !GeneralSecurityProfile::identifier_allowed(*c)) + .collect(); + let codepoints_len = codepoints.len(); + + cx.emit_span_lint( + UNCOMMON_CODEPOINTS, + sp, + IdentifierUncommonCodepoints { codepoints, codepoints_len }, + ); } } @@ -218,7 +228,7 @@ impl EarlyLintPass for NonAsciiIdents { .entry(skeleton_sym) .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| { if !*existing_is_ascii || !is_ascii { - cx.emit_spanned_lint( + cx.emit_span_lint( CONFUSABLE_IDENTS, sp, ConfusableIdentifierPair { @@ -339,7 +349,7 @@ impl EarlyLintPass for NonAsciiIdents { let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); includes += &char_info; } - cx.emit_spanned_lint( + cx.emit_span_lint( MIXED_SCRIPT_CONFUSABLES, sp, MixedScriptConfusables { set: script_set.to_string(), includes }, diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 479acd88d7183..ebef77f687972 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -121,7 +121,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } #[allow(rustc::diagnostic_outside_of_impl)] - cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { + cx.span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { lint.arg("name", symbol); lint.note(fluent::lint_note); lint.note(fluent::lint_more_info_note); @@ -251,7 +251,7 @@ fn check_panic_str<'tcx>( .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .collect(), }; - cx.emit_spanned_lint( + cx.emit_span_lint( NON_FMT_PANICS, arg_spans, NonFmtPanicUnused { @@ -268,7 +268,7 @@ fn check_panic_str<'tcx>( .collect() }); let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2); - cx.emit_spanned_lint( + cx.emit_span_lint( NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), NonFmtPanicBraces { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 59f27a88aec63..05b39829a12f1 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -150,7 +150,7 @@ impl NonCamelCaseTypes { } else { NonCamelCaseTypeSub::Label { span: ident.span } }; - cx.emit_spanned_lint( + cx.emit_span_lint( NON_CAMEL_CASE_TYPES, ident.span, NonCamelCaseType { sort, name, sub }, @@ -320,7 +320,7 @@ impl NonSnakeCase { } else { NonSnakeCaseDiagSub::Label { span } }; - cx.emit_spanned_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub }); + cx.emit_span_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub }); } } } @@ -481,7 +481,7 @@ impl NonUpperCaseGlobals { } else { NonUpperCaseGlobalSub::Label { span: ident.span } }; - cx.emit_spanned_lint( + cx.emit_span_lint( NON_UPPER_CASE_GLOBALS, ident.span, NonUpperCaseGlobal { sort, name, sub }, diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index cfbca6efbfa54..26c5e4fb4837d 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { let orig_ty = expr_ty.peel_refs(); if receiver_ty == expr_ty { - cx.emit_spanned_lint( + cx.emit_span_lint( NOOP_METHOD_CALL, span, NoopMethodCallDiag { method: call.ident.name, orig_ty, trait_, label: span }, @@ -131,12 +131,12 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // If `type_of(x) == T` and `x.borrow()` is used to get `&T`, // then that should be allowed sym::noop_method_borrow => return, - sym::noop_method_clone => cx.emit_spanned_lint( + sym::noop_method_clone => cx.emit_span_lint( SUSPICIOUS_DOUBLE_REF_OP, span, SuspiciousDoubleRefCloneDiag { ty: expr_ty }, ), - sym::noop_method_deref => cx.emit_spanned_lint( + sym::noop_method_deref => cx.emit_span_lint( SUSPICIOUS_DOUBLE_REF_OP, span, SuspiciousDoubleRefDerefDiag { ty: expr_ty }, diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 44b23b8bdc0c3..bed5d3c80c046 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -4,7 +4,7 @@ use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ self, fold::BottomUpFolder, print::TraitPredPrintModifiersAndPath, Ty, TypeFoldable, }; -use rustc_span::Span; +use rustc_span::{symbol::kw, Span}; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -96,6 +96,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { continue; } + // HACK: `async fn() -> Self` in traits is "ok"... + // This is not really that great, but it's similar to why the `-> Self` + // return type is well-formed in traits even when `Self` isn't sized. + if let ty::Param(param_ty) = *proj_term.kind() + && param_ty.name == kw::SelfUpper + && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_)) + && opaque.in_trait + { + continue; + } + let proj_ty = Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args); // For every instance of the projection type in the bounds, @@ -145,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { }), _ => None, }; - cx.emit_spanned_lint( + cx.emit_span_lint( OPAQUE_HIDDEN_INFERRED_BOUND, pred_span, OpaqueHiddenInferredBoundLint { diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index fce750c9b558f..160d42caa9e2a 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -29,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } } if let Some(t) = path_for_pass_by_value(cx, inner_ty) { - cx.emit_spanned_lint( + cx.emit_span_lint( PASS_BY_VALUE, ty.span, PassByValueDiag { ty: t, suggestion: ty.span }, diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 4ac8a5ceb8553..8038115ef51c1 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { ) && let Some(diag) = incorrect_check(cx, arg) => { - cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) + cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } // Catching: @@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { ) && let Some(diag) = incorrect_check(cx, receiver) => { - cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) + cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { @@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { && let LitKind::Int(v, _) = spanned.node && v == 0 => { - cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) + cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } // Catching: @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) => { - cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) + cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } _ => {} diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 9a8b14b4907ea..1681ac2f1e5a4 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -47,7 +47,7 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo return; } - cx.emit_spanned_lint( + cx.emit_span_lint( REDUNDANT_SEMICOLONS, span, RedundantSemicolonsDiag { multiple, suggestion: span }, diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 96290288f072c..9e6cca8531784 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { let orig_cast = if init.span != e.span { Some(init.span) } else { None }; let ty_has_interior_mutability = ty_has_interior_mutability.then_some(()); - cx.emit_spanned_lint( + cx.emit_span_lint( INVALID_REFERENCE_CASTING, expr.span, if pat == PatternKind::Assign { diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index e812493b3dd39..789f154eac5bc 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { continue; } let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - cx.emit_spanned_lint( + cx.emit_span_lint( DROP_BOUNDS, span, DropTraitConstraintsDiag { predicate, tcx: cx.tcx, def_id }, @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let def_id = bound.trait_ref.trait_def_id(); if cx.tcx.lang_items().drop_trait() == def_id { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - cx.emit_spanned_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); + cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a86fe2db2b2d5..1205395b8908d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -254,7 +254,7 @@ fn lint_overflowing_range_endpoint<'tcx>( } }; - cx.emit_spanned_lint( + cx.emit_span_lint( OVERFLOWING_LITERALS, struct_expr.span, RangeEndpointOutOfRange { ty, sub: sub_sugg }, @@ -371,7 +371,7 @@ fn report_bin_hex_error( }) .flatten(); - cx.emit_spanned_lint( + cx.emit_span_lint( OVERFLOWING_LITERALS, expr.span, OverflowingBinHex { @@ -473,7 +473,7 @@ fn lint_int_literal<'tcx>( let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); - cx.emit_spanned_lint( + cx.emit_span_lint( OVERFLOWING_LITERALS, span, OverflowingInt { ty: t.name_str(), lit, min, max, help }, @@ -492,7 +492,7 @@ fn lint_uint_literal<'tcx>( let lit_val: u128 = match lit.node { // _v is u8, within range by definition ast::LitKind::Byte(_v) => return, - ast::LitKind::Int(v, _) => v, + ast::LitKind::Int(v, _) => v.get(), _ => bug!(), }; if lit_val < min || lit_val > max { @@ -501,7 +501,7 @@ fn lint_uint_literal<'tcx>( match par_e.kind { hir::ExprKind::Cast(..) => { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { - cx.emit_spanned_lint( + cx.emit_span_lint( OVERFLOWING_LITERALS, par_e.span, OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, @@ -528,7 +528,7 @@ fn lint_uint_literal<'tcx>( ); return; } - cx.emit_spanned_lint( + cx.emit_span_lint( OVERFLOWING_LITERALS, e.span, OverflowingUInt { @@ -555,7 +555,7 @@ fn lint_literal<'tcx>( ty::Int(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { - lint_int_literal(cx, type_limits, e, lit, t, v) + lint_int_literal(cx, type_limits, e, lit, t, v.get()) } _ => bug!(), }; @@ -570,7 +570,7 @@ fn lint_literal<'tcx>( _ => bug!(), }; if is_infinite == Ok(true) { - cx.emit_spanned_lint( + cx.emit_span_lint( OVERFLOWING_LITERALS, e.span, OverflowingLiteral { @@ -654,7 +654,7 @@ fn lint_nan<'tcx>( _ => return, }; - cx.emit_spanned_lint(INVALID_NAN_COMPARISONS, e.span, lint); + cx.emit_span_lint(INVALID_NAN_COMPARISONS, e.span, lint); } fn lint_wide_pointer<'tcx>( @@ -700,7 +700,7 @@ fn lint_wide_pointer<'tcx>( let (Some(l_span), Some(r_span)) = (l.span.find_ancestor_inside(e.span), r.span.find_ancestor_inside(e.span)) else { - return cx.emit_spanned_lint( + return cx.emit_span_lint( AMBIGUOUS_WIDE_POINTER_COMPARISONS, e.span, AmbiguousWidePointerComparisons::Spanless, @@ -718,7 +718,7 @@ fn lint_wide_pointer<'tcx>( let deref_left = &*"*".repeat(l_ty_refs); let deref_right = &*"*".repeat(r_ty_refs); - cx.emit_spanned_lint( + cx.emit_span_lint( AMBIGUOUS_WIDE_POINTER_COMPARISONS, e.span, AmbiguousWidePointerComparisons::Spanful { @@ -770,7 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { hir::ExprKind::Binary(binop, ref l, ref r) => { if is_comparison(binop) { if !check_limits(cx, binop, l, r) { - cx.emit_spanned_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons); + cx.emit_span_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons); } else { lint_nan(cx, e, binop, l, r); lint_wide_pointer(cx, e, binop.node, l, r); @@ -842,7 +842,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { ast::LitKind::Int( v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed, - ) => v as i128, + ) => v.get() as i128, _ => return true, }, _ => bug!(), @@ -853,7 +853,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { let (min, max): (u128, u128) = uint_ty_range(uint_ty); let lit_val: u128 = match lit.kind { hir::ExprKind::Lit(li) => match li.node { - ast::LitKind::Int(v, _) => v, + ast::LitKind::Int(v, _) => v.get(), _ => return true, }, _ => bug!(), @@ -1435,6 +1435,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Bound(..) | ty::Error(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Placeholder(..) @@ -1464,7 +1465,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { None }; - self.cx.emit_spanned_lint( + self.cx.emit_span_lint( lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note }, @@ -1792,7 +1793,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { // We only warn if the largest variant is at least thrice as large as // the second-largest. if largest > slargest * 3 && slargest > 0 { - cx.emit_spanned_lint( + cx.emit_span_lint( VARIANT_SIZE_DIFFERENCES, enum_definition.variants[largest_index].span, VariantSizeDifferencesDiag { largest }, @@ -1913,17 +1914,9 @@ impl InvalidAtomicOrdering { && (ordering == invalid_ordering || ordering == sym::AcqRel) { if method == sym::load { - cx.emit_spanned_lint( - INVALID_ATOMIC_ORDERING, - ordering_arg.span, - AtomicOrderingLoad, - ); + cx.emit_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad); } else { - cx.emit_spanned_lint( - INVALID_ATOMIC_ORDERING, - ordering_arg.span, - AtomicOrderingStore, - ); + cx.emit_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore); }; } } @@ -1935,7 +1928,7 @@ impl InvalidAtomicOrdering { && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)) && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) { - cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, args[0].span, AtomicOrderingFence); + cx.emit_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, AtomicOrderingFence); } } @@ -1957,7 +1950,7 @@ impl InvalidAtomicOrdering { let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return }; if matches!(fail_ordering, sym::Release | sym::AcqRel) { - cx.emit_spanned_lint( + cx.emit_span_lint( INVALID_ATOMIC_ORDERING, fail_order_arg.span, InvalidAtomicOrderingDiag { method, fail_order_arg_span: fail_order_arg.span }, diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs index c80889f3ae752..b74430d8fa09c 100644 --- a/compiler/rustc_lint/src/unit_bindings.rs +++ b/compiler/rustc_lint/src/unit_bindings.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitBindings { && !matches!(init.kind, hir::ExprKind::Tup([])) && !matches!(local.pat.kind, hir::PatKind::Tuple([], ..)) { - cx.emit_spanned_lint( + cx.emit_span_lint( UNIT_BINDINGS, local.span, UnitBindingsDiag { label: local.pat.span }, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 39decf1faabf1..9f670893b270d 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -182,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { - cx.emit_spanned_lint( + cx.emit_span_lint( UNUSED_MUST_USE, expr.span, UnusedOp { @@ -202,7 +202,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) { - cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); + cx.emit_span_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); } fn check_fn_must_use( @@ -355,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { Some(len) => is_ty_must_use(cx, ty, expr, span) .map(|inner| MustUsePath::Array(Box::new(inner), len)), }, - ty::Closure(..) => Some(MustUsePath::Closure(span)), + ty::Closure(..) | ty::CoroutineClosure(..) => Some(MustUsePath::Closure(span)), ty::Coroutine(def_id, ..) => { // async fn should be treated as "implementor of `Future`" let must_use = if cx.tcx.coroutine_is_async(def_id) { @@ -494,21 +494,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Closure(span) => { - cx.emit_spanned_lint( + cx.emit_span_lint( UNUSED_MUST_USE, *span, UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Coroutine(span) => { - cx.emit_spanned_lint( + cx.emit_span_lint( UNUSED_MUST_USE, *span, UnusedCoroutine { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Def(span, def_id, reason) => { - cx.emit_spanned_lint( + cx.emit_span_lint( UNUSED_MUST_USE, *span, UnusedDef { @@ -568,9 +568,9 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { } else { PathStatementDropSub::Help { span: s.span } }; - cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub }) + cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub }) } else { - cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect); + cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect); } } } @@ -824,7 +824,7 @@ trait UnusedDelimLint { end_replace: hi_replace, } }); - cx.emit_spanned_lint( + cx.emit_span_lint( self.lint(), primary_span, UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion }, @@ -1507,7 +1507,7 @@ impl UnusedImportBraces { ast::UseTreeKind::Nested(_) => return, }; - cx.emit_spanned_lint( + cx.emit_span_lint( UNUSED_IMPORT_BRACES, item.span, UnusedImportBracesDiag { node: node_name }, @@ -1564,10 +1564,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { match m { adjustment::AutoBorrowMutability::Not => { - cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag); + cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag); } adjustment::AutoBorrowMutability::Mut { .. } => { - cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag); + cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag); } }; } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e917e7cb02b39..6a2a2c1e48e2a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3,6 +3,9 @@ //! These are the built-in lints that are emitted direct in the main //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. +//! +//! When removing a lint, make sure to also add a call to `register_removed` in +//! compiler/rustc_lint/src/lib.rs. use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason}; use rustc_span::edition::Edition; @@ -45,7 +48,6 @@ declare_lint_pass! { FUZZY_PROVENANCE_CASTS, HIDDEN_GLOB_REEXPORTS, ILL_FORMED_ATTRIBUTE_INPUT, - ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, INCOMPLETE_INCLUDE, INDIRECT_STRUCTURAL_MATCH, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, @@ -67,7 +69,6 @@ declare_lint_pass! { MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, NON_EXHAUSTIVE_OMITTED_PATTERNS, - NONTRIVIAL_STRUCTURAL_MATCH, ORDER_DEPENDENT_TRAIT_OBJECTS, OVERLAPPING_RANGE_ENDPOINTS, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -1873,55 +1874,6 @@ declare_lint! { }; } -declare_lint! { - /// The `illegal_floating_point_literal_pattern` lint detects - /// floating-point literals used in patterns. - /// - /// ### Example - /// - /// ```rust - /// let x = 42.0; - /// - /// match x { - /// 5.0 => {} - /// _ => {} - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Previous versions of the compiler accepted floating-point literals in - /// patterns, but it was later determined this was a mistake. The - /// semantics of comparing floating-point values may not be clear in a - /// pattern when contrasted with "structural equality". Typically you can - /// work around this by using a [match guard], such as: - /// - /// ```rust - /// # let x = 42.0; - /// - /// match x { - /// y if y == 5.0 => {} - /// _ => {} - /// } - /// ``` - /// - /// This is a [future-incompatible] lint to transition this to a hard - /// error in the future. See [issue #41620] for more details. - /// - /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620 - /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - Warn, - "floating-point literals cannot be used in patterns", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #41620 ", - }; -} - declare_lint! { /// The `unstable_name_collisions` lint detects that you have used a name /// that the standard library plans to add in the future. @@ -2330,8 +2282,8 @@ declare_lint! { Warn, "constant used in pattern contains value of non-structural-match type in a field or a variant", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #62411 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #120362 ", }; } @@ -2386,47 +2338,8 @@ declare_lint! { Warn, "pointers are not structural-match", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #62411 ", - }; -} - -declare_lint! { - /// The `nontrivial_structural_match` lint detects constants that are used in patterns, - /// whose type is not structural-match and whose initializer body actually uses values - /// that are not structural-match. So `Option` is ok if the constant - /// is just `None`. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(nontrivial_structural_match)] - /// - /// #[derive(Copy, Clone, Debug)] - /// struct NoDerive(u32); - /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } - /// impl Eq for NoDerive { } - /// fn main() { - /// const INDEX: Option = [None, Some(NoDerive(10))][0]; - /// match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Previous versions of Rust accepted constants in patterns, even if those constants' types - /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of - /// `PartialEq`, which can report that two constants are not equal even if they are - /// bit-equivalent. - pub NONTRIVIAL_STRUCTURAL_MATCH, - Warn, - "constant used in pattern of non-structural-match type and the constant's initializer \ - expression contains values of non-structural-match types", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #73448 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #120362 ", }; } @@ -2755,6 +2668,11 @@ declare_lint! { pub UNSAFE_OP_IN_UNSAFE_FN, Allow, "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #71668 ", + explain_reason: false + }; @edition Edition2024 => Warn; } @@ -4604,3 +4522,50 @@ declare_lint! { reference: "issue #X ", }; } + +declare_lint! { + /// The `private_macro_use` lint detects private macros that are imported + /// with `#[macro_use]`. + /// + /// ### Example + /// + /// ```rust,ignore (needs extern crate) + /// // extern_macro.rs + /// macro_rules! foo_ { () => {}; } + /// use foo_ as foo; + /// + /// // code.rs + /// + /// #![deny(private_macro_use)] + /// + /// #[macro_use] + /// extern crate extern_macro; + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: cannot find macro `foo` in this scope + /// ``` + /// + /// ### Explanation + /// + /// This lint arises from overlooking visibility checks for macros + /// in an external crate. + /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PRIVATE_MACRO_USE, + Warn, + "detects certain macro bindings that should not be re-exported", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #120192 ", + }; +} diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 5bfffc5d9117b..6d578c97f3fe1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -76,7 +76,6 @@ enum LLVMRustAttribute { SanitizeMemory = 22, NonLazyBind = 23, OptimizeNone = 24, - ReturnsTwice = 25, ReadNone = 26, SanitizeHWAddress = 28, WillReturn = 29, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 6114f7c867807..3b6bf03686b0d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -934,10 +934,8 @@ LLVMRustOptimize( } else { for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); - if (OptStage != LLVMRustOptStage::PreLinkThinLTO) { - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); - } + for (const auto &C : OptimizerLastEPCallbacks) + PB.registerOptimizerLastEPCallback(C); switch (OptStage) { case LLVMRustOptStage::PreLinkNoLTO: @@ -945,14 +943,7 @@ LLVMRustOptimize( break; case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel); - // The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback - // passes may still run afterwards. This means we need to run the buffer passes again. - // FIXME: In LLVM 13, the ThinLTOPreLink pipeline also runs OptimizerLastEPCallbacks - // before the RequiredLTOPreLinkPasses, in which case we can remove these hacks. - if (OptimizerLastEPCallbacks.empty()) - NeedThinLTOBufferPasses = false; - for (const auto &C : OptimizerLastEPCallbacks) - C(MPM, OptLevel); + NeedThinLTOBufferPasses = false; break; case LLVMRustOptStage::PreLinkFatLTO: MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 0df7b7eed11f9..a2dfebec59441 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -250,8 +250,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::NonLazyBind; case OptimizeNone: return Attribute::OptimizeNone; - case ReturnsTwice: - return Attribute::ReturnsTwice; case ReadNone: return Attribute::ReadNone; case SanitizeHWAddress: diff --git a/compiler/rustc_macros/build.rs b/compiler/rustc_macros/build.rs new file mode 100644 index 0000000000000..717f8a922457d --- /dev/null +++ b/compiler/rustc_macros/build.rs @@ -0,0 +1,16 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); + if !std::env::var("RUSTC_BOOTSTRAP").is_ok() { + eprintln!( + "error: you are attempting to build the compiler without going through bootstrap" + ); + eprintln!( + "help: see https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html for how to build the compiler" + ); + eprintln!( + "help: if you know what you're doing, set the RUSTC_BOOTSTRAP environment variable to any value" + ); + panic!("wrong command used for building"); + } +} diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 0b7ecff8148b3..85bb9584a0575 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -209,9 +209,9 @@ impl DiagnosticDeriveVariantBuilder { if path.is_ident("code") { self.code.set_once((), path.span().unwrap()); - let code = nested.parse::()?; + let code = nested.parse::()?; tokens.extend(quote! { - diag.code(#code.to_string()); + diag.code(#code); }); } else { span_err(path.span().unwrap(), "unknown argument") diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index d3a4e7ba7d191..33dffe6998a1e 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -20,7 +20,7 @@ use synstructure::Structure; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(Diagnostic)] -/// #[diag(borrowck_move_out_of_borrow, code = "E0505")] +/// #[diag(borrowck_move_out_of_borrow, code = E0505)] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, @@ -90,7 +90,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// Then, later, to emit the error: /// /// ```ignore (rust) -/// cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint { +/// cx.span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint { /// method, /// success_ordering, /// fail_ordering, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index f5d942b924e6c..9e85a59b5b92b 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -9,7 +9,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] -#![recursion_limit = "128"] use synstructure::decl_derive; diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index ad1980136f3b9..25675e06e38d6 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -120,7 +120,8 @@ struct QueryModifiers { /// Forward the result on ensure if the query gets recomputed, and /// return `Ok(())` otherwise. Only applicable to queries returning - /// `Result<(), ErrorGuaranteed>` + /// `Result`. The `T` is not returned from `ensure` + /// invocations. ensure_forwards_result_if_red: Option, } diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 08cc8173eb049..79d3482472a81 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -libloading = "0.7.1" +libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 27c26d3178144..d17bf0cf708f6 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -4,7 +4,7 @@ use std::{ }; use rustc_errors::{ - error_code, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, + codes::*, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::Diagnostic; use rustc_session::config; @@ -122,7 +122,7 @@ pub struct WasmImportForm { } #[derive(Diagnostic)] -#[diag(metadata_empty_link_name, code = "E0454")] +#[diag(metadata_empty_link_name, code = E0454)] pub struct EmptyLinkName { #[primary_span] #[label] @@ -130,21 +130,21 @@ pub struct EmptyLinkName { } #[derive(Diagnostic)] -#[diag(metadata_link_framework_apple, code = "E0455")] +#[diag(metadata_link_framework_apple, code = E0455)] pub struct LinkFrameworkApple { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata_framework_only_windows, code = "E0455")] +#[diag(metadata_framework_only_windows, code = E0455)] pub struct FrameworkOnlyWindows { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata_unknown_link_kind, code = "E0458")] +#[diag(metadata_unknown_link_kind, code = E0458)] pub struct UnknownLinkKind<'a> { #[primary_span] #[label] @@ -239,7 +239,7 @@ pub struct IncompatibleWasmLink { } #[derive(Diagnostic)] -#[diag(metadata_link_requires_name, code = "E0459")] +#[diag(metadata_link_requires_name, code = E0459)] pub struct LinkRequiresName { #[primary_span] #[label] @@ -502,7 +502,7 @@ impl IntoDiagnostic<'_, G> for MultipleCandidates { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_multiple_candidates); diag.arg("crate_name", self.crate_name); diag.arg("flavor", self.flavor); - diag.code(error_code!(E0464)); + diag.code(E0464); diag.span(self.span); for (i, candidate) in self.candidates.iter().enumerate() { diag.note(format!("candidate #{}: {}", i + 1, candidate.display())); @@ -512,7 +512,7 @@ impl IntoDiagnostic<'_, G> for MultipleCandidates { } #[derive(Diagnostic)] -#[diag(metadata_symbol_conflicts_current, code = "E0519")] +#[diag(metadata_symbol_conflicts_current, code = E0519)] pub struct SymbolConflictsCurrent { #[primary_span] pub span: Span, @@ -537,7 +537,7 @@ pub struct DlError { } #[derive(Diagnostic)] -#[diag(metadata_newer_crate_version, code = "E0460")] +#[diag(metadata_newer_crate_version, code = E0460)] #[note] #[note(metadata_found_crate_versions)] pub struct NewerCrateVersion { @@ -549,7 +549,7 @@ pub struct NewerCrateVersion { } #[derive(Diagnostic)] -#[diag(metadata_no_crate_with_triple, code = "E0461")] +#[diag(metadata_no_crate_with_triple, code = E0461)] #[note(metadata_found_crate_versions)] pub struct NoCrateWithTriple<'a> { #[primary_span] @@ -561,7 +561,7 @@ pub struct NoCrateWithTriple<'a> { } #[derive(Diagnostic)] -#[diag(metadata_found_staticlib, code = "E0462")] +#[diag(metadata_found_staticlib, code = E0462)] #[note(metadata_found_crate_versions)] #[help] pub struct FoundStaticlib { @@ -573,7 +573,7 @@ pub struct FoundStaticlib { } #[derive(Diagnostic)] -#[diag(metadata_incompatible_rustc, code = "E0514")] +#[diag(metadata_incompatible_rustc, code = E0514)] #[note(metadata_found_crate_versions)] #[help] pub struct IncompatibleRustc { @@ -598,7 +598,7 @@ impl IntoDiagnostic<'_, G> for InvalidMetadataFiles { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_invalid_meta_files); diag.arg("crate_name", self.crate_name); diag.arg("add_info", self.add_info); - diag.code(error_code!(E0786)); + diag.code(E0786); diag.span(self.span); for crate_rejection in self.crate_rejections { diag.note(crate_rejection); @@ -627,7 +627,7 @@ impl IntoDiagnostic<'_, G> for CannotFindCrate { diag.arg("current_crate", self.current_crate); diag.arg("add_info", self.add_info); diag.arg("locator_triple", self.locator_triple.triple()); - diag.code(error_code!(E0463)); + diag.code(E0463); diag.span(self.span); if (self.crate_name == sym::std || self.crate_name == sym::core) && self.locator_triple != TargetTriple::from_triple(config::host_triple()) diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 6c6c60af063fb..471425e80174f 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -11,11 +11,9 @@ #![feature(proc_macro_internals)] #![feature(macro_metavar_expr)] #![feature(min_specialization)] -#![feature(slice_as_chunks)] #![feature(trusted_len)] #![feature(try_blocks)] #![feature(never_type)] -#![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2376d95334155..1ab965e28769f 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -291,7 +291,7 @@ impl fmt::Display for CrateFlavor { } impl IntoDiagnosticArg for CrateFlavor { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { match self { CrateFlavor::Rlib => DiagnosticArgValue::Str(Cow::Borrowed("rlib")), CrateFlavor::Rmeta => DiagnosticArgValue::Str(Cow::Borrowed("rmeta")), diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c3d6c21c4027d..0b352a02b64c7 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -236,7 +236,14 @@ provide! { tcx, def_id, other, cdata, impl_polarity => { table_direct } defaultness => { table_direct } constness => { table_direct } - coerce_unsized_info => { table } + coerce_unsized_info => { + Ok(cdata + .root + .tables + .coerce_unsized_info + .get(cdata, def_id.index) + .map(|lazy| lazy.decode((cdata, tcx))) + .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) } mir_const_qualif => { table } rendered_const => { table } asyncness => { table_direct } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2d4e49e27d9b9..85631bd8edbfa 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -386,7 +386,7 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { } } -// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would +// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy($value))`, which would // normally need extra variables to avoid errors about multiple mutable borrows. macro_rules! record { ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ @@ -398,7 +398,7 @@ macro_rules! record { }}; } -// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would +// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_array($value))`, which would // normally need extra variables to avoid errors about multiple mutable borrows. macro_rules! record_array { ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ @@ -1994,7 +1994,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // if this is an impl of `CoerceUnsized`, create its // "unsized info", else just store None if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() { - let coerce_unsized_info = tcx.coerce_unsized_info(def_id); + let coerce_unsized_info = tcx.coerce_unsized_info(def_id).unwrap(); record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index e745913fabc37..c648b2bfe9b90 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -94,7 +94,7 @@ macro_rules! arena_types { // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena - // (during lowering) and the `librustc_middle` arena (for decoding MIR) + // (during lowering) and the `rustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet, [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 3c5536570872a..3ebbcd650302f 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,14 +1,13 @@ -use std::borrow::Cow; use std::fmt; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage}; +use rustc_errors::{codes::*, DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage}; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use crate::ty::Ty; #[derive(Diagnostic)] -#[diag(middle_drop_check_overflow, code = "E0320")] +#[diag(middle_drop_check_overflow, code = E0320)] #[note] pub struct DropCheckOverflow<'tcx> { #[primary_span] @@ -95,17 +94,14 @@ pub(super) struct ConstNotUsedTraitAlias { pub struct CustomSubdiagnostic<'a> { pub msg: fn() -> DiagnosticMessage, - pub add_args: - Box, DiagnosticArgValue<'static>)) + 'a>, + pub add_args: Box, } impl<'a> CustomSubdiagnostic<'a> { pub fn label(x: fn() -> DiagnosticMessage) -> Self { Self::label_and_then(x, |_| {}) } - pub fn label_and_then< - F: FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>)) + 'a, - >( + pub fn label_and_then( msg: fn() -> DiagnosticMessage, f: F, ) -> Self { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 949b786e3a7d2..ba1ae46626b22 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -107,9 +107,8 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { fn next(&mut self) -> Option { if self.current_id.local_id.index() != 0 { self.current_id.local_id = ItemLocalId::new(0); - if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) { - return Some((self.current_id.owner, node)); - } + let node = self.map.tcx.hir_owner_node(self.current_id.owner); + return Some((self.current_id.owner, node)); } if self.current_id == CRATE_HIR_ID { return None; @@ -125,22 +124,42 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { self.current_id = HirId::make_owner(parent_id.def_id); // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. - if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) { - return Some((self.current_id.owner, node)); - } + let node = self.map.tcx.hir_owner_node(self.current_id.owner); + return Some((self.current_id.owner, node)); } } } impl<'tcx> TyCtxt<'tcx> { #[inline] - fn hir_owner(self, owner: OwnerId) -> Option> { - Some(self.hir_owner_nodes(owner).as_owner()?.node()) + fn expect_hir_owner_nodes(self, def_id: LocalDefId) -> &'tcx OwnerNodes<'tcx> { + self.opt_hir_owner_nodes(def_id) + .unwrap_or_else(|| span_bug!(self.def_span(def_id), "{def_id:?} is not an owner")) + } + + #[inline] + pub fn hir_owner_nodes(self, owner_id: OwnerId) -> &'tcx OwnerNodes<'tcx> { + self.expect_hir_owner_nodes(owner_id.def_id) + } + + #[inline] + fn opt_hir_owner_node(self, def_id: LocalDefId) -> Option> { + self.opt_hir_owner_nodes(def_id).map(|nodes| nodes.node()) + } + + #[inline] + pub fn expect_hir_owner_node(self, def_id: LocalDefId) -> OwnerNode<'tcx> { + self.expect_hir_owner_nodes(def_id).node() + } + + #[inline] + pub fn hir_owner_node(self, owner_id: OwnerId) -> OwnerNode<'tcx> { + self.hir_owner_nodes(owner_id).node() } /// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found. pub fn opt_hir_node(self, id: HirId) -> Option> { - let owner = self.hir_owner_nodes(id.owner).as_owner()?; + let owner = self.hir_owner_nodes(id.owner); let node = owner.nodes[id.local_id].as_ref()?; Some(node.node) } @@ -174,8 +193,8 @@ impl<'hir> Map<'hir> { #[inline] pub fn root_module(self) -> &'hir Mod<'hir> { - match self.tcx.hir_owner(CRATE_OWNER_ID) { - Some(OwnerNode::Crate(item)) => item, + match self.tcx.hir_owner_node(CRATE_OWNER_ID) { + OwnerNode::Crate(item) => item, _ => bug!(), } } @@ -213,7 +232,7 @@ impl<'hir> Map<'hir> { if id.local_id == ItemLocalId::from_u32(0) { Some(self.tcx.hir_owner_parent(id.owner)) } else { - let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?; + let owner = self.tcx.hir_owner_nodes(id.owner); let node = owner.nodes[id.local_id].as_ref()?; let hir_id = HirId { owner: id.owner, local_id: node.parent }; // HIR indexing should have checked that. @@ -241,32 +260,27 @@ impl<'hir> Map<'hir> { } pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> { - let node = self.tcx.hir_owner(OwnerId { def_id: id })?; - node.generics() - } - - pub fn owner(self, id: OwnerId) -> OwnerNode<'hir> { - self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)) + self.tcx.opt_hir_owner_node(id)?.generics() } pub fn item(self, id: ItemId) -> &'hir Item<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().expect_item() + self.tcx.hir_owner_node(id.owner_id).expect_item() } pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().expect_trait_item() + self.tcx.hir_owner_node(id.owner_id).expect_trait_item() } pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().expect_impl_item() + self.tcx.hir_owner_node(id.owner_id).expect_impl_item() } pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().expect_foreign_item() + self.tcx.hir_owner_node(id.owner_id).expect_foreign_item() } pub fn body(self, id: BodyId) -> &'hir Body<'hir> { - self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id] + self.tcx.hir_owner_nodes(id.hir_id.owner).bodies[&id.hir_id.local_id] } #[track_caller] @@ -436,9 +450,9 @@ impl<'hir> Map<'hir> { pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) { let hir_id = HirId::make_owner(module.to_local_def_id()); - match self.tcx.hir_owner(hir_id.owner) { - Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. })) => (m, span, hir_id), - Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id), + match self.tcx.hir_owner_node(hir_id.owner) { + OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. }) => (m, span, hir_id), + OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id), node => panic!("not a module: {node:?}"), } } @@ -726,8 +740,8 @@ impl<'hir> Map<'hir> { pub fn get_foreign_abi(self, hir_id: HirId) -> Abi { let parent = self.get_parent_item(hir_id); - if let Some(node) = self.tcx.hir_owner(parent) - && let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node + if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = + self.tcx.hir_owner_node(parent) { return *abi; } @@ -737,38 +751,29 @@ impl<'hir> Map<'hir> { ) } - pub fn expect_owner(self, def_id: LocalDefId) -> OwnerNode<'hir> { - self.tcx - .hir_owner(OwnerId { def_id }) - .unwrap_or_else(|| bug!("expected owner for {:?}", def_id)) - } - pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> { - match self.tcx.hir_owner(OwnerId { def_id: id }) { - Some(OwnerNode::Item(item)) => item, + match self.tcx.expect_hir_owner_node(id) { + OwnerNode::Item(item) => item, _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))), } } pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> { - match self.tcx.hir_owner(OwnerId { def_id: id }) { - Some(OwnerNode::ImplItem(item)) => item, + match self.tcx.expect_hir_owner_node(id) { + OwnerNode::ImplItem(item) => item, _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))), } } pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> { - match self.tcx.hir_owner(OwnerId { def_id: id }) { - Some(OwnerNode::TraitItem(item)) => item, + match self.tcx.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>> { - match self.tcx.hir_owner(OwnerId { def_id }) { - Some(node) => node.fn_decl().map(|fn_decl| &fn_decl.output), - _ => None, - } + Some(&self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.output) } pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> { @@ -779,8 +784,8 @@ impl<'hir> Map<'hir> { } pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> { - match self.tcx.hir_owner(id) { - Some(OwnerNode::ForeignItem(item)) => item, + match self.tcx.hir_owner_node(id) { + OwnerNode::ForeignItem(item) => item, _ => { bug!( "expected foreign item, found {}", diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 2d4d5deaefa93..94191df30a5e6 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -127,21 +127,15 @@ pub fn provide(providers: &mut Providers) { providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; - providers.opt_local_def_id_to_hir_id = |tcx, id| { - let owner = tcx.hir_crate(()).owners[id].map(|_| ()); - Some(match owner { - MaybeOwner::Owner(_) => HirId::make_owner(id), - MaybeOwner::Phantom => bug!("No HirId for {:?}", id), + providers.opt_local_def_id_to_hir_id = |tcx, def_id| { + Some(match tcx.hir_crate(()).owners[def_id] { + MaybeOwner::Owner(_) => HirId::make_owner(def_id), MaybeOwner::NonOwner(hir_id) => hir_id, + MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id), }) }; - providers.hir_owner_nodes = |tcx, id| { - if let Some(i) = tcx.hir_crate(()).owners.get(id.def_id) { - i.map(|i| &i.nodes) - } else { - MaybeOwner::Phantom - } - }; + providers.opt_hir_owner_nodes = + |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash. tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| { diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index c35799ef47f2b..63c0ebd5f6b79 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -194,33 +194,37 @@ impl<'tcx> UnifyValue for ConstVariableValue<'tcx> { /// values for the effect inference variable #[derive(Clone, Copy, Debug)] pub enum EffectVarValue<'tcx> { - /// The host effect is on, enabling access to syscalls, filesystem access, etc. - Host, - /// The host effect is off. Execution is restricted to const operations only. - NoHost, - Const(ty::Const<'tcx>), + Unknown, + Known(ty::Const<'tcx>), } impl<'tcx> EffectVarValue<'tcx> { - pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> { + pub fn known(self) -> Option> { match self { - EffectVarValue::Host => tcx.consts.true_, - EffectVarValue::NoHost => tcx.consts.false_, - EffectVarValue::Const(c) => c, + EffectVarValue::Unknown => None, + EffectVarValue::Known(value) => Some(value), + } + } + + pub fn is_unknown(self) -> bool { + match self { + EffectVarValue::Unknown => true, + EffectVarValue::Known(_) => false, } } } impl<'tcx> UnifyValue for EffectVarValue<'tcx> { - type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>); + type Error = NoError; fn unify_values(value1: &Self, value2: &Self) -> Result { - match (value1, value2) { - (EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host), - (EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost), - (EffectVarValue::NoHost | EffectVarValue::Host, _) - | (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)), - (EffectVarValue::Const(_), EffectVarValue::Const(_)) => { - bug!("equating two const variables, both of which have known values") + match (*value1, *value2) { + (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown), + (EffectVarValue::Unknown, EffectVarValue::Known(val)) + | (EffectVarValue::Known(val), EffectVarValue::Unknown) => { + Ok(EffectVarValue::Known(val)) + } + (EffectVarValue::Known(_), EffectVarValue::Known(_)) => { + bug!("equating known inference variables: {value1:?} {value2:?}") } } } @@ -229,7 +233,7 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> { #[derive(PartialEq, Copy, Clone, Debug)] pub struct EffectVidKey<'tcx> { pub vid: ty::EffectVid, - pub phantom: PhantomData>, + pub phantom: PhantomData>, } impl<'tcx> From for EffectVidKey<'tcx> { @@ -239,7 +243,7 @@ impl<'tcx> From for EffectVidKey<'tcx> { } impl<'tcx> UnifyKey for EffectVidKey<'tcx> { - type Value = Option>; + type Value = EffectVarValue<'tcx>; #[inline] fn index(&self) -> u32 { self.vid.as_u32() diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 3475e582a8f22..ddfb2ece39f10 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -33,7 +33,6 @@ #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(coroutines)] -#![feature(get_mut_unchecked)] #![feature(if_let_guard)] #![feature(inline_const)] #![feature(iter_from_coroutine)] @@ -49,19 +48,15 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] -#![feature(trusted_step)] +#![cfg_attr(not(bootstrap), feature(trait_upcasting))] #![feature(try_blocks)] -#![feature(try_reserve_kind)] -#![feature(nonzero_ops)] #![feature(decl_macro)] #![feature(extract_if)] #![feature(intra_doc_pointers)] #![feature(yeet_expr)] #![feature(const_option)] -#![feature(trait_alias)] #![feature(ptr_alignment_type)] #![feature(macro_metavar_expr)] -#![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] #![allow(internal_features)] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 4ab16cf19ba93..6ffa0819f3571 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -247,18 +247,18 @@ pub fn explain_lint_level_source( /// /// If you are looking to implement a lint, look for higher level functions, /// for example: -/// - [`TyCtxt::emit_spanned_lint`] -/// - [`TyCtxt::struct_span_lint_hir`] -/// - [`TyCtxt::emit_lint`] -/// - [`TyCtxt::struct_lint_node`] -/// - `LintContext::lookup` +/// - [`TyCtxt::emit_node_span_lint`] +/// - [`TyCtxt::node_span_lint`] +/// - [`TyCtxt::emit_node_lint`] +/// - [`TyCtxt::node_lint`] +/// - `LintContext::opt_span_lint` /// /// ## `decorate` /// /// It is not intended to call `emit`/`cancel` on the `DiagnosticBuilder` passed /// in the `decorate` callback. #[track_caller] -pub fn struct_lint_level( +pub fn lint_level( sess: &Session, lint: &'static Lint, level: Level, @@ -270,7 +270,7 @@ pub fn struct_lint_level( // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to // the "real" work. #[track_caller] - fn struct_lint_level_impl( + fn lint_level_impl( sess: &Session, lint: &'static Lint, level: Level, @@ -399,7 +399,7 @@ pub fn struct_lint_level( explain_lint_level_source(lint, level, src, &mut *err); err.emit() } - struct_lint_level_impl(sess, lint, level, src, span, msg, Box::new(decorate)) + lint_level_impl(sess, lint, level, src, span, msg, Box::new(decorate)) } /// Returns whether `span` originates in a foreign crate's external macro. diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index e11c9371118cb..7d6d39a2a8a39 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -74,35 +74,32 @@ bitflags! { /// `#[used]`: indicates that LLVM can't eliminate this function (but the /// linker can!). const USED = 1 << 9; - /// `#[ffi_returns_twice]`, indicates that an extern function can return - /// multiple times - const FFI_RETURNS_TWICE = 1 << 10; /// `#[track_caller]`: allow access to the caller location - const TRACK_CALLER = 1 << 11; + const TRACK_CALLER = 1 << 10; /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function /// declaration. - const FFI_PURE = 1 << 12; + const FFI_PURE = 1 << 11; /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. - const FFI_CONST = 1 << 13; + const FFI_CONST = 1 << 12; /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a /// function as an entry function from Non-Secure code. - const CMSE_NONSECURE_ENTRY = 1 << 14; + const CMSE_NONSECURE_ENTRY = 1 << 13; /// `#[coverage(off)]`: indicates that the function should be ignored by /// the MIR `InstrumentCoverage` pass and not added to the coverage map /// during codegen. - const NO_COVERAGE = 1 << 15; + const NO_COVERAGE = 1 << 14; /// `#[used(linker)]`: /// indicates that neither LLVM nor the linker will eliminate this function. - const USED_LINKER = 1 << 16; + const USED_LINKER = 1 << 15; /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory. - const DEALLOCATOR = 1 << 17; + const DEALLOCATOR = 1 << 16; /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory. - const REALLOCATOR = 1 << 18; + const REALLOCATOR = 1 << 17; /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory. - const ALLOCATOR_ZEROED = 1 << 19; + const ALLOCATOR_ZEROED = 1 << 18; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. - const NO_BUILTINS = 1 << 20; + const NO_BUILTINS = 1 << 19; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index f92c72c8a588c..a4e193ba2c942 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Given a [`DefId`] of a [`Fn`], [`FnMut`] or [`FnOnce`] traits, + /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option { @@ -36,6 +36,19 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Given a [`DefId`] of one of the `AsyncFn`, `AsyncFnMut` or `AsyncFnOnce` traits, + /// returns a corresponding [`ty::ClosureKind`]. + /// For any other [`DefId`] return `None`. + pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option { + let items = self.lang_items(); + match Some(id) { + x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn), + x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut), + x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce), + _ => None, + } + } + /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family /// trait, if it is defined. pub fn fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option { diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 5d6a7f75df843..b9914f6cb7a00 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -221,9 +221,6 @@ pub struct ScopeTree { /// variable is declared. var_map: FxIndexMap, - /// Maps from a `NodeId` to the associated destruction scope (if any). - destruction_scopes: FxIndexMap, - /// Identifies expressions which, if captured into a temporary, ought to /// have a temporary whose lifetime extends to the end of the enclosing *block*, /// and not the enclosing *statement*. Expressions that are not present in this @@ -336,11 +333,6 @@ impl ScopeTree { let prev = self.parent_map.insert(child, p); assert!(prev.is_none()); } - - // Record the destruction scopes for later so we can query them. - if let ScopeData::Destruction = child.data { - self.destruction_scopes.insert(child.item_local_id(), child); - } } pub fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index efe7bdfa06db1..afb6937b43b94 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -217,7 +217,7 @@ fn late_report_deprecation( return; } let method_span = method_span.unwrap_or(span); - tcx.struct_span_lint_hir(lint, hir_id, method_span, message, |diag| { + tcx.node_span_lint(lint, hir_id, method_span, message, |diag| { if let hir::Node::Expr(_) = tcx.hir_node(hir_id) { let kind = tcx.def_descr(def_id); deprecation_suggestion(diag, kind, suggestion, method_span); @@ -585,7 +585,7 @@ impl<'tcx> TyCtxt<'tcx> { unmarked: impl FnOnce(Span, DefId), ) -> bool { let soft_handler = |lint, span, msg: String| { - self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |_| {}) + self.node_span_lint(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |_| {}) }; let eval_result = self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable); diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 2c38f998c9590..9731d86fb17c2 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -195,7 +195,7 @@ impl<'tcx> ConstValue<'tcx> { /// Constants #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] -#[derive(TypeFoldable, TypeVisitable)] +#[derive(TypeFoldable, TypeVisitable, Lift)] pub enum Const<'tcx> { /// This constant came from the type system. /// @@ -456,7 +456,7 @@ impl<'tcx> Const<'tcx> { /// An unevaluated (potentially generic) constant used in MIR. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Hash, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, pub args: GenericArgsRef<'tcx>, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 1b4e9c286351a..0f69ab93452f7 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -5,7 +5,9 @@ use crate::mir::{ConstAlloc, ConstValue}; use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; use rustc_data_structures::sync::Lock; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; +use rustc_errors::{ + DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, +}; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; @@ -200,8 +202,6 @@ pub enum InvalidProgramInfo<'tcx> { /// (which unfortunately typeck does not reject). /// Not using `FnAbiError` as that contains a nested `LayoutError`. FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), - /// We are runnning into a nonsense situation due to ConstProp violating our invariants. - ConstPropNonsense, } /// Details of why a pointer had to be in-bounds. @@ -235,7 +235,7 @@ pub enum InvalidMetaKind { } impl IntoDiagnosticArg for InvalidMetaKind { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Borrowed(match self { InvalidMetaKind::SliceTooBig => "slice_too_big", InvalidMetaKind::TooBig => "too_big", @@ -269,7 +269,7 @@ pub struct Misalignment { macro_rules! impl_into_diagnostic_arg_through_debug { ($($ty:ty),*$(,)?) => {$( impl IntoDiagnosticArg for $ty { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Owned(format!("{self:?}"))) } } @@ -369,7 +369,7 @@ pub enum PointerKind { } impl IntoDiagnosticArg for PointerKind { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str( match self { Self::Ref => "ref", @@ -416,14 +416,14 @@ pub enum ValidationErrorKind<'tcx> { PartialPointer, PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, PtrToStatic { ptr_kind: PointerKind }, - PtrToMut { ptr_kind: PointerKind }, MutableRefInConst, + MutableRefToImmutable, + UnsafeCellInImmutable, NullFnPtr, NeverVal, NullablePtrOutOfRange { range: WrappingRange, max_value: u128 }, PtrOutOfRange { range: WrappingRange, max_value: u128 }, OutOfRange { value: String, range: WrappingRange, max_value: u128 }, - UnsafeCell, UninhabitedVal { ty: Ty<'tcx> }, InvalidEnumTag { value: String }, UninhabitedEnumVariant, @@ -487,10 +487,7 @@ pub trait MachineStopType: Any + fmt::Debug + Send { fn diagnostic_message(&self) -> DiagnosticMessage; /// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to /// fluent for formatting the translated diagnostic message. - fn add_args( - self: Box, - adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>), - ); + fn add_args(self: Box, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)); } impl dyn MachineStopType { diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 6893387736a5a..dabf6297aa9c8 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -277,6 +277,12 @@ impl From for Pointer { Pointer::new(alloc_id.into(), Size::ZERO) } } +impl From for Pointer { + #[inline(always)] + fn from(prov: CtfeProvenance) -> Self { + Pointer::new(prov, Size::ZERO) + } +} impl From> for Pointer> { #[inline(always)] diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 092b59deeff36..5f9e7f6e36854 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -108,7 +108,7 @@ impl<'tcx> TyCtxt<'tcx> { let mir_body = self.mir_for_ctfe(instance.def_id()); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; - self.struct_span_lint_hir( + self.node_span_lint( lint::builtin::CONST_EVALUATABLE_UNCHECKED, self.local_def_id_to_hir_id(local_def_id), self.def_span(ct.def), @@ -145,7 +145,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(param_env.and(cid)); + let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid)); if let Some(span) = span { // The query doesn't know where it is being invoked, so we need to fix the span. self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span)) @@ -164,7 +164,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> EvalToValTreeResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(param_env.and(cid)); + let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid)); debug!(?inputs); if let Some(span) = span { // The query doesn't know where it is being invoked, so we need to fix the span. diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 5ecff04f3ae35..e937c17c8acec 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -418,8 +418,8 @@ impl<'tcx, Prov: Provenance> Scalar { #[inline] pub fn to_float(self) -> InterpResult<'tcx, F> { - // Going through `to_uint` to check size and truncation. - Ok(F::from_bits(self.to_uint(Size::from_bits(F::BITS))?)) + // Going through `to_bits` to check size and truncation. + Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?)) } #[inline] diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 36f5ba161d5f1..9475b89aa15c2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -14,7 +14,9 @@ use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, GenericArgsRef}; use rustc_data_structures::captures::Captures; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; +use rustc_errors::{ + DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, +}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind}; @@ -244,18 +246,42 @@ impl<'tcx> MirSource<'tcx> { } } +/// Additional information carried by a MIR body when it is lowered from a coroutine. +/// This information is modified as it is lowered during the `StateTransform` MIR pass, +/// so not all fields will be active at a given time. For example, the `yield_ty` is +/// taken out of the field after yields are turned into returns, and the `coroutine_drop` +/// body is only populated after the state transform pass. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct CoroutineInfo<'tcx> { - /// The yield type of the function, if it is a coroutine. + /// The yield type of the function. This field is removed after the state transform pass. pub yield_ty: Option>, - /// The resume type of the function, if it is a coroutine. + /// The resume type of the function. This field is removed after the state transform pass. pub resume_ty: Option>, - /// Coroutine drop glue. + /// Coroutine drop glue. This field is populated after the state transform pass. pub coroutine_drop: Option>, - /// The layout of a coroutine. Produced by the state transformation. + /// The body of the coroutine, modified to take its upvars by move rather than by ref. + /// + /// This is used by coroutine-closures, which must return a different flavor of coroutine + /// when called using `AsyncFnOnce::call_once`. It is produced by the `ByMoveBody` pass which + /// is run right after building the initial MIR, and will only be populated for coroutines + /// which come out of the async closure desugaring. + /// + /// This body should be processed in lockstep with the containing body -- any optimization + /// passes, etc, should be applied to this body as well. This is done automatically if + /// using `run_passes`. + pub by_move_body: Option>, + + /// The body of the coroutine, modified to take its upvars by mutable ref rather than by + /// immutable ref. + /// + /// FIXME(async_closures): This is literally the same body as the parent body. Find a better + /// way to represent the by-mut signature (or cap the closure-kind of the coroutine). + pub by_mut_body: Option>, + + /// The layout of a coroutine. This field is populated after the state transform pass. pub coroutine_layout: Option>, /// If this is a coroutine then record the type of source expression that caused this coroutine @@ -274,6 +300,8 @@ impl<'tcx> CoroutineInfo<'tcx> { coroutine_kind, yield_ty: Some(yield_ty), resume_ty: Some(resume_ty), + by_move_body: None, + by_mut_body: None, coroutine_drop: None, coroutine_layout: None, } @@ -303,6 +331,12 @@ pub struct Body<'tcx> { /// and used for debuginfo. Indexed by a `SourceScope`. pub source_scopes: IndexVec>, + /// Additional information carried by a MIR body when it is lowered from a coroutine. + /// + /// Note that the coroutine drop shim, any promoted consts, and other synthetic MIR + /// bodies that come from processing a coroutine body are not typically coroutines + /// themselves, and should probably set this to `None` to avoid carrying redundant + /// information. pub coroutine: Option>>, /// Declarations of locals. @@ -578,6 +612,14 @@ impl<'tcx> Body<'tcx> { self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_drop.as_ref()) } + pub fn coroutine_by_move_body(&self) -> Option<&Body<'tcx>> { + self.coroutine.as_ref()?.by_move_body.as_ref() + } + + pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> { + self.coroutine.as_ref()?.by_mut_body.as_ref() + } + #[inline] pub fn coroutine_kind(&self) -> Option { self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 91fdf0b312991..6937df7bb1897 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -402,6 +402,8 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f18ce3187e49c..23281a7e710b6 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -993,7 +993,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { }) } - AggregateKind::Closure(def_id, args) => ty::tls::with(|tcx| { + AggregateKind::Closure(def_id, args) + | AggregateKind::CoroutineClosure(def_id, args) => ty::tls::with(|tcx| { let name = if tcx.sess.opts.unstable_opts.span_free_formats { let args = tcx.lift(args).unwrap(); format!("{{closure@{}}}", tcx.def_path_str_with_args(def_id, args),) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 98642adc19090..90b6df1dd1f5e 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -189,7 +189,7 @@ pub struct BorrowCheckResult<'tcx> { /// The result of the `mir_const_qualif` query. /// -/// Each field (except `error_occurred`) corresponds to an implementer of the `Qualif` trait in +/// Each field (except `tainted_by_errors`) corresponds to an implementer of the `Qualif` trait in /// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each /// `Qualif`. #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)] @@ -197,7 +197,6 @@ pub struct ConstQualifs { pub has_mut_interior: bool, pub needs_drop: bool, pub needs_non_const_drop: bool, - pub custom_eq: bool, pub tainted_by_errors: Option, } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index eb9466e4610e2..f42f6832b6b9d 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -13,6 +13,7 @@ use crate::ty::{self, List, Ty}; use crate::ty::{Region, UserTypeAnnotationIndex}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_data_structures::packed::Pu128; use rustc_hir::def_id::DefId; use rustc_hir::{self, CoroutineKind}; use rustc_index::IndexVec; @@ -856,7 +857,7 @@ impl TerminatorKind<'_> { pub struct SwitchTargets { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - pub(super) values: SmallVec<[u128; 1]>, + pub(super) values: SmallVec<[Pu128; 1]>, /// Possible branch sites. The last element of this vector is used /// for the otherwise branch, so targets.len() == values.len() + 1 @@ -1100,6 +1101,8 @@ pub enum ProjectionElem { /// "Downcast" to a variant of an enum or a coroutine. /// /// The included Symbol is the name of the variant, used for printing MIR. + /// + /// This operation itself is never UB, all it does is change the type of the place. Downcast(Option, VariantIdx), /// Like an explicit cast from an opaque type to a concrete type, but without @@ -1374,6 +1377,7 @@ pub enum AggregateKind<'tcx> { Closure(DefId, GenericArgsRef<'tcx>), Coroutine(DefId, GenericArgsRef<'tcx>), + CoroutineClosure(DefId, GenericArgsRef<'tcx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 5597609c7d796..4780042a51090 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -202,6 +202,9 @@ impl<'tcx> Rvalue<'tcx> { AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args), AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args), AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args), + AggregateKind::CoroutineClosure(did, args) => { + Ty::new_coroutine_closure(tcx, did, args) + } }, Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 385237b357b40..91b7952bec5e8 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -3,6 +3,7 @@ use rustc_hir::LangItem; use smallvec::SmallVec; use super::TerminatorKind; +use rustc_data_structures::packed::Pu128; use rustc_macros::HashStable; use std::slice; @@ -14,7 +15,8 @@ impl SwitchTargets { /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to /// `goto otherwise;`. pub fn new(targets: impl Iterator, otherwise: BasicBlock) -> Self { - let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip(); + let (values, mut targets): (SmallVec<_>, SmallVec<_>) = + targets.map(|(v, t)| (Pu128(v), t)).unzip(); targets.push(otherwise); Self { values, targets } } @@ -22,7 +24,7 @@ impl SwitchTargets { /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, /// and to `else_` if not. pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self { - Self { values: smallvec![value], targets: smallvec![then, else_] } + Self { values: smallvec![Pu128(value)], targets: smallvec![then, else_] } } /// Inverse of `SwitchTargets::static_if`. @@ -31,7 +33,7 @@ impl SwitchTargets { if let &[value] = &self.values[..] && let &[then, else_] = &self.targets[..] { - Some((value, then, else_)) + Some((value.get(), then, else_)) } else { None } @@ -75,7 +77,7 @@ impl SwitchTargets { } pub struct SwitchTargetsIter<'a> { - inner: iter::Zip, slice::Iter<'a, BasicBlock>>, + inner: iter::Zip, slice::Iter<'a, BasicBlock>>, } impl<'a> Iterator for SwitchTargetsIter<'a> { @@ -83,7 +85,7 @@ impl<'a> Iterator for SwitchTargetsIter<'a> { #[inline] fn next(&mut self) -> Option { - self.inner.next().map(|(val, bb)| (*val, *bb)) + self.inner.next().map(|(val, bb)| (val.get(), *bb)) } #[inline] @@ -290,7 +292,7 @@ impl AssertKind { } } - pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>)) + pub fn add_args(self, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) where O: fmt::Debug, { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 06657d71931c4..d77ea50fbfc16 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -345,6 +345,8 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | + ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | + ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | @@ -742,6 +744,12 @@ macro_rules! make_mir_visitor { ) => { self.visit_args(coroutine_args, location); } + AggregateKind::CoroutineClosure( + _, + coroutine_closure_args, + ) => { + self.visit_args(coroutine_closure_args, location); + } } for operand in operands { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 778b4308d2ee8..a272a51f32747 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,6 +1,7 @@ use crate::mir; use crate::query::CyclePlaceholder; use crate::traits; +use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty}; use std::intrinsics::transmute_unchecked; use std::mem::{size_of, MaybeUninit}; @@ -105,6 +106,10 @@ impl EraseType for Result>, rustc_errors::ErrorGuarantee [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; } +impl EraseType for Result { + type Result = [u8; size_of::>()]; +} + impl EraseType for Result>>, rustc_errors::ErrorGuaranteed> { type Result = [u8; size_of::< Result>>, rustc_errors::ErrorGuaranteed>, @@ -180,8 +185,8 @@ impl EraseType for Option>> { type Result = [u8; size_of::>>>()]; } -impl EraseType for rustc_hir::MaybeOwner<&'_ T> { - type Result = [u8; size_of::>()]; +impl EraseType for rustc_hir::MaybeOwner<'_> { + type Result = [u8; size_of::>()]; } impl EraseType for ty::EarlyBinder { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a9dc7f5d11a20..938fba0ed0981 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -109,7 +109,7 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue // as they will raise an fatal error on query cycles instead. rustc_queries! { /// This exists purely for testing the interactions between span_delayed_bug and incremental. - query trigger_span_delayed_bug(key: DefId) -> () { + query trigger_span_delayed_bug(key: DefId) { desc { "triggering a span delayed bug for testing incremental" } } @@ -119,7 +119,7 @@ rustc_queries! { desc { "compute registered tools for crate" } } - query early_lint_checks(_: ()) -> () { + query early_lint_checks(_: ()) { desc { "perform lints prior to macro expansion" } } @@ -190,11 +190,11 @@ rustc_queries! { desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) } } - /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. + /// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner. /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_owner_nodes(key: hir::OwnerId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> { + query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> { desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) } } @@ -299,7 +299,7 @@ rustc_queries! { /// name. This is useful for cases were not all linting code from rustc /// was called. With the default `None` all registered lints will also /// be checked for expectation fulfillment. - query check_expectations(key: Option) -> () { + query check_expectations(key: Option) { eval_always desc { "checking lint expectations (RFC 2383)" } } @@ -343,6 +343,15 @@ rustc_queries! { } } + query impl_trait_in_assoc_types_defined_by( + key: LocalDefId + ) -> &'tcx ty::List { + desc { + |tcx| "computing the opaque types defined by `{}`", + tcx.def_path_str(key.to_def_id()) + } + } + /// Returns the list of bounds that can be used for /// `SelectionCandidate::ProjectionCandidate(_)` and /// `ProjectionTyCandidate::TraitDef`. @@ -746,6 +755,11 @@ rustc_queries! { separate_provide_extern } + query coroutine_for_closure(def_id: DefId) -> DefId { + desc { |_tcx| "Given a coroutine-closure def id, return the def id of the coroutine returned by it" } + separate_provide_extern + } + /// Gets a map with the variance of every item; use `variances_of` instead. query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> { arena_cache @@ -897,39 +911,39 @@ rustc_queries! { } /// Performs lint checking for the module. - query lint_mod(key: LocalModDefId) -> () { + query lint_mod(key: LocalModDefId) { desc { |tcx| "linting {}", describe_as_module(key, tcx) } } - query check_unused_traits(_: ()) -> () { + query check_unused_traits(_: ()) { desc { "checking unused trait imports in crate" } } /// Checks the attributes in the module. - query check_mod_attrs(key: LocalModDefId) -> () { + query check_mod_attrs(key: LocalModDefId) { desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) } } /// Checks for uses of unstable APIs in the module. - query check_mod_unstable_api_usage(key: LocalModDefId) -> () { + query check_mod_unstable_api_usage(key: LocalModDefId) { desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } } /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`). - query check_mod_const_bodies(key: LocalModDefId) -> () { + query check_mod_const_bodies(key: LocalModDefId) { desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) } } /// Checks the loops in the module. - query check_mod_loops(key: LocalModDefId) -> () { + query check_mod_loops(key: LocalModDefId) { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query check_mod_naked_functions(key: LocalModDefId) -> () { + query check_mod_naked_functions(key: LocalModDefId) { desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } } - query check_mod_privacy(key: LocalModDefId) -> () { + query check_mod_privacy(key: LocalModDefId) { desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } @@ -949,7 +963,7 @@ rustc_queries! { desc { "finding live symbols in crate" } } - query check_mod_deathness(key: LocalModDefId) -> () { + query check_mod_deathness(key: LocalModDefId) { desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } } @@ -963,15 +977,16 @@ rustc_queries! { ensure_forwards_result_if_red } - query collect_mod_item_types(key: LocalModDefId) -> () { + query collect_mod_item_types(key: LocalModDefId) { desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } } /// Caches `CoerceUnsized` kinds for impls on custom types. - query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo { + query coerce_unsized_info(key: DefId) -> Result { desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + ensure_forwards_result_if_red } query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { @@ -991,8 +1006,9 @@ rustc_queries! { desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) } } - query coherent_trait(def_id: DefId) -> () { + query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } + ensure_forwards_result_if_red } /// Borrow-checks the function body. If this is a closure, returns @@ -1023,6 +1039,7 @@ rustc_queries! { "checking whether impl `{}` follows the orphan rules", tcx.def_path_str(key), } + ensure_forwards_result_if_red } /// Check whether the function has any recursion that could cause the inliner to trigger @@ -1109,7 +1126,7 @@ rustc_queries! { eval_always desc { "checking effective visibilities" } } - query check_private_in_public(_: ()) -> () { + query check_private_in_public(_: ()) { eval_always desc { "checking for private elements in public interfaces" } } @@ -1291,6 +1308,7 @@ rustc_queries! { query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> { desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } + ensure_forwards_result_if_red } query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] { desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } @@ -1347,9 +1365,9 @@ rustc_queries! { /// /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types /// correctly. - query has_structural_eq_impls(ty: Ty<'tcx>) -> bool { + query has_structural_eq_impl(ty: Ty<'tcx>) -> bool { desc { - "computing whether `{}` implements `PartialStructuralEq` and `StructuralEq`", + "computing whether `{}` implements `StructuralPartialEq`", ty } } diff --git a/compiler/rustc_middle/src/tests.rs b/compiler/rustc_middle/src/tests.rs index 757e0bd3bfbf9..49960cc0bb2a2 100644 --- a/compiler/rustc_middle/src/tests.rs +++ b/compiler/rustc_middle/src/tests.rs @@ -1,7 +1,7 @@ use super::*; -// FIXME(#27438): right now the unit tests of librustc_middle don't refer to any actual -// functions generated in librustc_data_structures (all +// FIXME(#27438): right now the unit tests of rustc_middle don't refer to any actual +// functions generated in rustc_data_structures (all // references are through generic functions), but statics are // referenced from time to time. Due to this bug we won't // actually correctly link in the statics unless we also diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b4b8387c262b9..0fed4ccc62a83 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -674,7 +674,7 @@ impl<'tcx> Pat<'tcx> { } impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { format!("{self}").into_diagnostic_arg() } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 135680b934936..894acf3c2aa5f 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -292,6 +292,8 @@ pub enum ObligationCauseCode<'tcx> { SizedArgumentType(Option), /// Return type must be `Sized`. SizedReturnType, + /// Return type of a call expression must be `Sized`. + SizedCallReturnType, /// Yield type must be `Sized`. SizedYieldType, /// Inline asm operand type must be `Sized`. diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 64f4af08e12ed..28eba133c76df 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -134,6 +134,15 @@ pub enum SelectionCandidate<'tcx> { is_const: bool, }, + /// Implementation of an `AsyncFn`-family trait by one of the anonymous types + /// generated for an `async ||` expression. + AsyncClosureCandidate, + + /// Implementation of the the `AsyncFnKindHelper` helper trait, which + /// is used internally to delay computation for async closures until after + /// upvar analysis is performed in HIR typeck. + AsyncFnKindHelperCandidate, + /// Implementation of a `Coroutine` trait by one of the anonymous types /// generated for a coroutine. CoroutineCandidate, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 6ec1dec97816c..a930c7e8ebf80 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; +use rustc_type_ir::ConstKind as IrConstKind; use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo}; mod int; @@ -19,7 +20,7 @@ use rustc_span::Span; use rustc_span::DUMMY_SP; pub use valtree::*; -use super::sty::ConstKind; +pub type ConstKind<'tcx> = IrConstKind>; /// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 310cf113b11b6..515d564e81db7 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -117,7 +117,7 @@ impl std::fmt::Debug for ConstInt { impl IntoDiagnosticArg 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_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(format!("{self:?}").into()) } } @@ -249,11 +249,6 @@ impl ScalarInt { } } - #[inline] - pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result { - Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64) - } - /// Tries to convert the `ScalarInt` to an unsigned integer of the given size. /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the /// `ScalarInt`s size in that case. @@ -262,24 +257,12 @@ impl ScalarInt { self.to_bits(size) } - // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt` - // in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size` - // value of the `ScalarInt` in that case. - #[inline] - pub fn try_to_bool(self) -> Result { - match self.try_to_u8()? { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(self.size()), - } - } - // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt` // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in // that case. #[inline] pub fn try_to_u8(self) -> Result { - self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap()) + self.try_to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt` @@ -287,7 +270,7 @@ impl ScalarInt { /// that case. #[inline] pub fn try_to_u16(self) -> Result { - self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap()) + self.try_to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt` @@ -295,7 +278,7 @@ impl ScalarInt { /// that case. #[inline] pub fn try_to_u32(self) -> Result { - self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap()) + self.try_to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt` @@ -303,7 +286,7 @@ impl ScalarInt { /// that case. #[inline] pub fn try_to_u64(self) -> Result { - self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap()) + self.try_to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt` @@ -311,7 +294,24 @@ impl ScalarInt { /// that case. #[inline] pub fn try_to_u128(self) -> Result { - self.to_bits(Size::from_bits(128)) + self.try_to_uint(Size::from_bits(128)) + } + + #[inline] + pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result { + self.try_to_uint(tcx.data_layout.pointer_size).map(|v| u64::try_from(v).unwrap()) + } + + // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt` + // in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size` + // value of the `ScalarInt` in that case. + #[inline] + pub fn try_to_bool(self) -> Result { + match self.try_to_u8()? { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(self.size()), + } } /// Tries to convert the `ScalarInt` to a signed integer of the given size. @@ -357,6 +357,27 @@ impl ScalarInt { pub fn try_to_i128(self) -> Result { self.try_to_int(Size::from_bits(128)) } + + #[inline] + pub fn try_to_target_isize(&self, tcx: TyCtxt<'_>) -> Result { + self.try_to_int(tcx.data_layout.pointer_size).map(|v| i64::try_from(v).unwrap()) + } + + #[inline] + pub fn try_to_float(self) -> Result { + // Going through `to_uint` to check size and truncation. + Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?)) + } + + #[inline] + pub fn try_to_f32(self) -> Result { + self.try_to_float() + } + + #[inline] + pub fn try_to_f64(self) -> Result { + self.try_to_float() + } } macro_rules! from { @@ -399,11 +420,7 @@ impl TryFrom for bool { type Error = Size; #[inline] fn try_from(int: ScalarInt) -> Result { - int.to_bits(Size::from_bytes(1)).and_then(|u| match u { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(Size::from_bytes(1)), - }) + int.try_to_bool() } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 16e7b16a0bf8c..603d7f46aabe0 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -15,7 +15,7 @@ pub struct UnevaluatedConst<'tcx> { } impl rustc_errors::IntoDiagnosticArg for UnevaluatedConst<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { format!("{self:?}").into_diagnostic_arg() } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6807eacb7f177..b747f0a4fb646 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -7,7 +7,7 @@ pub mod tls; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::struct_lint_level; +use crate::lint::lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_bound_vars; @@ -745,7 +745,7 @@ impl<'tcx> TyCtxt<'tcx> { ], ) = attr.meta_item_list().as_deref() { - Bound::Included(a) + Bound::Included(a.get()) } else { self.dcx().span_delayed_bug( attr.span, @@ -1193,7 +1193,7 @@ impl<'tcx> TyCtxt<'tcx> { let (suitable_region_binding_scope, bound_region) = loop { let def_id = match region.kind() { ty::ReLateParam(fr) => fr.bound_region.get_id()?.as_local()?, - ty::ReEarlyParam(ebr) => ebr.def_id.expect_local(), + ty::ReEarlyParam(ebr) => ebr.def_id.as_local()?, _ => return None, // not a free region }; let scope = self.local_parent(def_id); @@ -1416,6 +1416,7 @@ nop_lift! {const_; Const<'a> => Const<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} nop_lift! {predicate; Clause<'a> => Clause<'tcx>} +nop_lift! {layout; Layout<'a> => Layout<'tcx>} nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>} @@ -1424,8 +1425,28 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a GenericArgs<'a>`. nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>} +macro_rules! nop_slice_lift { + ($ty:ty => $lifted:ty) => { + impl<'a, 'tcx> Lift<'tcx> for &'a [$ty] { + type Lifted = &'tcx [$lifted]; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + if self.is_empty() { + return Some(&[]); + } + tcx.interners + .arena + .dropless + .contains_slice(self) + .then(|| unsafe { mem::transmute(self) }) + } + } + }; +} + +nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>} + TrivialLiftImpls! { - ImplPolarity, + ImplPolarity, Promoted } macro_rules! sty_debug_print { @@ -1523,6 +1544,7 @@ impl<'tcx> TyCtxt<'tcx> { CoroutineWitness, Dynamic, Closure, + CoroutineClosure, Tuple, Bound, Param, @@ -2056,7 +2078,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, /// typically generated by `#[derive(LintDiagnostic)]`). #[track_caller] - pub fn emit_spanned_lint( + pub fn emit_node_span_lint( self, lint: &'static Lint, hir_id: HirId, @@ -2065,17 +2087,17 @@ impl<'tcx> TyCtxt<'tcx> { ) { let msg = decorator.msg(); let (level, src) = self.lint_level_at_node(lint, hir_id); - struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, |diag| { + lint_level(self.sess, lint, level, src, Some(span.into()), msg, |diag| { decorator.decorate_lint(diag); }) } /// Emit a lint at the appropriate level for a hir node, with an associated span. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_span_lint_hir( + pub fn node_span_lint( self, lint: &'static Lint, hir_id: HirId, @@ -2084,29 +2106,29 @@ impl<'tcx> TyCtxt<'tcx> { decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let (level, src) = self.lint_level_at_node(lint, hir_id); - struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate); + lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate); } /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically /// generated by `#[derive(LintDiagnostic)]`). #[track_caller] - pub fn emit_lint( + pub fn emit_node_lint( self, lint: &'static Lint, id: HirId, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.struct_lint_node(lint, id, decorator.msg(), |diag| { + self.node_lint(lint, id, decorator.msg(), |diag| { decorator.decorate_lint(diag); }) } /// Emit a lint at the appropriate level for a hir node. /// - /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_lint_node( + pub fn node_lint( self, lint: &'static Lint, id: HirId, @@ -2114,7 +2136,7 @@ impl<'tcx> TyCtxt<'tcx> { decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let (level, src) = self.lint_level_at_node(lint, id); - struct_lint_level(self.sess, lint, level, src, None, msg, decorate); + lint_level(self.sess, lint, level, src, None, msg, decorate); } pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index c1e2479defd0a..8678f388298c2 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -20,7 +20,7 @@ use rustc_span::{BytePos, Span}; use rustc_type_ir::TyKind::*; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 0e44878524bf0..80b763d1469e4 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -299,7 +299,7 @@ impl<'tcx> Ty<'tcx> { }, ty::FnPtr(_) => "fn pointer".into(), ty::Dynamic(..) => "trait object".into(), - ty::Closure(..) => "closure".into(), + ty::Closure(..) | ty::CoroutineClosure(..) => "closure".into(), ty::Coroutine(def_id, ..) => { format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into() } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index b71919adc58fa..adc153c4dfd2d 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -128,7 +128,9 @@ pub fn simplify_type<'tcx>( _ => Some(SimplifiedType::MarkerTraitObject), }, ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), - ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)), + ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => { + Some(SimplifiedType::Closure(def_id)) + } ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)), ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)), ty::Never => Some(SimplifiedType::Never), @@ -236,6 +238,7 @@ impl DeepRejectCtxt { | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), ty::FnDef(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Placeholder(..) @@ -312,7 +315,7 @@ impl DeepRejectCtxt { }, // Impls cannot contain these types as these cannot be named directly. - ty::FnDef(..) | ty::Closure(..) | ty::Coroutine(..) => false, + ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false, // Placeholder types don't unify with anything on their own ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0c1d10914146f..0f4b5fe228c96 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -136,6 +136,22 @@ impl FlagComputation { self.add_ty(args.tupled_upvars_ty()); } + &ty::CoroutineClosure(_, args) => { + let args = args.as_coroutine_closure(); + let should_remove_further_specializable = + !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_args(args.parent_args()); + if should_remove_further_specializable { + self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; + } + + self.add_ty(args.kind_ty()); + self.add_ty(args.signature_parts_ty()); + self.add_ty(args.tupled_upvars_ty()); + self.add_ty(args.coroutine_captures_by_ref_ty()); + self.add_ty(args.coroutine_witness_ty()); + } + &ty::Bound(debruijn, _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_TY_BOUND); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 63f4bab7914ed..b9fff660a03b9 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -2,7 +2,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; -use crate::ty::sty::{ClosureArgs, CoroutineArgs, InlineConstArgs}; +use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs}; use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; @@ -20,6 +20,7 @@ use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; use std::ops::{ControlFlow, Deref}; +use std::ptr::NonNull; /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). @@ -31,12 +32,31 @@ use std::ops::{ControlFlow, Deref}; /// `Region` and `Const` are all interned. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct GenericArg<'tcx> { - ptr: NonZeroUsize, + ptr: NonNull<()>, marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +#[cfg(parallel_compiler)] +unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where + &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend +{ +} +#[cfg(parallel_compiler)] +unsafe impl<'tcx> rustc_data_structures::sync::DynSync for GenericArg<'tcx> where + &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSync +{ +} +unsafe impl<'tcx> Send for GenericArg<'tcx> where + &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): Send +{ +} +unsafe impl<'tcx> Sync for GenericArg<'tcx> where + &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): Sync +{ +} + impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -60,21 +80,21 @@ impl<'tcx> GenericArgKind<'tcx> { GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0); - (REGION_TAG, lt.0.0 as *const ty::RegionKind<'tcx> as usize) + (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); - (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo> as usize) + (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); - (CONST_TAG, ct.0.0 as *const WithCachedTypeInfo> as usize) + (CONST_TAG, NonNull::from(ct.0.0).cast()) } }; - GenericArg { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } + GenericArg { ptr: ptr.map_addr(|addr| addr | tag), marker: PhantomData } } } @@ -123,20 +143,22 @@ impl<'tcx> From> for GenericArg<'tcx> { impl<'tcx> GenericArg<'tcx> { #[inline] pub fn unpack(self) -> GenericArgKind<'tcx> { - let ptr = self.ptr.get(); + let ptr = unsafe { + self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK)) + }; // SAFETY: use of `Interned::new_unchecked` here is ok because these // pointers were originally created from `Interned` types in `pack()`, // and this is just going in the other direction. unsafe { - match ptr & TAG_MASK { + match self.ptr.addr().get() & TAG_MASK { REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>), + ptr.cast::>().as_ref(), ))), TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), + ptr.cast::>>().as_ref(), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), + ptr.cast::>>().as_ref(), ))), _ => intrinsics::unreachable(), } @@ -266,6 +288,14 @@ impl<'tcx> GenericArgs<'tcx> { ClosureArgs { args: self } } + /// Interpret these generic args as the args of a coroutine-closure type. + /// Coroutine-closure args have a particular structure controlled by the + /// compiler that encodes information like the signature and closure kind; + /// see `ty::CoroutineClosureArgs` struct for more comments. + pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<'tcx> { + CoroutineClosureArgs { args: self } + } + /// Interpret these generic args as the args of a coroutine type. /// Coroutine args have a particular structure controlled by the /// compiler that encodes information like the signature and coroutine kind; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index dd41cb5a61f44..9c1f4b20d2c83 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -3,6 +3,7 @@ use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt}; use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; @@ -11,6 +12,7 @@ use rustc_macros::HashStable; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::Symbol; +use std::assert_matches::assert_matches; use std::fmt; /// A monomorphized `InstanceDef`. @@ -80,11 +82,33 @@ pub enum InstanceDef<'tcx> { /// details on that). Virtual(DefId, usize), - /// `<[FnMut closure] as FnOnce>::call_once`. + /// `<[FnMut/Fn closure] as FnOnce>::call_once`. /// /// The `DefId` is the ID of the `call_once` method in `FnOnce`. + /// + /// This generates a body that will just borrow the (owned) self type, + /// and dispatch to the `FnMut::call_mut` instance for the closure. ClosureOnceShim { call_once: DefId, track_caller: bool }, + /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or + /// `<[Fn coroutine-closure] as FnMut>::call_mut`. + /// + /// The body generated here differs significantly from the `ClosureOnceShim`, + /// since we need to generate a distinct coroutine type that will move the + /// closure's upvars *out* of the closure. + ConstructCoroutineInClosureShim { + coroutine_closure_def_id: DefId, + target_kind: ty::ClosureKind, + }, + + /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce` + /// is called on a coroutine-closure whose closure kind greater than `FnOnce`, or + /// similarly for `AsyncFnMut`. + /// + /// This will select the body that is produced by the `ByMoveBody` transform, and thus + /// take and use all of its upvars by-move rather than by-ref. + CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind }, + /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking /// native support. @@ -166,6 +190,11 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(def_id) | InstanceDef::ThreadLocalShim(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } + | ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id: def_id, + target_kind: _, + } + | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -185,6 +214,8 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => None, @@ -280,6 +311,8 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::Item(_) | InstanceDef::Intrinsic(..) @@ -317,6 +350,8 @@ fn fmt_instance( InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"), InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), + InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), + InstanceDef::CoroutineKindShim { .. } => write!(f, " - shim"), InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), @@ -528,12 +563,12 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, args: ty::GenericArgsRef<'tcx>, requested_kind: ty::ClosureKind, - ) -> Option> { + ) -> Instance<'tcx> { let actual_kind = args.as_closure().kind(); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, args), - _ => Some(Instance::new(def_id, args)), + _ => Instance::new(def_id, args), } } @@ -548,7 +583,7 @@ impl<'tcx> Instance<'tcx> { tcx: TyCtxt<'tcx>, closure_did: DefId, args: ty::GenericArgsRef<'tcx>, - ) -> Option> { + ) -> Instance<'tcx> { let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); let call_once = tcx .associated_items(fn_once) @@ -562,14 +597,77 @@ impl<'tcx> Instance<'tcx> { let self_ty = Ty::new_closure(tcx, closure_did, args); - let sig = args.as_closure().sig(); - let sig = - tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?; - assert_eq!(sig.inputs().len(), 1); - let args = tcx.mk_args_trait(self_ty, [sig.inputs()[0].into()]); + let tupled_inputs_ty = args.as_closure().sig().map_bound(|sig| sig.inputs()[0]); + let tupled_inputs_ty = tcx.instantiate_bound_regions_with_erased(tupled_inputs_ty); + let args = tcx.mk_args_trait(self_ty, [tupled_inputs_ty.into()]); + + debug!(?self_ty, args=?tupled_inputs_ty.tuple_fields()); + Instance { def, args } + } + + pub fn try_resolve_item_for_coroutine( + tcx: TyCtxt<'tcx>, + trait_item_id: DefId, + trait_id: DefId, + rcvr_args: ty::GenericArgsRef<'tcx>, + ) -> Option> { + let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { + return None; + }; + let coroutine_kind = tcx.coroutine_kind(coroutine_def_id).unwrap(); + + let lang_items = tcx.lang_items(); + let coroutine_callable_item = if Some(trait_id) == lang_items.future_trait() { + assert_matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + ); + hir::LangItem::FuturePoll + } else if Some(trait_id) == lang_items.iterator_trait() { + assert_matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) + ); + hir::LangItem::IteratorNext + } else if Some(trait_id) == lang_items.async_iterator_trait() { + assert_matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) + ); + hir::LangItem::AsyncIteratorPollNext + } else if Some(trait_id) == lang_items.coroutine_trait() { + assert_matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); + hir::LangItem::CoroutineResume + } else { + return None; + }; - debug!(?self_ty, ?sig); - Some(Instance { def, args }) + if tcx.lang_items().get(coroutine_callable_item) == Some(trait_item_id) { + let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind() + else { + bug!() + }; + + // If the closure's kind ty disagrees with the identity closure's kind ty, + // then this must be a coroutine generated by one of the `ConstructCoroutineInClosureShim`s. + if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() { + Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) + } else { + Some(Instance { + def: ty::InstanceDef::CoroutineKindShim { + coroutine_def_id, + target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), + }, + args, + }) + } + } else { + // All other methods should be defaulted methods of the built-in trait. + // This is important for `Iterator`'s combinators, but also useful for + // adding future default methods to `Future`, for instance. + debug_assert!(tcx.defaultness(trait_item_id).has_value()); + Some(Instance::new(trait_item_id, rcvr_args)) + } } /// Depending on the kind of `InstanceDef`, the MIR body associated with an diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 25473f52c039e..8d8d06b7c0b7f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -269,7 +269,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } impl<'tcx> IntoDiagnosticArg for LayoutError<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -906,6 +906,12 @@ where i, ), + ty::CoroutineClosure(_, args) => field_ty_or_layout( + TyAndLayout { ty: args.as_coroutine_closure().tupled_upvars_ty(), ..this }, + cx, + i, + ), + ty::Coroutine(def_id, args) => match this.variants { Variants::Single { index } => TyMaybeWithLayout::Ty( args.as_coroutine() @@ -1247,7 +1253,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> PtxKernel | Msp430Interrupt | X86Interrupt - | AmdGpuKernel | EfiApi | AvrInterrupt | AvrNonBlockingInterrupt diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a5d9e0fcf44cd..c9137f374a238 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -63,6 +63,7 @@ use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; use std::ops::ControlFlow; +use std::ptr::NonNull; use std::{fmt, str}; pub use crate::ty::diagnostics::*; @@ -79,23 +80,35 @@ pub use self::closure::{ CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, CAPTURE_STRUCT_LOCAL, }; -pub use self::consts::{Const, ConstData, ConstInt, Expr, ScalarInt, UnevaluatedConst, ValTree}; +pub use self::consts::{ + Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree, +}; pub use self::context::{ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; +pub use self::predicate::{ + Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection, + ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, + PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, + PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, + PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, + RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitPredicate, + TraitRef, TypeOutlivesPredicate, +}; +pub use self::region::{ + BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region, + RegionKind, RegionVid, +}; pub use self::rvalue_scopes::RvalueScopes; -pub use self::sty::BoundRegionKind::*; pub use self::sty::{ - AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, - BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind, - CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, ExistentialPredicate, - ExistentialProjection, ExistentialTraitRef, FnSig, GenSig, InlineConstArgs, - InlineConstArgsParts, LateParamRegion, ParamConst, ParamTy, PolyExistentialPredicate, - PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyTraitRef, PredicateKind, - Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, + AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs, + InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -138,6 +151,8 @@ mod instance; mod list; mod opaque_types; mod parameterized; +mod predicate; +mod region; mod rvalue_scopes; mod structural_impls; #[allow(hidden_glob_reexports)] @@ -490,165 +505,6 @@ impl EarlyParamRegion { } } -/// A statement that can be proven by a trait solver. This includes things that may -/// show up in where clauses, such as trait predicates and projection predicates, -/// and also things that are emitted as part of type checking such as `ObjectSafe` -/// predicate which is emitted when a type is coerced to a trait object. -/// -/// Use this rather than `PredicateKind`, whenever possible. -#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] -#[rustc_pass_by_value] -pub struct Predicate<'tcx>( - Interned<'tcx, WithCachedTypeInfo>>>, -); - -impl<'tcx> Predicate<'tcx> { - /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. - #[inline] - pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { - self.0.internee - } - - #[inline(always)] - pub fn flags(self) -> TypeFlags { - self.0.flags - } - - #[inline(always)] - pub fn outer_exclusive_binder(self) -> DebruijnIndex { - self.0.outer_exclusive_binder - } - - /// Flips the polarity of a Predicate. - /// - /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. - pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option> { - let kind = self - .kind() - .map_bound(|kind| match kind { - PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity, - })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: polarity.flip()?, - }))), - - _ => None, - }) - .transpose()?; - - 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 - /// can remove required bounds which would cause us to - /// unsoundly accept some programs. See #91068. - #[inline] - pub fn allow_normalization(self) -> bool { - match self.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, - // `NormalizesTo` is only used in the new solver, so this shouldn't - // matter. Normalizing `term` would be 'wrong' however, as it changes whether - // `normalizes-to(::Assoc, ::Assoc)` holds. - PredicateKind::NormalizesTo(..) => false, - PredicateKind::Clause(ClauseKind::Trait(_)) - | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) - | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) - | PredicateKind::Clause(ClauseKind::Projection(_)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::AliasRelate(..) - | PredicateKind::ObjectSafe(_) - | PredicateKind::Subtype(_) - | PredicateKind::Coerce(_) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) - | PredicateKind::ConstEquate(_, _) - | PredicateKind::Ambiguous => true, - } - } -} - -impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) - } -} - -impl rustc_errors::IntoDiagnosticArg for Clause<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) - } -} - -/// A subset of predicates which can be assumed by the trait solver. They show up in -/// an item's where clauses, hence the name `Clause`, and may either be user-written -/// (such as traits) or may be inserted during lowering. -#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] -#[rustc_pass_by_value] -pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo>>>); - -impl<'tcx> Clause<'tcx> { - pub fn as_predicate(self) -> Predicate<'tcx> { - Predicate(self.0) - } - - pub fn kind(self) -> Binder<'tcx, ClauseKind<'tcx>> { - self.0.internee.map_bound(|kind| match kind { - PredicateKind::Clause(clause) => clause, - _ => unreachable!(), - }) - } - - pub fn as_trait_clause(self) -> Option>> { - let clause = self.kind(); - if let ty::ClauseKind::Trait(trait_clause) = clause.skip_binder() { - Some(clause.rebind(trait_clause)) - } else { - None - } - } - - pub fn as_projection_clause(self) -> Option>> { - let clause = self.kind(); - if let ty::ClauseKind::Projection(projection_clause) = clause.skip_binder() { - Some(clause.rebind(projection_clause)) - } else { - None - } - } - - pub fn as_type_outlives_clause(self) -> Option>> { - let clause = self.kind(); - if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() { - Some(clause.rebind(o)) - } else { - None - } - } - - pub fn as_region_outlives_clause(self) -> Option>> { - let clause = self.kind(); - if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() { - Some(clause.rebind(o)) - } else { - None - } - } -} - /// The crate outlives map is computed during typeck and contains the /// outlives of every item in the local crate. You should not use it /// directly, because to do so will make your pass dependent on the @@ -663,195 +519,25 @@ pub struct CratePredicatesMap<'tcx> { pub predicates: DefIdMap<&'tcx [(Clause<'tcx>, Span)]>, } -impl<'tcx> Clause<'tcx> { - /// Performs a substitution suitable for going from a - /// poly-trait-ref to supertraits that must hold if that - /// poly-trait-ref holds. This is slightly different from a normal - /// substitution in terms of what happens with bound regions. See - /// lengthy comment below for details. - pub fn subst_supertrait( - self, - tcx: TyCtxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> Clause<'tcx> { - // The interaction between HRTB and supertraits is not entirely - // obvious. Let me walk you (and myself) through an example. - // - // Let's start with an easy case. Consider two traits: - // - // trait Foo<'a>: Bar<'a,'a> { } - // trait Bar<'b,'c> { } - // - // Now, if we have a trait reference `for<'x> T: Foo<'x>`, then - // we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we - // knew that `Foo<'x>` (for any 'x) then we also know that - // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from - // normal substitution. - // - // In terms of why this is sound, the idea is that whenever there - // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` - // holds. So if there is an impl of `T:Foo<'a>` that applies to - // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all - // `'a`. - // - // Another example to be careful of is this: - // - // trait Foo1<'a>: for<'b> Bar1<'a,'b> { } - // trait Bar1<'b,'c> { } - // - // Here, if we have `for<'x> T: Foo1<'x>`, then what do we know? - // The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The - // reason is similar to the previous example: any impl of - // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`. So - // basically we would want to collapse the bound lifetimes from - // the input (`trait_ref`) and the supertraits. - // - // To achieve this in practice is fairly straightforward. Let's - // consider the more complicated scenario: - // - // - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x` - // has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`, - // where both `'x` and `'b` would have a DB index of 1. - // The substitution from the input trait-ref is therefore going to be - // `'a => 'x` (where `'x` has a DB index of 1). - // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b` is a late-bound parameter with a - // DB index of 1. - // - If we replace `'a` with `'x` from the input, it too will have - // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` - // just as we wanted. - // - // There is only one catch. If we just apply the substitution `'a - // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will - // adjust the DB index because we substituting into a binder (it - // tries to be so smart...) resulting in `for<'x> for<'b> - // Bar1<'x,'b>` (we have no syntax for this, so use your - // imagination). Basically the 'x will have DB index of 2 and 'b - // will have DB index of 1. Not quite what we want. So we apply - // the substitution to the *contents* of the trait reference, - // rather than the trait reference itself (put another way, the - // substitution code expects equal binding levels in the values - // from the substitution and the value being substituted into, and - // this trick achieves that). - - // Working through the second example: - // trait_ref: for<'x> T: Foo1<'^0.0>; args: [T, '^0.0] - // predicate: for<'b> Self: Bar1<'a, '^0.0>; args: [Self, 'a, '^0.0] - // We want to end up with: - // for<'x, 'b> T: Bar1<'^0.0, '^0.1> - // To do this: - // 1) We must shift all bound vars in predicate by the length - // of trait ref's bound vars. So, we would end up with predicate like - // Self: Bar1<'a, '^0.1> - // 2) We can then apply the trait args to this, ending up with - // T: Bar1<'^0.0, '^0.1> - // 3) Finally, to create the final bound vars, we concatenate the bound - // vars of the trait ref with those of the predicate: - // ['x, 'b] - let bound_pred = self.kind(); - let pred_bound_vars = bound_pred.bound_vars(); - let trait_bound_vars = trait_ref.bound_vars(); - // 1) Self: Bar1<'a, '^0.0> -> Self: Bar1<'a, '^0.1> - let shifted_pred = - tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); - // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = EarlyBinder::bind(shifted_pred).instantiate(tcx, trait_ref.skip_binder().args); - // 3) ['x] + ['b] -> ['x, 'b] - let bound_vars = - tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); - - // FIXME: Is it really perf sensitive to use reuse_or_mk_predicate here? - tcx.reuse_or_mk_predicate( - self.as_predicate(), - ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars), - ) - .expect_clause() - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx>, - - /// If polarity is Positive: we are proving that the trait is implemented. - /// - /// 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: ImplPolarity, -} - -pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; - -impl<'tcx> TraitPredicate<'tcx> { - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self } - } - - pub fn def_id(self) -> DefId { - self.trait_ref.def_id - } - - pub fn self_ty(self) -> Ty<'tcx> { - self.trait_ref.self_ty() - } -} - -impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(self) -> DefId { - // Ok to skip binder since trait `DefId` does not care about regions. - self.skip_binder().def_id() - } - - pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> { - self.map_bound(|trait_ref| trait_ref.self_ty()) - } - - #[inline] - pub fn polarity(self) -> ImplPolarity { - self.skip_binder().polarity - } -} - -/// `A: B` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct OutlivesPredicate(pub A, pub B); -pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; -pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; -pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; -pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; - -/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates -/// whether the `a` type is the type that we should label as "expected" when -/// presenting user diagnostics. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct SubtypePredicate<'tcx> { - pub a_is_expected: bool, - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, -} -pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; - -/// Encodes that we have to coerce *from* the `a` type to the `b` type. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct CoercePredicate<'tcx> { - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, -} -pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Term<'tcx> { - ptr: NonZeroUsize, + ptr: NonNull<()>, marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, } +#[cfg(parallel_compiler)] +unsafe impl<'tcx> rustc_data_structures::sync::DynSend for Term<'tcx> where + &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSend +{ +} +#[cfg(parallel_compiler)] +unsafe impl<'tcx> rustc_data_structures::sync::DynSync for Term<'tcx> where + &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSync +{ +} +unsafe impl<'tcx> Send for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Send {} +unsafe impl<'tcx> Sync for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Sync {} + impl Debug for Term<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let data = if let Some(ty) = self.ty() { @@ -914,17 +600,19 @@ impl<'tcx, D: TyDecoder>> Decodable for Term<'tcx> { impl<'tcx> Term<'tcx> { #[inline] pub fn unpack(self) -> TermKind<'tcx> { - let ptr = self.ptr.get(); + let ptr = unsafe { + self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK)) + }; // SAFETY: use of `Interned::new_unchecked` here is ok because these // pointers were originally created from `Interned` types in `pack()`, // and this is just going in the other direction. unsafe { - match ptr & TAG_MASK { + match self.ptr.addr().get() & TAG_MASK { TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), + ptr.cast::>>().as_ref(), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), + ptr.cast::>>().as_ref(), ))), _ => core::intrinsics::unreachable(), } @@ -986,16 +674,16 @@ impl<'tcx> TermKind<'tcx> { TermKind::Ty(ty) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); - (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo> as usize) + (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); - (CONST_TAG, ct.0.0 as *const WithCachedTypeInfo> as usize) + (CONST_TAG, NonNull::from(ct.0.0).cast()) } }; - Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } + Term { ptr: ptr.map_addr(|addr| addr | tag), marker: PhantomData } } } @@ -1032,351 +720,6 @@ impl From for TermVid { } } -/// This kind of predicate has no *direct* correspondent in the -/// syntax, but it roughly corresponds to the syntactic forms: -/// -/// 1. `T: TraitRef<..., Item = Type>` -/// 2. `>::Item == Type` (NYI) -/// -/// In particular, form #1 is "desugared" to the combination of a -/// normal trait predicate (`T: TraitRef<...>`) and one of these -/// predicates. Form #2 is a broader form in that it also permits -/// equality between arbitrary types. Processing an instance of -/// Form #2 eventually yields one of these `ProjectionPredicate` -/// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct ProjectionPredicate<'tcx> { - pub projection_ty: AliasTy<'tcx>, - pub term: Term<'tcx>, -} - -impl<'tcx> ProjectionPredicate<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.projection_ty.self_ty() - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ProjectionPredicate<'tcx> { - Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self } - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - self.projection_ty.trait_def_id(tcx) - } - - pub fn def_id(self) -> DefId { - self.projection_ty.def_id - } -} - -pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>; - -impl<'tcx> PolyProjectionPredicate<'tcx> { - /// Returns the `DefId` of the trait of the associated item being projected. - #[inline] - pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { - self.skip_binder().projection_ty.trait_def_id(tcx) - } - - /// Get the [PolyTraitRef] required for this projection to be well formed. - /// Note that for generic associated types the predicates of the associated - /// type also need to be checked. - #[inline] - pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { - // Note: unlike with `TraitRef::to_poly_trait_ref()`, - // `self.0.trait_ref` is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx)) - } - - pub fn term(&self) -> Binder<'tcx, Term<'tcx>> { - self.map_bound(|predicate| predicate.term) - } - - /// The `DefId` of the `TraitItem` for the associated type. - /// - /// Note that this is not the `DefId` of the `TraitRef` containing this - /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. - pub fn projection_def_id(&self) -> DefId { - // Ok to skip binder since trait `DefId` does not care about regions. - self.skip_binder().projection_ty.def_id - } -} - -/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be -/// proven by actually normalizing `alias`. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct NormalizesTo<'tcx> { - pub alias: AliasTy<'tcx>, - pub term: Term<'tcx>, -} - -impl<'tcx> NormalizesTo<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.alias.self_ty() - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> { - Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - self.alias.trait_def_id(tcx) - } - - pub fn def_id(self) -> DefId { - self.alias.def_id - } -} - -pub trait ToPolyTraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - self.map_bound_ref(|trait_pred| trait_pred.trait_ref) - } -} - -pub trait ToPredicate<'tcx, P = Predicate<'tcx>> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P; -} - -impl<'tcx, T> ToPredicate<'tcx, T> for T { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T { - self - } -} - -impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - ty::Binder::dummy(self).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(self) - } -} - -impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) - } -} - -impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause)) - } -} - -impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { - #[inline(always)] - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.as_predicate() - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - ty::Binder::dummy(self).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> { - #[inline(always)] - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> { - TraitPredicate { trait_ref: self, polarity: ImplPolarity::Positive } - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - let p: Predicate<'tcx> = self.to_predicate(tcx); - p.expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); - pred.to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); - pred.to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { - #[inline(always)] - fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { - self.map_bound(|trait_ref| TraitPredicate { - trait_ref, - polarity: ty::ImplPolarity::Positive, - }) - } -} - -impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - let p: Predicate<'tcx> = self.to_predicate(tcx); - p.expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - let p: Predicate<'tcx> = self.to_predicate(tcx); - p.expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate, ty::Region<'tcx>> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(self))).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx) - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - let p: Predicate<'tcx> = self.to_predicate(tcx); - p.expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { - let p: Predicate<'tcx> = self.to_predicate(tcx); - p.expect_clause() - } -} - -impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::NormalizesTo(self).to_predicate(tcx) - } -} - -impl<'tcx> Predicate<'tcx> { - pub fn to_opt_poly_trait_pred(self) -> Option> { - let predicate = self.kind(); - match predicate.skip_binder() { - PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(ClauseKind::Projection(..)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::NormalizesTo(..) - | PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) - | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) - | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous => None, - } - } - - pub fn to_opt_poly_projection_pred(self) -> Option> { - let predicate = self.kind(); - match predicate.skip_binder() { - PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(ClauseKind::Trait(..)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::NormalizesTo(..) - | PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) - | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) - | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous => None, - } - } - - /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. - pub fn as_clause(self) -> Option> { - match self.kind().skip_binder() { - PredicateKind::Clause(..) => Some(self.expect_clause()), - _ => None, - } - } - - /// Assert that the predicate is a clause. - pub fn expect_clause(self) -> Clause<'tcx> { - match self.kind().skip_binder() { - PredicateKind::Clause(..) => Clause(self.0), - _ => bug!("{self} is not a clause"), - } - } -} - /// Represents the bounds declared on a particular set of type /// parameters. Should eventually be generalized into a flag list of /// where-clauses. You can obtain an `InstantiatedPredicates` list from a @@ -2337,6 +1680,8 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs new file mode 100644 index 0000000000000..7c5b49512ae50 --- /dev/null +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -0,0 +1,1062 @@ +use rustc_data_structures::captures::Captures; +use rustc_data_structures::intern::Interned; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; +use rustc_span::Span; +use rustc_type_ir::ClauseKind as IrClauseKind; +use rustc_type_ir::PredicateKind as IrPredicateKind; +use std::cmp::Ordering; + +use crate::ty::visit::TypeVisitableExt; +use crate::ty::{ + self, AliasTy, Binder, DebruijnIndex, DebugWithInfcx, EarlyBinder, GenericArg, GenericArgs, + GenericArgsRef, ImplPolarity, Term, Ty, TyCtxt, TypeFlags, WithCachedTypeInfo, +}; + +pub type ClauseKind<'tcx> = IrClauseKind>; +pub type PredicateKind<'tcx> = IrPredicateKind>; + +/// A statement that can be proven by a trait solver. This includes things that may +/// show up in where clauses, such as trait predicates and projection predicates, +/// and also things that are emitted as part of type checking such as `ObjectSafe` +/// predicate which is emitted when a type is coerced to a trait object. +/// +/// Use this rather than `PredicateKind`, whenever possible. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Predicate<'tcx>( + pub(super) Interned<'tcx, WithCachedTypeInfo>>>, +); + +impl<'tcx> Predicate<'tcx> { + /// Gets the inner `ty::Binder<'tcx, PredicateKind<'tcx>>`. + #[inline] + pub fn kind(self) -> ty::Binder<'tcx, PredicateKind<'tcx>> { + self.0.internee + } + + #[inline(always)] + pub fn flags(self) -> TypeFlags { + self.0.flags + } + + #[inline(always)] + pub fn outer_exclusive_binder(self) -> DebruijnIndex { + self.0.outer_exclusive_binder + } + + /// Flips the polarity of a Predicate. + /// + /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. + pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option> { + let kind = self + .kind() + .map_bound(|kind| match kind { + PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity, + })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: polarity.flip()?, + }))), + + _ => None, + }) + .transpose()?; + + 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 + /// can remove required bounds which would cause us to + /// unsoundly accept some programs. See #91068. + #[inline] + pub fn allow_normalization(self) -> bool { + match self.kind().skip_binder() { + PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, + // `NormalizesTo` is only used in the new solver, so this shouldn't + // matter. Normalizing `term` would be 'wrong' however, as it changes whether + // `normalizes-to(::Assoc, ::Assoc)` holds. + PredicateKind::NormalizesTo(..) => false, + PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) + | PredicateKind::Clause(ClauseKind::Projection(_)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::AliasRelate(..) + | PredicateKind::ObjectSafe(_) + | PredicateKind::Subtype(_) + | PredicateKind::Coerce(_) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) + | PredicateKind::ConstEquate(_, _) + | PredicateKind::Ambiguous => true, + } + } +} + +impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { + rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) + } +} + +impl rustc_errors::IntoDiagnosticArg for Clause<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { + rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) + } +} + +/// A subset of predicates which can be assumed by the trait solver. They show up in +/// an item's where clauses, hence the name `Clause`, and may either be user-written +/// (such as traits) or may be inserted during lowering. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Clause<'tcx>( + pub(super) Interned<'tcx, WithCachedTypeInfo>>>, +); + +impl<'tcx> Clause<'tcx> { + pub fn as_predicate(self) -> Predicate<'tcx> { + Predicate(self.0) + } + + pub fn kind(self) -> ty::Binder<'tcx, ClauseKind<'tcx>> { + self.0.internee.map_bound(|kind| match kind { + PredicateKind::Clause(clause) => clause, + _ => unreachable!(), + }) + } + + pub fn as_trait_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::Trait(trait_clause) = clause.skip_binder() { + Some(clause.rebind(trait_clause)) + } else { + None + } + } + + pub fn as_projection_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::Projection(projection_clause) = clause.skip_binder() { + Some(clause.rebind(projection_clause)) + } else { + None + } + } + + pub fn as_type_outlives_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } + + pub fn as_region_outlives_clause( + self, + ) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub enum ExistentialPredicate<'tcx> { + /// E.g., `Iterator`. + Trait(ExistentialTraitRef<'tcx>), + /// E.g., `Iterator::Item = T`. + Projection(ExistentialProjection<'tcx>), + /// E.g., `Send`. + AutoTrait(DefId), +} + +impl<'tcx> DebugWithInfcx> for ExistentialPredicate<'tcx> { + fn fmt>>( + this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + std::fmt::Debug::fmt(&this.data, f) + } +} + +impl<'tcx> ExistentialPredicate<'tcx> { + /// Compares via an ordering that will not change if modules are reordered or other changes are + /// made to the tree. In particular, this ordering is preserved across incremental compilations. + pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering { + use self::ExistentialPredicate::*; + match (*self, *other) { + (Trait(_), Trait(_)) => Ordering::Equal, + (Projection(ref a), Projection(ref b)) => { + tcx.def_path_hash(a.def_id).cmp(&tcx.def_path_hash(b.def_id)) + } + (AutoTrait(ref a), AutoTrait(ref b)) => { + tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b)) + } + (Trait(_), _) => Ordering::Less, + (Projection(_), Trait(_)) => Ordering::Greater, + (Projection(_), _) => Ordering::Less, + (AutoTrait(_), _) => Ordering::Greater, + } + } +} + +pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>; + +impl<'tcx> PolyExistentialPredicate<'tcx> { + /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), + /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` + /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). + pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> { + match self.skip_binder() { + ExistentialPredicate::Trait(tr) => { + self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx) + } + ExistentialPredicate::Projection(p) => { + self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) + } + ExistentialPredicate::AutoTrait(did) => { + let generics = tcx.generics_of(did); + let trait_ref = if generics.params.len() == 1 { + ty::TraitRef::new(tcx, did, [self_ty]) + } else { + // If this is an ill-formed auto trait, then synthesize + // new error args for the missing generics. + let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]); + ty::TraitRef::new(tcx, did, err_args) + }; + self.rebind(trait_ref).to_predicate(tcx) + } + } + } +} + +impl<'tcx> ty::List> { + /// Returns the "principal `DefId`" of this set of existential predicates. + /// + /// A Rust trait object type consists (in addition to a lifetime bound) + /// of a set of trait bounds, which are separated into any number + /// of auto-trait bounds, and at most one non-auto-trait bound. The + /// non-auto-trait bound is called the "principal" of the trait + /// object. + /// + /// Only the principal can have methods or type parameters (because + /// auto traits can have neither of them). This is important, because + /// it means the auto traits can be treated as an unordered set (methods + /// would force an order for the vtable, while relating traits with + /// type parameters without knowing the order to relate them in is + /// a rather non-trivial task). + /// + /// For example, in the trait object `dyn std::fmt::Debug + Sync`, the + /// principal bound is `Some(std::fmt::Debug)`, while the auto-trait bounds + /// are the set `{Sync}`. + /// + /// It is also possible to have a "trivial" trait object that + /// consists only of auto traits, with no principal - for example, + /// `dyn Send + Sync`. In that case, the set of auto-trait bounds + /// is `{Send, Sync}`, while there is no principal. These trait objects + /// have a "trivial" vtable consisting of just the size, alignment, + /// and destructor. + pub fn principal(&self) -> Option>> { + self[0] + .map_bound(|this| match this { + ExistentialPredicate::Trait(tr) => Some(tr), + _ => None, + }) + .transpose() + } + + pub fn principal_def_id(&self) -> Option { + self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) + } + + #[inline] + pub fn projection_bounds<'a>( + &'a self, + ) -> impl Iterator>> + 'a { + self.iter().filter_map(|predicate| { + predicate + .map_bound(|pred| match pred { + ExistentialPredicate::Projection(projection) => Some(projection), + _ => None, + }) + .transpose() + }) + } + + #[inline] + pub fn auto_traits<'a>(&'a self) -> impl Iterator + Captures<'tcx> + 'a { + self.iter().filter_map(|predicate| match predicate.skip_binder() { + ExistentialPredicate::AutoTrait(did) => Some(did), + _ => None, + }) + } +} + +/// A complete reference to a trait. These take numerous guises in syntax, +/// but perhaps the most recognizable form is in a where-clause: +/// ```ignore (illustrative) +/// T: Foo +/// ``` +/// This would be represented by a trait-reference where the `DefId` is the +/// `DefId` for the trait `Foo` and the args define `T` as parameter 0, +/// and `U` as parameter 1. +/// +/// Trait references also appear in object types like `Foo`, but in +/// that case the `Self` parameter is absent from the substitutions. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitRef<'tcx> { + pub def_id: DefId, + pub args: GenericArgsRef<'tcx>, + /// This field exists to prevent the creation of `TraitRef` without + /// calling [`TraitRef::new`]. + pub(super) _use_trait_ref_new_instead: (), +} + +impl<'tcx> TraitRef<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + args: impl IntoIterator>>, + ) -> Self { + let args = tcx.check_and_mk_args(trait_def_id, args); + Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () } + } + + pub fn from_lang_item( + tcx: TyCtxt<'tcx>, + trait_lang_item: LangItem, + span: Span, + args: impl IntoIterator>>, + ) -> Self { + let trait_def_id = tcx.require_lang_item(trait_lang_item, Some(span)); + Self::new(tcx, trait_def_id, args) + } + + pub fn from_method( + tcx: TyCtxt<'tcx>, + trait_id: DefId, + args: GenericArgsRef<'tcx>, + ) -> ty::TraitRef<'tcx> { + let defs = tcx.generics_of(trait_id); + ty::TraitRef::new(tcx, trait_id, tcx.mk_args(&args[..defs.params.len()])) + } + + /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` + /// are the parameters defined on trait. + pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { + ty::TraitRef::new(tcx, def_id, GenericArgs::identity_for_item(tcx, def_id)) + } + + pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + ty::TraitRef::new( + tcx, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.iter().skip(1)), + ) + } + + #[inline] + pub fn self_ty(&self) -> Ty<'tcx> { + self.args.type_at(0) + } +} + +pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>; + +impl<'tcx> PolyTraitRef<'tcx> { + pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> { + self.map_bound_ref(|tr| tr.self_ty()) + } + + pub fn def_id(&self) -> DefId { + self.skip_binder().def_id + } +} + +impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + self.to_string().into_diagnostic_arg() + } +} + +/// An existential reference to a trait, where `Self` is erased. +/// For example, the trait object `Trait<'a, 'b, X, Y>` is: +/// ```ignore (illustrative) +/// exists T. T: Trait<'a, 'b, X, Y> +/// ``` +/// The substitutions don't include the erased `Self`, only trait +/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct ExistentialTraitRef<'tcx> { + pub def_id: DefId, + pub args: GenericArgsRef<'tcx>, +} + +impl<'tcx> ExistentialTraitRef<'tcx> { + pub fn erase_self_ty( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + ) -> ty::ExistentialTraitRef<'tcx> { + // Assert there is a Self. + trait_ref.args.type_at(0); + + ty::ExistentialTraitRef { + def_id: trait_ref.def_id, + args: tcx.mk_args(&trait_ref.args[1..]), + } + } + + /// Object types don't have a self type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self type. A common choice is `mk_err()` + /// or some placeholder type. + pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { + // otherwise the escaping vars would be captured by the binder + // debug_assert!(!self_ty.has_escaping_bound_vars()); + + ty::TraitRef::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter())) + } +} + +impl<'tcx> IntoDiagnosticArg for ExistentialTraitRef<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + self.to_string().into_diagnostic_arg() + } +} + +pub type PolyExistentialTraitRef<'tcx> = ty::Binder<'tcx, ExistentialTraitRef<'tcx>>; + +impl<'tcx> PolyExistentialTraitRef<'tcx> { + pub fn def_id(&self) -> DefId { + self.skip_binder().def_id + } + + /// Object types don't have a self type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self type. A common choice is `mk_err()` + /// or some placeholder type. + pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> { + self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) + } +} + +/// A `ProjectionPredicate` for an `ExistentialTraitRef`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct ExistentialProjection<'tcx> { + pub def_id: DefId, + pub args: GenericArgsRef<'tcx>, + pub term: Term<'tcx>, +} + +pub type PolyExistentialProjection<'tcx> = ty::Binder<'tcx, ExistentialProjection<'tcx>>; + +impl<'tcx> ExistentialProjection<'tcx> { + /// Extracts the underlying existential trait reference from this projection. + /// For example, if this is a projection of `exists T. ::Item == X`, + /// then this function would return an `exists T. T: Iterator` existential trait + /// reference. + pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> { + let def_id = tcx.parent(self.def_id); + let subst_count = tcx.generics_of(def_id).count() - 1; + let args = tcx.mk_args(&self.args[..subst_count]); + ty::ExistentialTraitRef { def_id, args } + } + + pub fn with_self_ty( + &self, + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + ) -> ty::ProjectionPredicate<'tcx> { + // otherwise the escaping regions would be captured by the binders + debug_assert!(!self_ty.has_escaping_bound_vars()); + + ty::ProjectionPredicate { + projection_ty: AliasTy::new( + tcx, + self.def_id, + [self_ty.into()].into_iter().chain(self.args), + ), + term: self.term, + } + } + + pub fn erase_self_ty( + tcx: TyCtxt<'tcx>, + projection_predicate: ty::ProjectionPredicate<'tcx>, + ) -> Self { + // Assert there is a Self. + projection_predicate.projection_ty.args.type_at(0); + + Self { + def_id: projection_predicate.projection_ty.def_id, + args: tcx.mk_args(&projection_predicate.projection_ty.args[1..]), + term: projection_predicate.term, + } + } +} + +impl<'tcx> PolyExistentialProjection<'tcx> { + pub fn with_self_ty( + &self, + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + ) -> ty::PolyProjectionPredicate<'tcx> { + self.map_bound(|p| p.with_self_ty(tcx, self_ty)) + } + + pub fn item_def_id(&self) -> DefId { + self.skip_binder().def_id + } +} + +impl<'tcx> Clause<'tcx> { + /// Performs a substitution suitable for going from a + /// poly-trait-ref to supertraits that must hold if that + /// poly-trait-ref holds. This is slightly different from a normal + /// substitution in terms of what happens with bound regions. See + /// lengthy comment below for details. + pub fn subst_supertrait( + self, + tcx: TyCtxt<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + ) -> Clause<'tcx> { + // The interaction between HRTB and supertraits is not entirely + // obvious. Let me walk you (and myself) through an example. + // + // Let's start with an easy case. Consider two traits: + // + // trait Foo<'a>: Bar<'a,'a> { } + // trait Bar<'b,'c> { } + // + // Now, if we have a trait reference `for<'x> T: Foo<'x>`, then + // we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we + // knew that `Foo<'x>` (for any 'x) then we also know that + // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from + // normal substitution. + // + // In terms of why this is sound, the idea is that whenever there + // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` + // holds. So if there is an impl of `T:Foo<'a>` that applies to + // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all + // `'a`. + // + // Another example to be careful of is this: + // + // trait Foo1<'a>: for<'b> Bar1<'a,'b> { } + // trait Bar1<'b,'c> { } + // + // Here, if we have `for<'x> T: Foo1<'x>`, then what do we know? + // The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The + // reason is similar to the previous example: any impl of + // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`. So + // basically we would want to collapse the bound lifetimes from + // the input (`trait_ref`) and the supertraits. + // + // To achieve this in practice is fairly straightforward. Let's + // consider the more complicated scenario: + // + // - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x` + // has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`, + // where both `'x` and `'b` would have a DB index of 1. + // The substitution from the input trait-ref is therefore going to be + // `'a => 'x` (where `'x` has a DB index of 1). + // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an + // early-bound parameter and `'b` is a late-bound parameter with a + // DB index of 1. + // - If we replace `'a` with `'x` from the input, it too will have + // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` + // just as we wanted. + // + // There is only one catch. If we just apply the substitution `'a + // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will + // adjust the DB index because we substituting into a binder (it + // tries to be so smart...) resulting in `for<'x> for<'b> + // Bar1<'x,'b>` (we have no syntax for this, so use your + // imagination). Basically the 'x will have DB index of 2 and 'b + // will have DB index of 1. Not quite what we want. So we apply + // the substitution to the *contents* of the trait reference, + // rather than the trait reference itself (put another way, the + // substitution code expects equal binding levels in the values + // from the substitution and the value being substituted into, and + // this trick achieves that). + + // Working through the second example: + // trait_ref: for<'x> T: Foo1<'^0.0>; args: [T, '^0.0] + // predicate: for<'b> Self: Bar1<'a, '^0.0>; args: [Self, 'a, '^0.0] + // We want to end up with: + // for<'x, 'b> T: Bar1<'^0.0, '^0.1> + // To do this: + // 1) We must shift all bound vars in predicate by the length + // of trait ref's bound vars. So, we would end up with predicate like + // Self: Bar1<'a, '^0.1> + // 2) We can then apply the trait args to this, ending up with + // T: Bar1<'^0.0, '^0.1> + // 3) Finally, to create the final bound vars, we concatenate the bound + // vars of the trait ref with those of the predicate: + // ['x, 'b] + let bound_pred = self.kind(); + let pred_bound_vars = bound_pred.bound_vars(); + let trait_bound_vars = trait_ref.bound_vars(); + // 1) Self: Bar1<'a, '^0.0> -> Self: Bar1<'a, '^0.1> + let shifted_pred = + tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); + // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> + let new = EarlyBinder::bind(shifted_pred).instantiate(tcx, trait_ref.skip_binder().args); + // 3) ['x] + ['b] -> ['x, 'b] + let bound_vars = + tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); + + // FIXME: Is it really perf sensitive to use reuse_or_mk_predicate here? + tcx.reuse_or_mk_predicate( + self.as_predicate(), + ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars), + ) + .expect_clause() + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitPredicate<'tcx> { + pub trait_ref: TraitRef<'tcx>, + + /// If polarity is Positive: we are proving that the trait is implemented. + /// + /// 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: ImplPolarity, +} + +pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; + +impl<'tcx> TraitPredicate<'tcx> { + pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self } + } + + pub fn def_id(self) -> DefId { + self.trait_ref.def_id + } + + pub fn self_ty(self) -> Ty<'tcx> { + self.trait_ref.self_ty() + } +} + +impl<'tcx> PolyTraitPredicate<'tcx> { + pub fn def_id(self) -> DefId { + // Ok to skip binder since trait `DefId` does not care about regions. + self.skip_binder().def_id() + } + + pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } + + #[inline] + pub fn polarity(self) -> ImplPolarity { + self.skip_binder().polarity + } +} + +/// `A: B` +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct OutlivesPredicate(pub A, pub B); +pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; +pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; +pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; +pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; + +/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates +/// whether the `a` type is the type that we should label as "expected" when +/// presenting user diagnostics. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct SubtypePredicate<'tcx> { + pub a_is_expected: bool, + pub a: Ty<'tcx>, + pub b: Ty<'tcx>, +} +pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; + +/// Encodes that we have to coerce *from* the `a` type to the `b` type. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct CoercePredicate<'tcx> { + pub a: Ty<'tcx>, + pub b: Ty<'tcx>, +} +pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; + +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T: TraitRef<..., Item = Type>` +/// 2. `>::Item == Type` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T: TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of +/// Form #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct ProjectionPredicate<'tcx> { + pub projection_ty: AliasTy<'tcx>, + pub term: Term<'tcx>, +} + +impl<'tcx> ProjectionPredicate<'tcx> { + pub fn self_ty(self) -> Ty<'tcx> { + self.projection_ty.self_ty() + } + + pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ProjectionPredicate<'tcx> { + Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self } + } + + pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { + self.projection_ty.trait_def_id(tcx) + } + + pub fn def_id(self) -> DefId { + self.projection_ty.def_id + } +} + +pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>; + +impl<'tcx> PolyProjectionPredicate<'tcx> { + /// Returns the `DefId` of the trait of the associated item being projected. + #[inline] + pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { + self.skip_binder().projection_ty.trait_def_id(tcx) + } + + /// Get the [PolyTraitRef] required for this projection to be well formed. + /// Note that for generic associated types the predicates of the associated + /// type also need to be checked. + #[inline] + pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { + // Note: unlike with `TraitRef::to_poly_trait_ref()`, + // `self.0.trait_ref` is permitted to have escaping regions. + // This is because here `self` has a `Binder` and so does our + // return value, so we are preserving the number of binding + // levels. + self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx)) + } + + pub fn term(&self) -> Binder<'tcx, Term<'tcx>> { + self.map_bound(|predicate| predicate.term) + } + + /// The `DefId` of the `TraitItem` for the associated type. + /// + /// Note that this is not the `DefId` of the `TraitRef` containing this + /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. + pub fn projection_def_id(&self) -> DefId { + // Ok to skip binder since trait `DefId` does not care about regions. + self.skip_binder().projection_ty.def_id + } +} + +/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be +/// proven by actually normalizing `alias`. +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct NormalizesTo<'tcx> { + pub alias: AliasTy<'tcx>, + pub term: Term<'tcx>, +} + +impl<'tcx> NormalizesTo<'tcx> { + pub fn self_ty(self) -> Ty<'tcx> { + self.alias.self_ty() + } + + pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> { + Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } + } + + pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { + self.alias.trait_def_id(tcx) + } + + pub fn def_id(self) -> DefId { + self.alias.def_id + } +} + +pub trait ToPolyTraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + self.map_bound_ref(|trait_pred| trait_pred.trait_ref) + } +} + +pub trait ToPredicate<'tcx, P = Predicate<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P; +} + +impl<'tcx, T> ToPredicate<'tcx, T> for T { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T { + self + } +} + +impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + tcx.mk_predicate(self) + } +} + +impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) + } +} + +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause)) + } +} + +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { + #[inline(always)] + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.as_predicate() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> { + TraitPredicate { trait_ref: self, polarity: ImplPolarity::Positive } + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); + pred.to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); + pred.to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { + self.map_bound(|trait_ref| TraitPredicate { + trait_ref, + polarity: ty::ImplPolarity::Positive, + }) + } +} + +impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate, ty::Region<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(self))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::NormalizesTo(self).to_predicate(tcx) + } +} + +impl<'tcx> Predicate<'tcx> { + pub fn to_opt_poly_trait_pred(self) -> Option> { + let predicate = self.kind(); + match predicate.skip_binder() { + PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::NormalizesTo(..) + | PredicateKind::AliasRelate(..) + | PredicateKind::Subtype(..) + | PredicateKind::Coerce(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) + | PredicateKind::ObjectSafe(..) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) + | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous => None, + } + } + + pub fn to_opt_poly_projection_pred(self) -> Option> { + let predicate = self.kind(); + match predicate.skip_binder() { + PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::NormalizesTo(..) + | PredicateKind::AliasRelate(..) + | PredicateKind::Subtype(..) + | PredicateKind::Coerce(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) + | PredicateKind::ObjectSafe(..) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) + | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous => None, + } + } + + /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. + pub fn as_clause(self) -> Option> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Some(self.expect_clause()), + _ => None, + } + } + + /// Assert that the predicate is a clause. + pub fn expect_clause(self) -> Clause<'tcx> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Clause(self.0), + _ => bug!("{self} is not a clause"), + } + } +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index f32b7b0852abc..19f8ba124f143 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -3,6 +3,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; +use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; @@ -130,8 +131,24 @@ pub trait Printer<'tcx>: Sized { parent_args = &args[..generics.parent_count.min(args.len())]; match key.disambiguated_data.data { - // Closures' own generics are only captures, don't print them. - DefPathData::Closure => {} + DefPathData::Closure => { + // FIXME(async_closures): This is somewhat ugly. + // We need to additionally print the `kind` field of a closure if + // it is desugared from a coroutine-closure. + if let Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Closure, + )) = self.tcx().coroutine_kind(def_id) + && args.len() >= parent_args.len() + 1 + { + return self.path_generic_args( + |cx| cx.print_def_path(def_id, parent_args), + &args[..parent_args.len() + 1][..1], + ); + } else { + // Closures' own generics are only captures, don't print them. + } + } // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`. // Anon consts doesn't have their own generics, and inline consts' own // generics are their inferred types, so don't print them. @@ -259,6 +276,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty::FnDef(def_id, _) | ty::Closure(def_id, _) + | ty::CoroutineClosure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineWitness(def_id, _) | ty::Foreign(def_id) => Some(def_id), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4028de27cae14..c0bfd2380ade0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -804,17 +804,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } else { p!(print_def_path(did, args)); - p!(" upvar_tys=("); - if !args.as_coroutine().is_valid() { - p!("unavailable"); - } else { - self.comma_sep(args.as_coroutine().upvar_tys().iter())?; - } - p!(")"); - - if args.as_coroutine().is_valid() { - p!(" ", print(args.as_coroutine().witness())); - } + p!( + " upvar_tys=", + print(args.as_coroutine().tupled_upvars_ty()), + " witness=", + print(args.as_coroutine().witness()) + ); } p!("}}") @@ -868,19 +863,56 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } else { p!(print_def_path(did, args)); - if !args.as_closure().is_valid() { - p!(" closure_args=(unavailable)"); - p!(write(" args={}", args.print_as_list())); + p!( + " closure_kind_ty=", + print(args.as_closure().kind_ty()), + " closure_sig_as_fn_ptr_ty=", + print(args.as_closure().sig_as_fn_ptr_ty()), + " upvar_tys=", + print(args.as_closure().tupled_upvars_ty()) + ); + } + p!("}}"); + } + ty::CoroutineClosure(did, args) => { + p!(write("{{")); + if !self.should_print_verbose() { + p!(write("coroutine-closure")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + if self.tcx().sess.opts.unstable_opts.span_free_formats { + p!("@", print_def_path(did.to_def_id(), args)); + } else { + let span = self.tcx().def_span(did); + let preference = if with_forced_trimmed_paths() { + FileNameDisplayPreference::Short + } else { + FileNameDisplayPreference::Remapped + }; + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_string(span, preference) + )); + } } else { - p!(" closure_kind_ty=", print(args.as_closure().kind_ty())); - p!( - " closure_sig_as_fn_ptr_ty=", - print(args.as_closure().sig_as_fn_ptr_ty()) - ); - p!(" upvar_tys=("); - self.comma_sep(args.as_closure().upvar_tys().iter())?; - p!(")"); + p!(write("@"), print_def_path(did, args)); } + } else { + p!(print_def_path(did, args)); + p!( + " closure_kind_ty=", + print(args.as_coroutine_closure().kind_ty()), + " signature_parts_ty=", + print(args.as_coroutine_closure().signature_parts_ty()), + " upvar_tys=", + print(args.as_coroutine_closure().tupled_upvars_ty()), + " coroutine_captures_by_ref_ty=", + print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + " coroutine_witness_ty=", + print(args.as_coroutine_closure().coroutine_witness_ty()) + ); } p!("}}"); } @@ -2642,7 +2674,7 @@ where pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>); impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintOnlyTraitPath<'tcx> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -2659,7 +2691,7 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>); impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintSugared<'tcx> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -3072,8 +3104,6 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N /// See also [`DelayDm`](rustc_error_messages::DelayDm) and [`with_no_trimmed_paths!`]. // this is pub to be able to intra-doc-link it pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { - assert!(tcx.sess.opts.trimmed_def_paths); - // Trimming paths is expensive and not optimized, since we expect it to only be used for error // reporting. // diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs new file mode 100644 index 0000000000000..75be380704e1f --- /dev/null +++ b/compiler/rustc_middle/src/ty/region.rs @@ -0,0 +1,399 @@ +use polonius_engine::Atom; +use rustc_data_structures::intern::Interned; +use rustc_errors::MultiSpan; +use rustc_hir::def_id::DefId; +use rustc_index::Idx; +use rustc_span::symbol::sym; +use rustc_span::symbol::{kw, Symbol}; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_type_ir::RegionKind as IrRegionKind; +use std::ops::Deref; + +use crate::ty::{self, BoundVar, TyCtxt, TypeFlags}; + +pub type RegionKind<'tcx> = IrRegionKind>; + +/// Use this rather than `RegionKind`, whenever possible. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); + +impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> { + type Kind = RegionKind<'tcx>; + + fn kind(self) -> RegionKind<'tcx> { + *self + } +} + +impl<'tcx> Region<'tcx> { + #[inline] + pub fn new_early_param( + tcx: TyCtxt<'tcx>, + early_bound_region: ty::EarlyParamRegion, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReEarlyParam(early_bound_region)) + } + + #[inline] + pub fn new_bound( + tcx: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + bound_region: ty::BoundRegion, + ) -> Region<'tcx> { + // Use a pre-interned one when possible. + if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region + && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) + && let Some(re) = inner.get(var.as_usize()).copied() + { + re + } else { + tcx.intern_region(ty::ReBound(debruijn, bound_region)) + } + } + + #[inline] + pub fn new_late_param( + tcx: TyCtxt<'tcx>, + scope: DefId, + bound_region: ty::BoundRegionKind, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReLateParam(ty::LateParamRegion { scope, bound_region })) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { + // Use a pre-interned one when possible. + tcx.lifetimes + .re_vars + .get(v.as_usize()) + .copied() + .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) + } + + #[inline] + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { + tcx.intern_region(ty::RePlaceholder(placeholder)) + } + + /// Constructs a `RegionKind::ReError` region. + #[track_caller] + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> { + tcx.intern_region(ty::ReError(reported)) + } + + /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it + /// gets used. + #[track_caller] + pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { + Region::new_error_with_message( + tcx, + DUMMY_SP, + "RegionKind::ReError constructed but no error reported", + ) + } + + /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given + /// `msg` to ensure it gets used. + #[track_caller] + pub fn new_error_with_message>( + tcx: TyCtxt<'tcx>, + span: S, + msg: &'static str, + ) -> Region<'tcx> { + let reported = tcx.dcx().span_delayed_bug(span, msg); + Region::new_error(tcx, reported) + } + + /// Avoid this in favour of more specific `new_*` methods, where possible, + /// to avoid the cost of the `match`. + pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { + match kind { + ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), + ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region), + ty::ReLateParam(ty::LateParamRegion { scope, bound_region }) => { + Region::new_late_param(tcx, scope, bound_region) + } + ty::ReStatic => tcx.lifetimes.re_static, + ty::ReVar(vid) => Region::new_var(tcx, vid), + ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), + ty::ReErased => tcx.lifetimes.re_erased, + ty::ReError(reported) => Region::new_error(tcx, reported), + } + } +} + +/// Region utilities +impl<'tcx> Region<'tcx> { + pub fn kind(self) -> RegionKind<'tcx> { + *self.0.0 + } + + pub fn get_name(self) -> Option { + if self.has_name() { + match *self { + ty::ReEarlyParam(ebr) => Some(ebr.name), + ty::ReBound(_, br) => br.kind.get_name(), + ty::ReLateParam(fr) => fr.bound_region.get_name(), + ty::ReStatic => Some(kw::StaticLifetime), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), + _ => None, + } + } else { + None + } + } + + pub fn get_name_or_anon(self) -> Symbol { + match self.get_name() { + Some(name) => name, + None => sym::anon, + } + } + + /// Is this region named by the user? + pub fn has_name(self) -> bool { + match *self { + ty::ReEarlyParam(ebr) => ebr.has_name(), + ty::ReBound(_, br) => br.kind.is_named(), + ty::ReLateParam(fr) => fr.bound_region.is_named(), + ty::ReStatic => true, + ty::ReVar(..) => false, + ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), + ty::ReErased => false, + ty::ReError(_) => false, + } + } + + #[inline] + pub fn is_error(self) -> bool { + matches!(*self, ty::ReError(_)) + } + + #[inline] + pub fn is_static(self) -> bool { + matches!(*self, ty::ReStatic) + } + + #[inline] + pub fn is_erased(self) -> bool { + matches!(*self, ty::ReErased) + } + + #[inline] + pub fn is_bound(self) -> bool { + matches!(*self, ty::ReBound(..)) + } + + #[inline] + pub fn is_placeholder(self) -> bool { + matches!(*self, ty::RePlaceholder(..)) + } + + #[inline] + pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { + match *self { + ty::ReBound(debruijn, _) => debruijn >= index, + _ => false, + } + } + + pub fn type_flags(self) -> TypeFlags { + let mut flags = TypeFlags::empty(); + + match *self { + ty::ReVar(..) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_RE_INFER; + } + ty::RePlaceholder(..) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; + } + ty::ReEarlyParam(..) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_RE_PARAM; + } + ty::ReLateParam { .. } => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + } + ty::ReStatic => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + } + ty::ReBound(..) => { + flags = flags | TypeFlags::HAS_RE_BOUND; + } + ty::ReErased => { + flags = flags | TypeFlags::HAS_RE_ERASED; + } + ty::ReError(_) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + } + } + + debug!("type_flags({:?}) = {:?}", self, flags); + + flags + } + + /// Given an early-bound or free region, returns the `DefId` where it was bound. + /// For example, consider the regions in this snippet of code: + /// + /// ```ignore (illustrative) + /// impl<'a> Foo { + /// // ^^ -- early bound, declared on an impl + /// + /// fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c + /// // ^^ ^^ ^ anonymous, late-bound + /// // | early-bound, appears in where-clauses + /// // late-bound, appears only in fn args + /// {..} + /// } + /// ``` + /// + /// Here, `free_region_binding_scope('a)` would return the `DefId` + /// of the impl, and for all the other highlighted regions, it + /// would return the `DefId` of the function. In other cases (not shown), this + /// function might return the `DefId` of a closure. + pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId { + match *self { + ty::ReEarlyParam(br) => tcx.parent(br.def_id), + ty::ReLateParam(fr) => fr.scope, + _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), + } + } + + /// True for free regions other than `'static`. + pub fn is_param(self) -> bool { + matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_)) + } + + /// True for free region in the current context. + /// + /// This is the case for `'static` and param regions. + pub fn is_free(self) -> bool { + match *self { + ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true, + ty::ReVar(..) + | ty::RePlaceholder(..) + | ty::ReBound(..) + | ty::ReErased + | ty::ReError(..) => false, + } + } + + pub fn is_var(self) -> bool { + matches!(self.kind(), ty::ReVar(_)) + } + + pub fn as_var(self) -> RegionVid { + match self.kind() { + ty::ReVar(vid) => vid, + _ => bug!("expected region {:?} to be of kind ReVar", self), + } + } +} + +impl<'tcx> Deref for Region<'tcx> { + type Target = RegionKind<'tcx>; + + #[inline] + fn deref(&self) -> &RegionKind<'tcx> { + self.0.0 + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] +#[derive(HashStable)] +pub struct EarlyParamRegion { + pub def_id: DefId, + pub index: u32, + pub name: Symbol, +} + +impl std::fmt::Debug for EarlyParamRegion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) + } +} + +rustc_index::newtype_index! { + /// A **region** (lifetime) **v**ariable **ID**. + #[derive(HashStable)] + #[encodable] + #[orderable] + #[debug_format = "'?{}"] + pub struct RegionVid {} +} + +impl Atom for RegionVid { + fn index(self) -> usize { + Idx::index(self) + } +} + +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] +#[derive(HashStable)] +/// The parameter representation of late-bound function parameters, "some region +/// at least as big as the scope `fr.scope`". +pub struct LateParamRegion { + pub scope: DefId, + pub bound_region: BoundRegionKind, +} + +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] +#[derive(HashStable)] +pub enum BoundRegionKind { + /// An anonymous region parameter for a given fn (&T) + BrAnon, + + /// Named region parameters for functions (a in &'a T) + /// + /// The `DefId` is needed to distinguish free regions in + /// the event of shadowing. + BrNamed(DefId, Symbol), + + /// Anonymous region for the implicit env pointer parameter + /// to a closure + BrEnv, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(HashStable)] +pub struct BoundRegion { + pub var: BoundVar, + pub kind: BoundRegionKind, +} + +impl BoundRegionKind { + pub fn is_named(&self) -> bool { + match *self { + BoundRegionKind::BrNamed(_, name) => { + name != kw::UnderscoreLifetime && name != kw::Empty + } + _ => false, + } + } + + pub fn get_name(&self) -> Option { + if self.is_named() { + match *self { + BoundRegionKind::BrNamed(_, name) => return Some(name), + _ => unreachable!(), + } + } + + None + } + + pub fn get_id(&self) -> Option { + match *self { + BoundRegionKind::BrNamed(id, _) => return Some(id), + _ => None, + } + } +} diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 8543bd0bbdd96..f2321e7e1d22f 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -481,6 +481,13 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_closure(tcx, a_id, args)) } + (&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args)) + if a_id == b_id => + { + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + } + (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; Ok(Ty::new_ptr(tcx, mt)) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 11b579a1f85b6..c6805ba932357 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -584,6 +584,9 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { ty::CoroutineWitness(did, args.try_fold_with(folder)?) } ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?), + ty::CoroutineClosure(did, args) => { + ty::CoroutineClosure(did, args.try_fold_with(folder)?) + } ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), ty::Bool @@ -632,6 +635,7 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { 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::Bool diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8cf5fc8013f1d..927924452f913 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -6,119 +6,44 @@ use crate::infer::canonical::Canonical; use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; use crate::ty::{ - self, AdtDef, Discr, IntoKind, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, + self, AdtDef, BoundRegionKind, Discr, Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use crate::ty::{List, ParamEnv}; use hir::def::DefKind; -use polonius_engine::Atom; use rustc_data_structures::captures::Captures; -use rustc_data_structures::intern::Interned; use rustc_errors::{ DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; -use rustc_index::Idx; use rustc_macros::HashStable; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::assert_matches::debug_assert_matches; use std::borrow::Cow; -use std::cmp::Ordering; -use std::fmt; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; use rustc_type_ir::BoundVar; -use rustc_type_ir::ClauseKind as IrClauseKind; use rustc_type_ir::CollectAndApply; -use rustc_type_ir::ConstKind as IrConstKind; -use rustc_type_ir::DebugWithInfcx; use rustc_type_ir::DynKind; -use rustc_type_ir::PredicateKind as IrPredicateKind; -use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; use rustc_type_ir::TyKind::*; use rustc_type_ir::TypeAndMut as IrTypeAndMut; +use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here #[rustc_diagnostic_item = "TyKind"] pub type TyKind<'tcx> = IrTyKind>; -pub type RegionKind<'tcx> = IrRegionKind>; -pub type ConstKind<'tcx> = IrConstKind>; -pub type PredicateKind<'tcx> = IrPredicateKind>; -pub type ClauseKind<'tcx> = IrClauseKind>; pub type TypeAndMut<'tcx> = IrTypeAndMut>; -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] -#[derive(HashStable)] -/// The parameter representation of late-bound function parameters, "some region -/// at least as big as the scope `fr.scope`". -pub struct LateParamRegion { - pub scope: DefId, - pub bound_region: BoundRegionKind, -} - -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] -#[derive(HashStable)] -pub enum BoundRegionKind { - /// An anonymous region parameter for a given fn (&T) - BrAnon, - - /// Named region parameters for functions (a in &'a T) - /// - /// The `DefId` is needed to distinguish free regions in - /// the event of shadowing. - BrNamed(DefId, Symbol), - - /// Anonymous region for the implicit env pointer parameter - /// to a closure - BrEnv, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] -#[derive(HashStable)] -pub struct BoundRegion { - pub var: BoundVar, - pub kind: BoundRegionKind, -} - -impl BoundRegionKind { - pub fn is_named(&self) -> bool { - match *self { - BoundRegionKind::BrNamed(_, name) => { - name != kw::UnderscoreLifetime && name != kw::Empty - } - _ => false, - } - } - - pub fn get_name(&self) -> Option { - if self.is_named() { - match *self { - BoundRegionKind::BrNamed(_, name) => return Some(name), - _ => unreachable!(), - } - } - - None - } - - pub fn get_id(&self) -> Option { - match *self { - BoundRegionKind::BrNamed(id, _) => return Some(id), - _ => None, - } - } -} - pub trait Article { fn article(&self) -> &'static str; } @@ -242,9 +167,15 @@ pub struct ClosureArgs<'tcx> { /// Struct returned by `split()`. pub struct ClosureArgsParts<'tcx> { + /// This is the args of the typeck root. pub parent_args: &'tcx [GenericArg<'tcx>], + /// Represents the maximum calling capability of the closure. pub closure_kind_ty: Ty<'tcx>, + /// Captures the closure's signature. This closure signature is "tupled", and + /// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`. pub closure_sig_as_fn_ptr_ty: Ty<'tcx>, + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: Ty<'tcx>, } @@ -277,15 +208,6 @@ impl<'tcx> ClosureArgs<'tcx> { } } - /// Returns `true` only if enough of the synthetic types are known to - /// allow using all of the methods on `ClosureArgs` without panicking. - /// - /// Used primarily by `ty::print::pretty` to be able to handle closure - /// types that haven't had their synthetic types substituted in. - pub fn is_valid(self) -> bool { - self.args.len() >= 3 && matches!(self.split().tupled_upvars_ty.kind(), Tuple(_)) - } - /// Returns the substitutions of the closure's parent. pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { self.split().parent_args @@ -296,9 +218,9 @@ impl<'tcx> ClosureArgs<'tcx> { /// empty iterator is returned. #[inline] pub fn upvar_tys(self) -> &'tcx List> { - match self.tupled_upvars_ty().kind() { + match *self.tupled_upvars_ty().kind() { TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), + TyKind::Tuple(tys) => tys, TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), } @@ -337,10 +259,9 @@ impl<'tcx> ClosureArgs<'tcx> { /// Extracts the signature from the closure. pub fn sig(self) -> ty::PolyFnSig<'tcx> { - let ty = self.sig_as_fn_ptr_ty(); - match ty.kind() { - ty::FnPtr(sig) => *sig, - _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()), + match *self.sig_as_fn_ptr_ty().kind() { + ty::FnPtr(sig) => sig, + ty => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"), } } @@ -349,6 +270,275 @@ impl<'tcx> ClosureArgs<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] +pub struct CoroutineClosureArgs<'tcx> { + pub args: GenericArgsRef<'tcx>, +} + +/// See docs for explanation of how each argument is used. +/// +/// See [`CoroutineClosureSignature`] for how these arguments are put together +/// to make a callable [`FnSig`] suitable for typeck and borrowck. +pub struct CoroutineClosureArgsParts<'tcx> { + /// This is the args of the typeck root. + pub parent_args: &'tcx [GenericArg<'tcx>], + /// Represents the maximum calling capability of the closure. + pub closure_kind_ty: Ty<'tcx>, + /// Represents all of the relevant parts of the coroutine returned by this + /// coroutine-closure. This signature parts type will have the general + /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where + /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the + /// coroutine returned by the coroutine-closure. + /// + /// Use `coroutine_closure_sig` to break up this type rather than using it + /// yourself. + pub signature_parts_ty: Ty<'tcx>, + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. + pub tupled_upvars_ty: Ty<'tcx>, + /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`. + /// This allows us to represent the binder of the self-captures of the closure. + /// + /// For example, if the coroutine returned by the closure borrows `String` + /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`, + /// while the `tupled_upvars_ty`, representing the by-move version of the same + /// captures, will be `(String,)`. + pub coroutine_captures_by_ref_ty: Ty<'tcx>, + /// Witness type returned by the generator produced by this coroutine-closure. + pub coroutine_witness_ty: Ty<'tcx>, +} + +impl<'tcx> CoroutineClosureArgs<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + parts: CoroutineClosureArgsParts<'tcx>, + ) -> CoroutineClosureArgs<'tcx> { + CoroutineClosureArgs { + args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.closure_kind_ty.into(), + parts.signature_parts_ty.into(), + parts.tupled_upvars_ty.into(), + parts.coroutine_captures_by_ref_ty.into(), + parts.coroutine_witness_ty.into(), + ])), + } + } + + fn split(self) -> CoroutineClosureArgsParts<'tcx> { + match self.args[..] { + [ + ref parent_args @ .., + closure_kind_ty, + signature_parts_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty, + ] => CoroutineClosureArgsParts { + parent_args, + closure_kind_ty: closure_kind_ty.expect_ty(), + signature_parts_ty: signature_parts_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), + coroutine_witness_ty: coroutine_witness_ty.expect_ty(), + }, + _ => bug!("closure args missing synthetics"), + } + } + + pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { + self.split().parent_args + } + + #[inline] + pub fn upvar_tys(self) -> &'tcx List> { + match self.tupled_upvars_ty().kind() { + TyKind::Error(_) => ty::List::empty(), + TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), + TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), + ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), + } + } + + #[inline] + pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + self.split().tupled_upvars_ty + } + + pub fn kind_ty(self) -> Ty<'tcx> { + self.split().closure_kind_ty + } + + pub fn kind(self) -> ty::ClosureKind { + self.kind_ty().to_opt_closure_kind().unwrap() + } + + pub fn signature_parts_ty(self) -> Ty<'tcx> { + self.split().signature_parts_ty + } + + pub fn coroutine_closure_sig(self) -> ty::Binder<'tcx, CoroutineClosureSignature<'tcx>> { + let interior = self.coroutine_witness_ty(); + let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() }; + sig.map_bound(|sig| { + let [resume_ty, tupled_inputs_ty] = *sig.inputs() else { + bug!(); + }; + let [yield_ty, return_ty] = **sig.output().tuple_fields() else { bug!() }; + CoroutineClosureSignature { + interior, + tupled_inputs_ty, + resume_ty, + yield_ty, + return_ty, + c_variadic: sig.c_variadic, + unsafety: sig.unsafety, + abi: sig.abi, + } + }) + } + + pub fn coroutine_captures_by_ref_ty(self) -> Ty<'tcx> { + self.split().coroutine_captures_by_ref_ty + } + + pub fn coroutine_witness_ty(self) -> Ty<'tcx> { + self.split().coroutine_witness_ty + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] +pub struct CoroutineClosureSignature<'tcx> { + pub interior: Ty<'tcx>, + pub tupled_inputs_ty: Ty<'tcx>, + pub resume_ty: Ty<'tcx>, + pub yield_ty: Ty<'tcx>, + pub return_ty: Ty<'tcx>, + + // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types + // never actually differ. But we save them rather than recreating them + // from scratch just for good measure. + /// Always false + pub c_variadic: bool, + /// Always [`hir::Unsafety::Normal`] + pub unsafety: hir::Unsafety, + /// Always [`abi::Abi::RustCall`] + pub abi: abi::Abi, +} + +impl<'tcx> CoroutineClosureSignature<'tcx> { + /// Construct a coroutine from the closure signature. Since a coroutine signature + /// is agnostic to the type of generator that is returned (by-ref/by-move), + /// the caller must specify what "flavor" of generator that they'd like to + /// create. Additionally, they must manually compute the upvars of the closure. + /// + /// This helper is not really meant to be used directly except for early on + /// during typeck, when we want to put inference vars into the kind and upvars tys. + /// When the kind and upvars are known, use the other helper functions. + pub fn to_coroutine( + self, + tcx: TyCtxt<'tcx>, + parent_args: &'tcx [GenericArg<'tcx>], + coroutine_kind_ty: Ty<'tcx>, + coroutine_def_id: DefId, + tupled_upvars_ty: Ty<'tcx>, + ) -> Ty<'tcx> { + let coroutine_args = ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args, + kind_ty: coroutine_kind_ty, + resume_ty: self.resume_ty, + yield_ty: self.yield_ty, + return_ty: self.return_ty, + witness: self.interior, + tupled_upvars_ty, + }, + ); + + Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) + } + + /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine + /// returned by that corresponding async fn trait. + /// + /// This function expects the upvars to have been computed already, and doesn't check + /// that the `ClosureKind` is actually supported by the coroutine-closure. + pub fn to_coroutine_given_kind_and_upvars( + self, + tcx: TyCtxt<'tcx>, + parent_args: &'tcx [GenericArg<'tcx>], + coroutine_def_id: DefId, + goal_kind: ty::ClosureKind, + env_region: ty::Region<'tcx>, + closure_tupled_upvars_ty: Ty<'tcx>, + coroutine_captures_by_ref_ty: Ty<'tcx>, + ) -> Ty<'tcx> { + let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( + tcx, + goal_kind, + self.tupled_inputs_ty, + closure_tupled_upvars_ty, + coroutine_captures_by_ref_ty, + env_region, + ); + + self.to_coroutine( + tcx, + parent_args, + Ty::from_closure_kind(tcx, goal_kind), + coroutine_def_id, + tupled_upvars_ty, + ) + } + + /// Compute the tupled upvars that a coroutine-closure's output coroutine + /// would return for the given `ClosureKind`. + /// + /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref" + /// to return a set of upvars which are borrowed with the given `env_region`. + /// + /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars' + /// lifetimes are related to the lifetime of the borrow on the closure made for + /// the call. This allows borrowck to enforce the self-borrows correctly. + pub fn tupled_upvars_by_closure_kind( + tcx: TyCtxt<'tcx>, + kind: ty::ClosureKind, + tupled_inputs_ty: Ty<'tcx>, + closure_tupled_upvars_ty: Ty<'tcx>, + coroutine_captures_by_ref_ty: Ty<'tcx>, + env_region: ty::Region<'tcx>, + ) -> Ty<'tcx> { + match kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + let ty::FnPtr(sig) = *coroutine_captures_by_ref_ty.kind() else { + bug!(); + }; + let coroutine_captures_by_ref_ty = tcx.replace_escaping_bound_vars_uncached( + sig.output().skip_binder(), + FnMutDelegate { + consts: &mut |c, t| ty::Const::new_bound(tcx, ty::INNERMOST, c, t), + types: &mut |t| Ty::new_bound(tcx, ty::INNERMOST, t), + regions: &mut |_| env_region, + }, + ); + Ty::new_tup_from_iter( + tcx, + tupled_inputs_ty + .tuple_fields() + .iter() + .chain(coroutine_captures_by_ref_ty.tuple_fields()), + ) + } + ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( + tcx, + tupled_inputs_ty + .tuple_fields() + .iter() + .chain(closure_tupled_upvars_ty.tuple_fields()), + ), + } + } +} /// Similar to `ClosureArgs`; see the above documentation for more. #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] pub struct CoroutineArgs<'tcx> { @@ -356,11 +546,31 @@ pub struct CoroutineArgs<'tcx> { } pub struct CoroutineArgsParts<'tcx> { + /// This is the args of the typeck root. pub parent_args: &'tcx [GenericArg<'tcx>], + + /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut` + /// implementations must be distinguished since the former takes the closure's + /// upvars by move, and the latter takes the closure's upvars by ref. + /// + /// This field distinguishes these fields so that codegen can select the right + /// body for the coroutine. This has the same type representation as the closure + /// kind: `i8`/`i16`/`i32`. + /// + /// For regular coroutines, this field will always just be `()`. + pub kind_ty: Ty<'tcx>, + pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, + + /// The interior type of the coroutine. + /// Represents all types that are stored in locals + /// in the coroutine's body. pub witness: Ty<'tcx>, + + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: Ty<'tcx>, } @@ -370,6 +580,7 @@ impl<'tcx> CoroutineArgs<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, parts: CoroutineArgsParts<'tcx>) -> CoroutineArgs<'tcx> { CoroutineArgs { args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.kind_ty.into(), parts.resume_ty.into(), parts.yield_ty.into(), parts.return_ty.into(), @@ -383,34 +594,37 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The ordering assumed here must match that used by `CoroutineArgs::new` above. fn split(self) -> CoroutineArgsParts<'tcx> { match self.args[..] { - [ref parent_args @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { - CoroutineArgsParts { - parent_args, - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - } - } + [ + ref parent_args @ .., + kind_ty, + resume_ty, + yield_ty, + return_ty, + witness, + tupled_upvars_ty, + ] => CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + witness: witness.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + }, _ => bug!("coroutine args missing synthetics"), } } - /// Returns `true` only if enough of the synthetic types are known to - /// allow using all of the methods on `CoroutineArgs` without panicking. - /// - /// Used primarily by `ty::print::pretty` to be able to handle coroutine - /// types that haven't had their synthetic types substituted in. - pub fn is_valid(self) -> bool { - self.args.len() >= 5 && matches!(self.split().tupled_upvars_ty.kind(), Tuple(_)) - } - /// Returns the substitutions of the coroutine's parent. pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { self.split().parent_args } + // Returns the kind of the coroutine. See docs on the `kind_ty` field. + pub fn kind_ty(self) -> Ty<'tcx> { + self.split().kind_ty + } + /// This describes the types that can be contained in a coroutine. /// It will be a type variable initially and unified in the last stages of typeck of a body. /// It contains a tuple of all the types that could end up on a coroutine frame. @@ -425,9 +639,9 @@ impl<'tcx> CoroutineArgs<'tcx> { /// empty iterator is returned. #[inline] pub fn upvar_tys(self) -> &'tcx List> { - match self.tupled_upvars_ty().kind() { + match *self.tupled_upvars_ty().kind() { TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), + TyKind::Tuple(tys) => tys, TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), } @@ -562,6 +776,7 @@ impl<'tcx> CoroutineArgs<'tcx> { pub enum UpvarArgs<'tcx> { Closure(GenericArgsRef<'tcx>), Coroutine(GenericArgsRef<'tcx>), + CoroutineClosure(GenericArgsRef<'tcx>), } impl<'tcx> UpvarArgs<'tcx> { @@ -573,6 +788,7 @@ impl<'tcx> UpvarArgs<'tcx> { let tupled_tys = match self { UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(), UpvarArgs::Coroutine(args) => args.as_coroutine().tupled_upvars_ty(), + UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().tupled_upvars_ty(), }; match tupled_tys.kind() { @@ -588,6 +804,7 @@ impl<'tcx> UpvarArgs<'tcx> { match self { UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(), UpvarArgs::Coroutine(args) => args.as_coroutine().tupled_upvars_ty(), + UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().tupled_upvars_ty(), } } } @@ -652,290 +869,6 @@ impl<'tcx> InlineConstArgs<'tcx> { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum ExistentialPredicate<'tcx> { - /// E.g., `Iterator`. - Trait(ExistentialTraitRef<'tcx>), - /// E.g., `Iterator::Item = T`. - Projection(ExistentialProjection<'tcx>), - /// E.g., `Send`. - AutoTrait(DefId), -} - -impl<'tcx> DebugWithInfcx> for ExistentialPredicate<'tcx> { - fn fmt>>( - this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - fmt::Debug::fmt(&this.data, f) - } -} - -impl<'tcx> ExistentialPredicate<'tcx> { - /// Compares via an ordering that will not change if modules are reordered or other changes are - /// made to the tree. In particular, this ordering is preserved across incremental compilations. - pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering { - use self::ExistentialPredicate::*; - match (*self, *other) { - (Trait(_), Trait(_)) => Ordering::Equal, - (Projection(ref a), Projection(ref b)) => { - tcx.def_path_hash(a.def_id).cmp(&tcx.def_path_hash(b.def_id)) - } - (AutoTrait(ref a), AutoTrait(ref b)) => { - tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b)) - } - (Trait(_), _) => Ordering::Less, - (Projection(_), Trait(_)) => Ordering::Greater, - (Projection(_), _) => Ordering::Less, - (AutoTrait(_), _) => Ordering::Greater, - } - } -} - -pub type PolyExistentialPredicate<'tcx> = Binder<'tcx, ExistentialPredicate<'tcx>>; - -impl<'tcx> PolyExistentialPredicate<'tcx> { - /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), - /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` - /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> { - use crate::ty::ToPredicate; - match self.skip_binder() { - ExistentialPredicate::Trait(tr) => { - self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx) - } - ExistentialPredicate::Projection(p) => { - self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) - } - ExistentialPredicate::AutoTrait(did) => { - let generics = tcx.generics_of(did); - let trait_ref = if generics.params.len() == 1 { - ty::TraitRef::new(tcx, did, [self_ty]) - } else { - // If this is an ill-formed auto trait, then synthesize - // new error args for the missing generics. - let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]); - ty::TraitRef::new(tcx, did, err_args) - }; - self.rebind(trait_ref).to_predicate(tcx) - } - } - } -} - -impl<'tcx> List> { - /// Returns the "principal `DefId`" of this set of existential predicates. - /// - /// A Rust trait object type consists (in addition to a lifetime bound) - /// of a set of trait bounds, which are separated into any number - /// of auto-trait bounds, and at most one non-auto-trait bound. The - /// non-auto-trait bound is called the "principal" of the trait - /// object. - /// - /// Only the principal can have methods or type parameters (because - /// auto traits can have neither of them). This is important, because - /// it means the auto traits can be treated as an unordered set (methods - /// would force an order for the vtable, while relating traits with - /// type parameters without knowing the order to relate them in is - /// a rather non-trivial task). - /// - /// For example, in the trait object `dyn fmt::Debug + Sync`, the - /// principal bound is `Some(fmt::Debug)`, while the auto-trait bounds - /// are the set `{Sync}`. - /// - /// It is also possible to have a "trivial" trait object that - /// consists only of auto traits, with no principal - for example, - /// `dyn Send + Sync`. In that case, the set of auto-trait bounds - /// is `{Send, Sync}`, while there is no principal. These trait objects - /// have a "trivial" vtable consisting of just the size, alignment, - /// and destructor. - pub fn principal(&self) -> Option>> { - self[0] - .map_bound(|this| match this { - ExistentialPredicate::Trait(tr) => Some(tr), - _ => None, - }) - .transpose() - } - - pub fn principal_def_id(&self) -> Option { - self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) - } - - #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator>> + 'a { - self.iter().filter_map(|predicate| { - predicate - .map_bound(|pred| match pred { - ExistentialPredicate::Projection(projection) => Some(projection), - _ => None, - }) - .transpose() - }) - } - - #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + Captures<'tcx> + 'a { - self.iter().filter_map(|predicate| match predicate.skip_binder() { - ExistentialPredicate::AutoTrait(did) => Some(did), - _ => None, - }) - } -} - -/// A complete reference to a trait. These take numerous guises in syntax, -/// but perhaps the most recognizable form is in a where-clause: -/// ```ignore (illustrative) -/// T: Foo -/// ``` -/// This would be represented by a trait-reference where the `DefId` is the -/// `DefId` for the trait `Foo` and the args define `T` as parameter 0, -/// and `U` as parameter 1. -/// -/// Trait references also appear in object types like `Foo`, but in -/// that case the `Self` parameter is absent from the substitutions. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct TraitRef<'tcx> { - pub def_id: DefId, - pub args: GenericArgsRef<'tcx>, - /// This field exists to prevent the creation of `TraitRef` without - /// calling [`TraitRef::new`]. - pub(super) _use_trait_ref_new_instead: (), -} - -impl<'tcx> TraitRef<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - args: impl IntoIterator>>, - ) -> Self { - let args = tcx.check_and_mk_args(trait_def_id, args); - Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () } - } - - pub fn from_lang_item( - tcx: TyCtxt<'tcx>, - trait_lang_item: LangItem, - span: Span, - args: impl IntoIterator>>, - ) -> Self { - let trait_def_id = tcx.require_lang_item(trait_lang_item, Some(span)); - Self::new(tcx, trait_def_id, args) - } - - pub fn from_method( - tcx: TyCtxt<'tcx>, - trait_id: DefId, - args: GenericArgsRef<'tcx>, - ) -> ty::TraitRef<'tcx> { - let defs = tcx.generics_of(trait_id); - ty::TraitRef::new(tcx, trait_id, tcx.mk_args(&args[..defs.params.len()])) - } - - /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` - /// are the parameters defined on trait. - pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { - ty::TraitRef::new(tcx, def_id, GenericArgs::identity_for_item(tcx, def_id)) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - ty::TraitRef::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args.iter().skip(1)), - ) - } - - #[inline] - pub fn self_ty(&self) -> Ty<'tcx> { - self.args.type_at(0) - } -} - -pub type PolyTraitRef<'tcx> = Binder<'tcx, TraitRef<'tcx>>; - -impl<'tcx> PolyTraitRef<'tcx> { - pub fn self_ty(&self) -> Binder<'tcx, Ty<'tcx>> { - self.map_bound_ref(|tr| tr.self_ty()) - } - - pub fn def_id(&self) -> DefId { - self.skip_binder().def_id - } -} - -impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } -} - -/// An existential reference to a trait, where `Self` is erased. -/// For example, the trait object `Trait<'a, 'b, X, Y>` is: -/// ```ignore (illustrative) -/// exists T. T: Trait<'a, 'b, X, Y> -/// ``` -/// The substitutions don't include the erased `Self`, only trait -/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct ExistentialTraitRef<'tcx> { - pub def_id: DefId, - pub args: GenericArgsRef<'tcx>, -} - -impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn erase_self_ty( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - ) -> ty::ExistentialTraitRef<'tcx> { - // Assert there is a Self. - trait_ref.args.type_at(0); - - ty::ExistentialTraitRef { - def_id: trait_ref.def_id, - args: tcx.mk_args(&trait_ref.args[1..]), - } - } - - /// Object types don't have a self type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self type. A common choice is `mk_err()` - /// or some placeholder type. - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { - // otherwise the escaping vars would be captured by the binder - // debug_assert!(!self_ty.has_escaping_bound_vars()); - - ty::TraitRef::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter())) - } -} - -impl<'tcx> IntoDiagnosticArg for ExistentialTraitRef<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } -} - -pub type PolyExistentialTraitRef<'tcx> = Binder<'tcx, ExistentialTraitRef<'tcx>>; - -impl<'tcx> PolyExistentialTraitRef<'tcx> { - pub fn def_id(&self) -> DefId { - self.skip_binder().def_id - } - - /// Object types don't have a self type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self type. A common choice is `mk_err()` - /// or some placeholder type. - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> { - self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) - } -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundVariableKind { @@ -1156,7 +1089,7 @@ impl<'tcx, T> IntoDiagnosticArg for Binder<'tcx, T> where T: IntoDiagnosticArg, { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.value.into_diagnostic_arg() } } @@ -1366,7 +1299,7 @@ impl<'tcx> FnSig<'tcx> { } impl<'tcx> IntoDiagnosticArg for FnSig<'tcx> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -1459,154 +1392,6 @@ impl ParamConst { } } -/// Use this rather than `RegionKind`, whenever possible. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] -#[rustc_pass_by_value] -pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); - -impl<'tcx> IntoKind for Region<'tcx> { - type Kind = RegionKind<'tcx>; - - fn kind(self) -> RegionKind<'tcx> { - *self - } -} - -impl<'tcx> Region<'tcx> { - #[inline] - pub fn new_early_param( - tcx: TyCtxt<'tcx>, - early_bound_region: ty::EarlyParamRegion, - ) -> Region<'tcx> { - tcx.intern_region(ty::ReEarlyParam(early_bound_region)) - } - - #[inline] - pub fn new_bound( - tcx: TyCtxt<'tcx>, - debruijn: ty::DebruijnIndex, - bound_region: ty::BoundRegion, - ) -> Region<'tcx> { - // Use a pre-interned one when possible. - if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region - && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) - && let Some(re) = inner.get(var.as_usize()).copied() - { - re - } else { - tcx.intern_region(ty::ReBound(debruijn, bound_region)) - } - } - - #[inline] - pub fn new_late_param( - tcx: TyCtxt<'tcx>, - scope: DefId, - bound_region: ty::BoundRegionKind, - ) -> Region<'tcx> { - tcx.intern_region(ty::ReLateParam(ty::LateParamRegion { scope, bound_region })) - } - - #[inline] - pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { - // Use a pre-interned one when possible. - tcx.lifetimes - .re_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) - } - - #[inline] - pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { - tcx.intern_region(ty::RePlaceholder(placeholder)) - } - - /// Constructs a `RegionKind::ReError` region. - #[track_caller] - pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> { - tcx.intern_region(ty::ReError(reported)) - } - - /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it - /// gets used. - #[track_caller] - pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { - Region::new_error_with_message( - tcx, - DUMMY_SP, - "RegionKind::ReError constructed but no error reported", - ) - } - - /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given - /// `msg` to ensure it gets used. - #[track_caller] - pub fn new_error_with_message>( - tcx: TyCtxt<'tcx>, - span: S, - msg: &'static str, - ) -> Region<'tcx> { - let reported = tcx.dcx().span_delayed_bug(span, msg); - Region::new_error(tcx, reported) - } - - /// Avoid this in favour of more specific `new_*` methods, where possible, - /// to avoid the cost of the `match`. - pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { - match kind { - ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), - ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region), - ty::ReLateParam(ty::LateParamRegion { scope, bound_region }) => { - Region::new_late_param(tcx, scope, bound_region) - } - ty::ReStatic => tcx.lifetimes.re_static, - ty::ReVar(vid) => Region::new_var(tcx, vid), - ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), - ty::ReErased => tcx.lifetimes.re_erased, - ty::ReError(reported) => Region::new_error(tcx, reported), - } - } -} - -impl<'tcx> Deref for Region<'tcx> { - type Target = RegionKind<'tcx>; - - #[inline] - fn deref(&self) -> &RegionKind<'tcx> { - self.0.0 - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] -#[derive(HashStable)] -pub struct EarlyParamRegion { - pub def_id: DefId, - pub index: u32, - pub name: Symbol, -} - -impl fmt::Debug for EarlyParamRegion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) - } -} - -rustc_index::newtype_index! { - /// A **region** (lifetime) **v**ariable **ID**. - #[derive(HashStable)] - #[encodable] - #[orderable] - #[debug_format = "'?{}"] - pub struct RegionVid {} -} - -impl Atom for RegionVid { - fn index(self) -> usize { - Idx::index(self) - } -} - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct BoundTy { @@ -1627,251 +1412,6 @@ impl From for BoundTy { } } -/// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct ExistentialProjection<'tcx> { - pub def_id: DefId, - pub args: GenericArgsRef<'tcx>, - pub term: Term<'tcx>, -} - -pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>; - -impl<'tcx> ExistentialProjection<'tcx> { - /// Extracts the underlying existential trait reference from this projection. - /// For example, if this is a projection of `exists T. ::Item == X`, - /// then this function would return an `exists T. T: Iterator` existential trait - /// reference. - pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> { - let def_id = tcx.parent(self.def_id); - let subst_count = tcx.generics_of(def_id).count() - 1; - let args = tcx.mk_args(&self.args[..subst_count]); - ty::ExistentialTraitRef { def_id, args } - } - - pub fn with_self_ty( - &self, - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - ) -> ty::ProjectionPredicate<'tcx> { - // otherwise the escaping regions would be captured by the binders - debug_assert!(!self_ty.has_escaping_bound_vars()); - - ty::ProjectionPredicate { - projection_ty: AliasTy::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args), - ), - term: self.term, - } - } - - pub fn erase_self_ty( - tcx: TyCtxt<'tcx>, - projection_predicate: ty::ProjectionPredicate<'tcx>, - ) -> Self { - // Assert there is a Self. - projection_predicate.projection_ty.args.type_at(0); - - Self { - def_id: projection_predicate.projection_ty.def_id, - args: tcx.mk_args(&projection_predicate.projection_ty.args[1..]), - term: projection_predicate.term, - } - } -} - -impl<'tcx> PolyExistentialProjection<'tcx> { - pub fn with_self_ty( - &self, - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - ) -> ty::PolyProjectionPredicate<'tcx> { - self.map_bound(|p| p.with_self_ty(tcx, self_ty)) - } - - pub fn item_def_id(&self) -> DefId { - self.skip_binder().def_id - } -} - -/// Region utilities -impl<'tcx> Region<'tcx> { - pub fn kind(self) -> RegionKind<'tcx> { - *self.0.0 - } - - pub fn get_name(self) -> Option { - if self.has_name() { - match *self { - ty::ReEarlyParam(ebr) => Some(ebr.name), - ty::ReBound(_, br) => br.kind.get_name(), - ty::ReLateParam(fr) => fr.bound_region.get_name(), - ty::ReStatic => Some(kw::StaticLifetime), - ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), - _ => None, - } - } else { - None - } - } - - pub fn get_name_or_anon(self) -> Symbol { - match self.get_name() { - Some(name) => name, - None => sym::anon, - } - } - - /// Is this region named by the user? - pub fn has_name(self) -> bool { - match *self { - ty::ReEarlyParam(ebr) => ebr.has_name(), - ty::ReBound(_, br) => br.kind.is_named(), - ty::ReLateParam(fr) => fr.bound_region.is_named(), - ty::ReStatic => true, - ty::ReVar(..) => false, - ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), - ty::ReErased => false, - ty::ReError(_) => false, - } - } - - #[inline] - pub fn is_error(self) -> bool { - matches!(*self, ty::ReError(_)) - } - - #[inline] - pub fn is_static(self) -> bool { - matches!(*self, ty::ReStatic) - } - - #[inline] - pub fn is_erased(self) -> bool { - matches!(*self, ty::ReErased) - } - - #[inline] - pub fn is_bound(self) -> bool { - matches!(*self, ty::ReBound(..)) - } - - #[inline] - pub fn is_placeholder(self) -> bool { - matches!(*self, ty::RePlaceholder(..)) - } - - #[inline] - pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { - match *self { - ty::ReBound(debruijn, _) => debruijn >= index, - _ => false, - } - } - - pub fn type_flags(self) -> TypeFlags { - let mut flags = TypeFlags::empty(); - - match *self { - ty::ReVar(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; - flags = flags | TypeFlags::HAS_RE_INFER; - } - ty::RePlaceholder(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; - flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; - } - ty::ReEarlyParam(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; - flags = flags | TypeFlags::HAS_RE_PARAM; - } - ty::ReLateParam { .. } => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; - } - ty::ReStatic => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - } - ty::ReBound(..) => { - flags = flags | TypeFlags::HAS_RE_BOUND; - } - ty::ReErased => { - flags = flags | TypeFlags::HAS_RE_ERASED; - } - ty::ReError(_) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - } - } - - debug!("type_flags({:?}) = {:?}", self, flags); - - flags - } - - /// Given an early-bound or free region, returns the `DefId` where it was bound. - /// For example, consider the regions in this snippet of code: - /// - /// ```ignore (illustrative) - /// impl<'a> Foo { - /// // ^^ -- early bound, declared on an impl - /// - /// fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c - /// // ^^ ^^ ^ anonymous, late-bound - /// // | early-bound, appears in where-clauses - /// // late-bound, appears only in fn args - /// {..} - /// } - /// ``` - /// - /// Here, `free_region_binding_scope('a)` would return the `DefId` - /// of the impl, and for all the other highlighted regions, it - /// would return the `DefId` of the function. In other cases (not shown), this - /// function might return the `DefId` of a closure. - pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId { - match *self { - ty::ReEarlyParam(br) => tcx.parent(br.def_id), - ty::ReLateParam(fr) => fr.scope, - _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), - } - } - - /// True for free regions other than `'static`. - pub fn is_param(self) -> bool { - matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_)) - } - - /// True for free region in the current context. - /// - /// This is the case for `'static` and param regions. - pub fn is_free(self) -> bool { - match *self { - ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true, - ty::ReVar(..) - | ty::RePlaceholder(..) - | ty::ReBound(..) - | ty::ReErased - | ty::ReError(..) => false, - } - } - - pub fn is_var(self) -> bool { - matches!(self.kind(), ty::ReVar(_)) - } - - pub fn as_var(self) -> RegionVid { - match self.kind() { - ty::ReVar(vid) => vid, - _ => bug!("expected region {:?} to be of kind ReVar", self), - } - } -} - /// Constructors for `Ty` impl<'tcx> Ty<'tcx> { // Avoid this in favour of more specific `new_*` methods, where possible. @@ -2123,7 +1663,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_dynamic( tcx: TyCtxt<'tcx>, - obj: &'tcx List>, + obj: &'tcx List>, reg: ty::Region<'tcx>, repr: DynKind, ) -> Ty<'tcx> { @@ -2153,6 +1693,20 @@ impl<'tcx> Ty<'tcx> { Ty::new(tcx, Closure(def_id, closure_args)) } + #[inline] + pub fn new_coroutine_closure( + tcx: TyCtxt<'tcx>, + def_id: DefId, + closure_args: GenericArgsRef<'tcx>, + ) -> Ty<'tcx> { + debug_assert_eq!( + closure_args.len(), + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, + "closure constructed with incorrect substitutions" + ); + Ty::new(tcx, CoroutineClosure(def_id, closure_args)) + } + #[inline] pub fn new_coroutine( tcx: TyCtxt<'tcx>, @@ -2161,7 +1715,7 @@ impl<'tcx> Ty<'tcx> { ) -> Ty<'tcx> { debug_assert_eq!( coroutine_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6, "coroutine constructed with incorrect number of substitutions" ); Ty::new(tcx, Coroutine(def_id, coroutine_args)) @@ -2487,6 +2041,11 @@ impl<'tcx> Ty<'tcx> { matches!(self.kind(), Coroutine(..)) } + #[inline] + pub fn is_coroutine_closure(self) -> bool { + matches!(self.kind(), CoroutineClosure(..)) + } + #[inline] pub fn is_integral(self) -> bool { matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_)) @@ -2555,7 +2114,7 @@ impl<'tcx> Ty<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let ty::Closure(_, _) = t.kind() { + if let ty::Closure(..) = t.kind() { ControlFlow::Break(()) } else { t.super_visit_with(self) @@ -2702,6 +2261,7 @@ impl<'tcx> Ty<'tcx> { | ty::FnPtr(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) @@ -2740,6 +2300,7 @@ impl<'tcx> Ty<'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Error(_) // Extern types have metadata = (). @@ -2794,7 +2355,7 @@ impl<'tcx> Ty<'tcx> { // "Bound" types appear in canonical queries when the // closure type is not yet known - Bound(..) | Infer(_) => None, + Bound(..) | Param(_) | Infer(_) => None, Error(_) => Some(ty::ClosureKind::Fn), @@ -2837,6 +2398,7 @@ impl<'tcx> Ty<'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Error(_) => true, @@ -2900,7 +2462,7 @@ impl<'tcx> Ty<'tcx> { ty::Coroutine(..) | ty::CoroutineWitness(..) => false, // Might be, but not "trivial" so just giving the safe answer. - ty::Adt(..) | ty::Closure(..) => false, + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) => false, // Needs normalization or revealing to determine, so no is the safe answer. ty::Alias(..) => false, @@ -2972,6 +2534,7 @@ impl<'tcx> Ty<'tcx> { | FnPtr(_) | Dynamic(_, _, _) | Closure(_, _) + | CoroutineClosure(_, _) | Coroutine(_, _) | CoroutineWitness(..) | Never @@ -3024,7 +2587,7 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(RegionKind<'_>, 24); - static_assert_size!(TyKind<'_>, 32); + static_assert_size!(ty::RegionKind<'_>, 24); + static_assert_size!(ty::TyKind<'_>, 32); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ef621f29bfd71..4feaeb0dd0523 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -350,7 +350,7 @@ impl<'tcx> TyCtxt<'tcx> { validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let drop_trait = self.lang_items().drop_trait()?; - self.ensure().coherent_trait(drop_trait); + self.ensure().coherent_trait(drop_trait).ok()?; let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; @@ -1119,6 +1119,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(..) | ty::Bound(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Dynamic(..) | ty::Foreign(_) | ty::Coroutine(..) @@ -1158,6 +1159,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(..) | ty::Bound(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Dynamic(..) | ty::Foreign(_) | ty::Coroutine(..) @@ -1249,19 +1251,18 @@ impl<'tcx> Ty<'tcx> { /// Primitive types (`u32`, `str`) have structural equality by definition. For composite data /// types, equality for the type as a whole is structural when it is the same as equality /// between all components (fields, array elements, etc.) of that type. For ADTs, structural - /// equality is indicated by an implementation of `PartialStructuralEq` and `StructuralEq` for - /// that type. + /// equality is indicated by an implementation of `StructuralPartialEq` for that type. /// /// This function is "shallow" because it may return `true` for a composite type whose fields - /// are not `StructuralEq`. For example, `[T; 4]` has structural equality regardless of `T` + /// are not `StructuralPartialEq`. For example, `[T; 4]` has structural equality regardless of `T` /// because equality for arrays is determined by the equality of each array element. If you /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way /// down, you will need to use a type visitor. #[inline] pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { - // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. - ty::Adt(..) => tcx.has_structural_eq_impls(self), + // Look for an impl of `StructuralPartialEq`. + ty::Adt(..) => tcx.has_structural_eq_impl(self), // Primitive types that satisfy `Eq`. ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => true, @@ -1281,7 +1282,11 @@ impl<'tcx> Ty<'tcx> { // Conservatively return `false` for all others... // Anonymous function types - ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Coroutine(..) => false, + ty::FnDef(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Dynamic(..) + | ty::Coroutine(..) => false, // Generic or inferred types // @@ -1425,6 +1430,7 @@ pub fn needs_drop_components<'tcx>( | ty::Placeholder(..) | ty::Infer(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => Ok(smallvec![ty]), } @@ -1457,7 +1463,11 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { // Not trivial because they have components, and instead of looking inside, // we'll just perform trait selection. - ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Adt(..) => false, + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Adt(..) => false, ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 1f8978aa8633d..a750a86d25707 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -55,10 +55,13 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable> { } fn error_reported(&self) -> Result<(), ErrorGuaranteed> { if self.references_error() { - if let Some(reported) = ty::tls::with(|tcx| tcx.dcx().is_compilation_going_to_fail()) { + // We must include lint errors and span delayed bugs here. + if let Some(reported) = + ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()) + { Err(reported) } else { - bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`"); + bug!("expected some kind of error in `error_reported`"); } } else { Ok(()) diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 9050716db9d38..46c26241c3e78 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -189,6 +189,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } ty::Adt(_, args) | ty::Closure(_, args) + | ty::CoroutineClosure(_, args) | ty::Coroutine(_, args) | ty::CoroutineWitness(_, args) | ty::FnDef(_, args) => { diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 6a03bf243eb46..27b48f46e75a2 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,7 +1,7 @@ use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::Representability; diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 615b553434fe6..8a6ccdb857829 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -107,10 +107,8 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior .label = use of extern static -mir_build_float_pattern = floating-point types cannot be used in patterns - mir_build_indirect_structural_match = - to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]` mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant @@ -232,8 +230,17 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa .note = mutating layout constrained fields cannot statically be checked for valid values .label = mutation of layout constrained field +mir_build_nan_pattern = cannot use NaN in patterns + .note = NaNs compare inequal to everything, even themselves, so this pattern would never match + .help = try using the `is_nan` method instead + mir_build_non_const_path = runtime values cannot be referenced in patterns +mir_build_non_empty_never_pattern = + mismatched types + .label = a never pattern must be used on an uninhabited type + .note = the matched value is of type `{$ty}` + mir_build_non_exhaustive_match_all_arms_guarded = match arms with guards don't count towards exhaustivity @@ -249,7 +256,7 @@ mir_build_non_partial_eq_match = to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq` mir_build_nontrivial_structural_match = - to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]` mir_build_pattern_not_covered = refutable pattern in {$origin} .pattern_ty = the matched value is of type `{$pattern_ty}` @@ -292,9 +299,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> } into the body mir_build_type_not_structural = - to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]` -mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 5428333a11611..c669d3fd6230d 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -20,6 +20,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { @call(mir_storage_dead, args) => { Ok(StatementKind::StorageDead(self.parse_local(args[0])?)) }, + @call(mir_assume, args) => { + let op = self.parse_operand(args[0])?; + Ok(StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(op)))) + }, @call(mir_deinit, args) => { Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?))) }, diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 5721957037e82..6636f75d99811 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -153,7 +153,7 @@ fn lit_to_mir_constant<'tcx>( ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) } (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { - trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? + trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })? } (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg) .ok_or_else(|| { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 6e8af7bb6df6c..c77f4a06d0569 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -483,6 +483,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { UpvarArgs::Closure(args) => { Box::new(AggregateKind::Closure(closure_id.to_def_id(), args)) } + UpvarArgs::CoroutineClosure(args) => { + Box::new(AggregateKind::CoroutineClosure(closure_id.to_def_id(), args)) + } }; block.and(Rvalue::Aggregate(result, operands)) } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a7f6f4873e383..065c93e86a866 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,7 +15,9 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::thir::{self, *}; +use rustc_middle::ty; use std::mem; @@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, ascription: thir::Ascription { ref annotation, variance }, } => { - // Apply the type ascription to the value at `match_pair.place`, which is the + // Apply the type ascription to the value at `match_pair.place` if let Some(source) = match_pair.place.try_to_place(self) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), @@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatKind::InlineConstant { subpattern: ref pattern, def: _ } => { + PatKind::InlineConstant { subpattern: ref pattern, def } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + if let Some(source) = match_pair.place.try_to_place(self) { + let span = match_pair.pattern.span; + let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + self.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id), + ty: self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }), + }, + ) + .args; + let user_ty = + self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + candidate.ascriptions.push(Ascription { + annotation, + source, + variance: ty::Contravariant, + }); + } candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); Ok(()) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 714c5f2686eb5..9a2f2ceced1ed 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -495,7 +495,7 @@ fn construct_fn<'tcx>( args.as_coroutine().yield_ty(), args.as_coroutine().resume_ty(), ))), - ty::Closure(..) | ty::FnDef(..) => None, + ty::Closure(..) | ty::CoroutineClosure(..) | ty::FnDef(..) => None, ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"), }; @@ -822,6 +822,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let upvar_args = match closure_ty.kind() { ty::Closure(_, args) => ty::UpvarArgs::Closure(args), ty::Coroutine(_, args) => ty::UpvarArgs::Coroutine(args), + ty::CoroutineClosure(_, args) => ty::UpvarArgs::CoroutineClosure(args), _ => return, }; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index b4a02fae4544b..8688c58906331 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -583,7 +583,7 @@ impl UnsafeOpKind { suggest_unsafe_block: bool, ) { let parent_id = tcx.hir().get_parent_item(hir_id); - let parent_owner = tcx.hir().owner(parent_id); + let parent_owner = tcx.hir_owner_node(parent_id); let should_suggest = parent_owner.fn_sig().is_some_and(|sig| sig.header.is_unsafe()); let unsafe_not_inherited_note = if should_suggest { suggest_unsafe_block.then(|| { @@ -599,17 +599,17 @@ impl UnsafeOpKind { // FIXME: ideally we would want to trim the def paths, but this is not // feasible with the current lint emission API (see issue #106126). match self { - CallToUnsafeFunction(Some(did)) => tcx.emit_spanned_lint( + CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { span, - function: &with_no_trimmed_paths!(tcx.def_path_str(*did)), + function: with_no_trimmed_paths!(tcx.def_path_str(*did)), unsafe_not_inherited_note, }, ), - CallToUnsafeFunction(None) => tcx.emit_spanned_lint( + CallToUnsafeFunction(None) => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -618,7 +618,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfInlineAssembly => tcx.emit_spanned_lint( + UseOfInlineAssembly => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -627,7 +627,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - InitializingTypeWith => tcx.emit_spanned_lint( + InitializingTypeWith => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -636,7 +636,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfMutableStatic => tcx.emit_spanned_lint( + UseOfMutableStatic => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -645,7 +645,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfExternStatic => tcx.emit_spanned_lint( + UseOfExternStatic => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -654,7 +654,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - DerefOfRawPointer => tcx.emit_spanned_lint( + DerefOfRawPointer => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -663,7 +663,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - AccessToUnionField => tcx.emit_spanned_lint( + AccessToUnionField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -672,7 +672,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - MutationOfLayoutConstrainedField => tcx.emit_spanned_lint( + MutationOfLayoutConstrainedField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -681,7 +681,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint( + BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -690,20 +690,23 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToFunctionWith { function, missing, build_enabled } => tcx.emit_spanned_lint( + CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { span, - function: &with_no_trimmed_paths!(tcx.def_path_str(*function)), + function: with_no_trimmed_paths!(tcx.def_path_str(*function)), missing_target_features: DiagnosticArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), missing_target_features_count: missing.len(), note: if build_enabled.is_empty() { None } else { Some(()) }, build_target_features: DiagnosticArgValue::StrListSepByAnd( - build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + build_enabled + .iter() + .map(|feature| Cow::from(feature.to_string())) + .collect(), ), build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, @@ -747,14 +750,14 @@ impl UnsafeOpKind { dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span, unsafe_not_inherited_note, - function: &tcx.def_path_str(*did), + function: tcx.def_path_str(*did), }); } CallToUnsafeFunction(Some(did)) => { dcx.emit_err(CallToUnsafeFunctionRequiresUnsafe { span, unsafe_not_inherited_note, - function: &tcx.def_path_str(*did), + function: tcx.def_path_str(*did), }); } CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => { @@ -860,32 +863,38 @@ impl UnsafeOpKind { dcx.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span, missing_target_features: DiagnosticArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), missing_target_features_count: missing.len(), note: if build_enabled.is_empty() { None } else { Some(()) }, build_target_features: DiagnosticArgValue::StrListSepByAnd( - build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + build_enabled + .iter() + .map(|feature| Cow::from(feature.to_string())) + .collect(), ), build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, - function: &tcx.def_path_str(*function), + function: tcx.def_path_str(*function), }); } CallToFunctionWith { function, missing, build_enabled } => { dcx.emit_err(CallToFunctionWithRequiresUnsafe { span, missing_target_features: DiagnosticArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), missing_target_features_count: missing.len(), note: if build_enabled.is_empty() { None } else { Some(()) }, build_target_features: DiagnosticArgValue::StrListSepByAnd( - build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + build_enabled + .iter() + .map(|feature| Cow::from(feature.to_string())) + .collect(), ), build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, - function: &tcx.def_path_str(*function), + function: tcx.def_path_str(*function), }); } } @@ -941,7 +950,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { warnings.sort_by_key(|w| w.block_span); for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings { let block_span = tcx.sess.source_map().guess_head_span(block_span); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNUSED_UNSAFE, hir_id, block_span, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 61ad99acf38a5..232b6033946a0 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::DiagnosticArgValue; use rustc_errors::{ - error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -23,10 +23,10 @@ pub struct UnconditionalRecursion { #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)] #[note] -pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> { +pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { #[label] pub span: Span, - pub function: &'a str, + pub function: String, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } @@ -123,34 +123,34 @@ pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)] #[help] -pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { +pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { #[label] pub span: Span, - pub function: &'a str, - pub missing_target_features: DiagnosticArgValue<'a>, + pub function: String, + pub missing_target_features: DiagnosticArgValue, pub missing_target_features_count: usize, #[note] pub note: Option<()>, - pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features: DiagnosticArgValue, pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = E0133)] #[note] -pub struct CallToUnsafeFunctionRequiresUnsafe<'a> { +pub struct CallToUnsafeFunctionRequiresUnsafe { #[primary_span] #[label] pub span: Span, - pub function: &'a str, + pub function: String, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = E0133)] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeNameless { #[primary_span] @@ -161,13 +161,13 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNameless { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { +pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] pub span: Span, - pub function: &'a str, + pub function: String, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } @@ -175,7 +175,7 @@ pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[derive(Diagnostic)] #[diag( mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { @@ -187,7 +187,7 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")] +#[diag(mir_build_inline_assembly_requires_unsafe, code = E0133)] #[note] pub struct UseOfInlineAssemblyRequiresUnsafe { #[primary_span] @@ -198,7 +198,7 @@ pub struct UseOfInlineAssemblyRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -209,7 +209,7 @@ pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")] +#[diag(mir_build_initializing_type_with_requires_unsafe, code = E0133)] #[note] pub struct InitializingTypeWithRequiresUnsafe { #[primary_span] @@ -222,7 +222,7 @@ pub struct InitializingTypeWithRequiresUnsafe { #[derive(Diagnostic)] #[diag( mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { @@ -234,7 +234,7 @@ pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")] +#[diag(mir_build_mutable_static_requires_unsafe, code = E0133)] #[note] pub struct UseOfMutableStaticRequiresUnsafe { #[primary_span] @@ -245,7 +245,7 @@ pub struct UseOfMutableStaticRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -256,7 +256,7 @@ pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")] +#[diag(mir_build_extern_static_requires_unsafe, code = E0133)] #[note] pub struct UseOfExternStaticRequiresUnsafe { #[primary_span] @@ -267,7 +267,7 @@ pub struct UseOfExternStaticRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -278,7 +278,7 @@ pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")] +#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = E0133)] #[note] pub struct DerefOfRawPointerRequiresUnsafe { #[primary_span] @@ -289,7 +289,7 @@ pub struct DerefOfRawPointerRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -300,7 +300,7 @@ pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_union_field_requires_unsafe, code = "E0133")] +#[diag(mir_build_union_field_requires_unsafe, code = E0133)] #[note] pub struct AccessToUnionFieldRequiresUnsafe { #[primary_span] @@ -311,7 +311,7 @@ pub struct AccessToUnionFieldRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -322,7 +322,7 @@ pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = E0133)] #[note] pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] @@ -335,7 +335,7 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { @@ -347,7 +347,7 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllow } #[derive(Diagnostic)] -#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = E0133)] #[note] pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] @@ -360,7 +360,7 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { @@ -372,36 +372,36 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed } #[derive(Diagnostic)] -#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")] +#[diag(mir_build_call_to_fn_with_requires_unsafe, code = E0133)] #[help] -pub struct CallToFunctionWithRequiresUnsafe<'a> { +pub struct CallToFunctionWithRequiresUnsafe { #[primary_span] #[label] pub span: Span, - pub function: &'a str, - pub missing_target_features: DiagnosticArgValue<'a>, + pub function: String, + pub missing_target_features: DiagnosticArgValue, pub missing_target_features_count: usize, #[note] pub note: Option<()>, - pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features: DiagnosticArgValue, pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[help] -pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { +pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] pub span: Span, - pub function: &'a str, - pub missing_target_features: DiagnosticArgValue<'a>, + pub function: String, + pub missing_target_features: DiagnosticArgValue, pub missing_target_features_count: usize, #[note] pub note: Option<()>, - pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features: DiagnosticArgValue, pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option, @@ -430,7 +430,7 @@ impl AddToDiagnostic for UnsafeNotInheritedLintNote { diag.tool_only_multipart_suggestion( fluent::mir_build_wrap_suggestion, vec![(body_start, "{ unsafe ".into()), (body_end, "}".into())], - Applicability::MaybeIncorrect, + Applicability::MachineApplicable, ); } } @@ -468,7 +468,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { fluent::mir_build_non_exhaustive_patterns_type_not_empty, ); diag.span(self.span); - diag.code(error_code!(E0004)); + diag.code(E0004); let peeled_ty = self.ty.peel_refs(); diag.arg("ty", self.ty); diag.arg("peeled_ty", peeled_ty); @@ -539,28 +539,28 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { pub struct NonExhaustiveMatchAllArmsGuarded; #[derive(Diagnostic)] -#[diag(mir_build_static_in_pattern, code = "E0158")] +#[diag(mir_build_static_in_pattern, code = E0158)] pub struct StaticInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_assoc_const_in_pattern, code = "E0158")] +#[diag(mir_build_assoc_const_in_pattern, code = E0158)] pub struct AssocConstInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_const_param_in_pattern, code = "E0158")] +#[diag(mir_build_const_param_in_pattern, code = E0158)] pub struct ConstParamInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_non_const_path, code = "E0080")] +#[diag(mir_build_non_const_path, code = E0080)] pub struct NonConstPath { #[primary_span] pub span: Span, @@ -590,7 +590,7 @@ pub struct CouldNotEvalConstPattern { } #[derive(Diagnostic)] -#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")] +#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = E0030)] pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[primary_span] #[label] @@ -611,7 +611,7 @@ pub struct LiteralOutOfRange<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")] +#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = E0579)] pub struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] pub span: Span, @@ -634,7 +634,7 @@ pub struct TrailingIrrefutableLetPatterns { } #[derive(LintDiagnostic)] -#[diag(mir_build_bindings_with_variant_name, code = "E0170")] +#[diag(mir_build_bindings_with_variant_name, code = E0170)] pub struct BindingsWithVariantName { #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")] pub suggestion: Option, @@ -780,14 +780,29 @@ pub struct UnsizedPattern<'tcx> { pub non_sm_ty: Ty<'tcx>, } -#[derive(LintDiagnostic)] -#[diag(mir_build_float_pattern)] -pub struct FloatPattern; +#[derive(Diagnostic)] +#[diag(mir_build_nan_pattern)] +#[note] +#[help] +pub struct NaNPattern { + #[primary_span] + pub span: Span, +} #[derive(LintDiagnostic)] #[diag(mir_build_pointer_pattern)] pub struct PointerPattern; +#[derive(Diagnostic)] +#[diag(mir_build_non_empty_never_pattern)] +#[note] +pub struct NonEmptyNeverPattern<'tcx> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'tcx>, +} + #[derive(LintDiagnostic)] #[diag(mir_build_indirect_structural_match)] #[note(mir_build_type_not_structural_tip)] @@ -811,7 +826,7 @@ pub struct NonPartialEqMatch<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_pattern_not_covered, code = "E0005")] +#[diag(mir_build_pattern_not_covered, code = E0005)] pub(crate) struct PatternNotCovered<'s, 'tcx> { #[primary_span] pub span: Span, diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 430c4ee3da780..a3d88b1269686 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -8,7 +8,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(try_blocks)] -#![recursion_limit = "256"] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 167b65328d11a..337493d15deca 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -53,7 +53,7 @@ fn check_recursion<'tcx>( let sp = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNCONDITIONAL_RECURSION, hir_id, sp, diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 8d5e6cd4f4100..71aebd13003b4 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -54,7 +54,7 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { let scalar_int = - trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?; + trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })?; ty::ValTree::from_scalar_int(scalar_int) } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 22094c112fc18..35adcc33480ca 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -556,6 +556,9 @@ impl<'tcx> Cx<'tcx> { ty::Coroutine(def_id, args) => { (def_id, UpvarArgs::Coroutine(args), Some(tcx.coroutine_movability(def_id))) } + ty::CoroutineClosure(def_id, args) => { + (def_id, UpvarArgs::CoroutineClosure(args), None) + } _ => { span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5d0bb3954ccc6..f4f591d15b933 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -127,10 +127,24 @@ impl<'tcx> Cx<'tcx> { ty::Coroutine(..) => { Param { ty: closure_ty, pat: None, ty_span: None, self_kind: None, hir_id: None } } - ty::Closure(_, closure_args) => { + ty::Closure(_, args) => { let closure_env_ty = self.tcx.closure_env_ty( closure_ty, - closure_args.as_closure().kind(), + args.as_closure().kind(), + self.tcx.lifetimes.re_erased, + ); + Param { + ty: closure_env_ty, + pat: None, + ty_span: None, + self_kind: None, + hir_id: None, + } + } + ty::CoroutineClosure(_, args) => { + let closure_env_ty = self.tcx.closure_env_ty( + closure_ty, + args.as_coroutine_closure().kind(), self.tcx.lifetimes.re_erased, ); Param { 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 f6c5e4a5cd6e2..1156e8be13e74 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,9 +1,8 @@ use rustc_pattern_analysis::errors::Uncovered; use rustc_pattern_analysis::rustc::{ - Constructor, DeconstructedPat, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness, + Constructor, DeconstructedPat, MatchArm, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness, UsefulnessReport, WitnessPat, }; -use rustc_pattern_analysis::{analyze_match, MatchArm}; use crate::errors::*; @@ -12,7 +11,7 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, + codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::*; @@ -48,9 +47,18 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err }; visitor.visit_expr(&thir[expr]); + let origin = match tcx.def_kind(def_id) { + DefKind::AssocFn | DefKind::Fn => "function argument", + DefKind::Closure => "closure argument", + // other types of MIR don't have function parameters, and we don't need to + // categorize those for the irrefutable check. + _ if thir.params.is_empty() => "", + kind => bug!("unexpected function parameters in THIR: {kind:?} {def_id:?}"), + }; + for param in thir.params.iter() { if let Some(box ref pattern) = param.pat { - visitor.check_binding_is_irrefutable(pattern, "function argument", None, None); + visitor.check_binding_is_irrefutable(pattern, origin, None, None); } } visitor.error @@ -276,11 +284,14 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { } else { // Check the pattern for some things unrelated to exhaustiveness. let refutable = if cx.refutable { Refutable } else { Irrefutable }; + let mut err = Ok(()); pat.walk_always(|pat| { check_borrow_conflicts_in_at_patterns(self, pat); check_for_bindings_named_same_as_variants(self, pat, refutable); + err = err.and(check_never_pattern(cx, pat)); }); - Ok(cx.pattern_arena.alloc(cx.lower_pat(pat))) + err?; + Ok(self.pattern_arena.alloc(cx.lower_pat(pat))) } } @@ -289,7 +300,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { fn is_known_valid_scrutinee(&self, scrutinee: &Expr<'tcx>) -> bool { use ExprKind::*; match &scrutinee.kind { - // Both pointers and references can validly point to a place with invalid data. + // Pointers can validly point to a place with invalid data. It is undecided whether + // references can too, so we conservatively assume they can. Deref { .. } => false, // Inherit validity of the parent place, unless the parent is an union. Field { lhs, .. } => { @@ -376,7 +388,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { typeck_results: self.typeck_results, param_env: self.param_env, module: self.tcx.parent_module(self.lint_level).to_def_id(), - pattern_arena: self.pattern_arena, dropless_arena: self.dropless_arena, match_lint_level: self.lint_level, whole_match_span, @@ -386,6 +397,34 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { } } + fn analyze_patterns( + &mut self, + cx: &MatchCheckCtxt<'p, 'tcx>, + arms: &[MatchArm<'p, 'tcx>], + scrut_ty: Ty<'tcx>, + ) -> Result, ErrorGuaranteed> { + let report = + rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty).map_err(|err| { + self.error = Err(err); + err + })?; + + // Warn unreachable subpatterns. + for (arm, is_useful) in report.arm_usefulness.iter() { + if let Usefulness::Useful(redundant_subpats) = is_useful + && !redundant_subpats.is_empty() + { + let mut redundant_subpats = redundant_subpats.clone(); + // Emit lints in the order in which they occur in the file. + redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span); + for pat in redundant_subpats { + report_unreachable_pattern(cx, arm.arm_data, pat.data().unwrap().span, None) + } + } + } + Ok(report) + } + #[instrument(level = "trace", skip(self))] fn check_let(&mut self, pat: &'p Pat<'tcx>, scrutinee: Option, span: Span) { assert!(self.let_source != LetSource::None); @@ -431,14 +470,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { } } - let scrut_ty = scrut.ty; - let report = match analyze_match(&cx, &tarms, scrut_ty) { - Ok(report) => report, - Err(err) => { - self.error = Err(err); - return; - } - }; + let Ok(report) = self.analyze_patterns(&cx, &tarms, scrut.ty) else { return }; match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -470,7 +502,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ); } else { self.error = Err(report_non_exhaustive_match( - &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span, + &cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span, )); } } @@ -515,7 +547,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let span_end = prefix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = prefix.len(); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( IRREFUTABLE_LET_PATTERNS, self.lint_level, span, @@ -534,7 +566,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let span_end = suffix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = suffix.len(); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( IRREFUTABLE_LET_PATTERNS, self.lint_level, span, @@ -552,7 +584,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let cx = self.new_cx(refutability, None, scrut, pat.span); let pat = self.lower_pattern(&cx, pat)?; let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }]; - let report = analyze_match(&cx, &arms, pat.ty().inner())?; + let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?; Ok((cx, report)) } @@ -563,7 +595,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ) -> Result { let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?; // Report if the pattern is unreachable, which can only occur when the type is uninhabited. - // This also reports unreachable sub-patterns. report_arm_reachability(&cx, &report); // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is // irrefutable. @@ -791,7 +822,7 @@ fn check_for_bindings_named_same_as_variants( { let variant_count = edef.variants().len(); let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); - cx.tcx.emit_spanned_lint( + cx.tcx.emit_node_span_lint( BINDINGS_WITH_VARIANT_NAME, cx.lint_level, pat.span, @@ -811,6 +842,19 @@ fn check_for_bindings_named_same_as_variants( } } +/// Check that never patterns are only used on inhabited types. +fn check_never_pattern<'tcx>( + cx: &MatchCheckCtxt<'_, 'tcx>, + pat: &Pat<'tcx>, +) -> Result<(), ErrorGuaranteed> { + if let PatKind::Never = pat.kind { + if !cx.is_uninhabited(pat.ty) { + return Err(cx.tcx.dcx().emit_err(NonEmptyNeverPattern { span: pat.span, ty: pat.ty })); + } + } + Ok(()) +} + fn report_irrefutable_let_patterns( tcx: TyCtxt<'_>, id: HirId, @@ -820,7 +864,7 @@ fn report_irrefutable_let_patterns( ) { macro_rules! emit_diag { ($lint:tt) => {{ - tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); + tcx.emit_node_span_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); }}; } @@ -833,39 +877,30 @@ fn report_irrefutable_let_patterns( } } +/// Report unreachable arms, if any. +fn report_unreachable_pattern<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + hir_id: HirId, + span: Span, + catchall: Option, +) { + cx.tcx.emit_node_span_lint( + UNREACHABLE_PATTERNS, + hir_id, + span, + UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall }, + ); +} + /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>, ) { - let report_unreachable_pattern = |span, hir_id, catchall: Option| { - cx.tcx.emit_spanned_lint( - UNREACHABLE_PATTERNS, - hir_id, - span, - UnreachablePattern { - span: if catchall.is_some() { Some(span) } else { None }, - catchall, - }, - ); - }; - let mut catchall = None; for (arm, is_useful) in report.arm_usefulness.iter() { - match is_useful { - Usefulness::Redundant => { - report_unreachable_pattern(arm.pat.data().unwrap().span, arm.arm_data, catchall) - } - Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {} - // The arm is reachable, but contains redundant subpatterns (from or-patterns). - Usefulness::Useful(redundant_subpats) => { - let mut redundant_subpats = redundant_subpats.clone(); - // Emit lints in the order in which they occur in the file. - redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span); - for pat in redundant_subpats { - report_unreachable_pattern(pat.data().unwrap().span, arm.arm_data, None); - } - } + if matches!(is_useful, Usefulness::Redundant) { + report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().unwrap().span, catchall) } if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { catchall = Some(arm.pat.data().unwrap().span); @@ -1113,7 +1148,7 @@ fn collect_non_exhaustive_tys<'tcx>( non_exhaustive_tys.insert(pat.ty().inner()); } if let Constructor::IntRange(range) = pat.ctor() { - if cx.is_range_beyond_boundaries(range, pat.ty()) { + if cx.is_range_beyond_boundaries(range, *pat.ty()) { // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. non_exhaustive_tys.insert(pat.ty().inner()); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 5631a38d0f0db..18a00724c3d0e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,5 +1,5 @@ +use rustc_apfloat::Float; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_index::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::Obligation; @@ -16,8 +16,8 @@ use std::cell::Cell; use super::PatCtxt; use crate::errors::{ - FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch, - NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern, + IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, PointerPattern, + TypeNotStructural, UnionPattern, UnsizedPattern, }; impl<'a, 'tcx> PatCtxt<'a, 'tcx> { @@ -32,11 +32,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { cv: mir::Const<'tcx>, id: hir::HirId, span: Span, - check_body_for_struct_match_violation: Option, ) -> Box> { let infcx = self.tcx.infer_ctxt().build(); let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(cv, check_body_for_struct_match_violation) + convert.to_pat(cv) } } @@ -102,11 +101,7 @@ impl<'tcx> ConstToPat<'tcx> { ty.is_structural_eq_shallow(self.infcx.tcx) } - fn to_pat( - &mut self, - cv: mir::Const<'tcx>, - check_body_for_struct_match_violation: Option, - ) -> Box> { + fn to_pat(&mut self, cv: mir::Const<'tcx>) -> Box> { trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be @@ -115,14 +110,6 @@ impl<'tcx> ConstToPat<'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| { - // `mir_const_qualif` must be called with the `DefId` of the item where the const is - // defined, not where it is declared. The difference is significant for associated - // constants. - self.tcx().mir_const_qualif(def_id).custom_eq - }); - debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation); - let have_valtree = matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_))); let inlined_const_as_pat = match cv { @@ -136,15 +123,15 @@ impl<'tcx> ConstToPat<'tcx> { | ty::ConstKind::Expr(_) => { span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind()) } - ty::ConstKind::Value(valtree) => self - .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false)) - .unwrap_or_else(|_: FallbackToOpaqueConst| { + ty::ConstKind::Value(valtree) => { + self.recur(valtree, cv.ty()).unwrap_or_else(|_: FallbackToOpaqueConst| { Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Constant { value: cv }, }) - }), + }) + } }, mir::Const::Unevaluated(_, _) => { span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}") @@ -159,7 +146,12 @@ impl<'tcx> ConstToPat<'tcx> { if self.saw_const_match_error.get().is_none() { // If we were able to successfully convert the const to some pat (possibly with some // lints, but no errors), double-check that all types in the const implement - // `Structural` and `PartialEq`. + // `PartialEq`. Even if we have a valtree, we may have found something + // in there with non-structural-equality, meaning we match using `PartialEq` + // and we hence have to check that that impl exists. + // This is all messy but not worth cleaning up: at some point we'll emit + // a hard error when we don't have a valtree or when we find something in + // the valtree that is not structural; then this can all be made a lot simpler. let structural = traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty()); @@ -169,19 +161,12 @@ impl<'tcx> ConstToPat<'tcx> { structural ); - // This can occur because const qualification treats all associated constants as - // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them - // before it runs. - // - // FIXME(#73448): Find a way to bring const qualification into parity with - // `search_for_structural_match_violation`. - if structural.is_none() && mir_structural_match_violation.unwrap_or(false) { - warn!("MIR const-checker found novel structural match violation. See #73448."); - return inlined_const_as_pat; - } - if let Some(non_sm_ty) = structural { if !self.type_has_partial_eq_impl(cv.ty()) { + // This is reachable and important even if we have a valtree: there might be + // non-structural things in a valtree, in which case we fall back to `PartialEq` + // comparison, in which case we better make sure the trait is implemented for + // each inner type (and not just for the surrounding type). let e = if let ty::Adt(def, ..) = non_sm_ty.kind() { if def.is_union() { let err = UnionPattern { span: self.span }; @@ -200,40 +185,23 @@ impl<'tcx> ConstToPat<'tcx> { // We errored. Signal that in the pattern, so that follow up errors can be silenced. let kind = PatKind::Error(e); return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } else if let ty::Adt(..) = cv.ty().kind() - && matches!(cv, mir::Const::Val(..)) - { - // This branch is only entered when the current `cv` is `mir::Const::Val`. - // This is because `mir::Const::ty` has already been handled by `Self::recur` - // and the invalid types may be ignored. + } else if !have_valtree { + // Not being structural prevented us from constructing a valtree, + // so this is definitely a case we want to reject. let err = TypeNotStructural { span: self.span, non_sm_ty }; let e = self.tcx().dcx().emit_err(err); let kind = PatKind::Error(e); return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } else if !self.saw_const_match_lint.get() { - if let Some(mir_structural_match_violation) = mir_structural_match_violation { - match non_sm_ty.kind() { - ty::Adt(..) if mir_structural_match_violation => { - self.tcx().emit_spanned_lint( - lint::builtin::INDIRECT_STRUCTURAL_MATCH, - self.id, - self.span, - IndirectStructuralMatch { non_sm_ty }, - ); - } - _ => { - debug!( - "`search_for_structural_match_violation` found one, but `CustomEq` was \ - not in the qualifs for that `const`" - ); - } - } - } + } else { + // This could be a violation in an inactive enum variant. + // Since we have a valtree, we trust that we have traversed the full valtree and + // complained about structural match violations there, so we don't + // have to check anything any more. } } else if !have_valtree && !self.saw_const_match_lint.get() { // The only way valtree construction can fail without the structural match // checker finding a violation is if there is a pointer somewhere. - self.tcx().emit_spanned_lint( + self.tcx().emit_node_span_lint( lint::builtin::POINTER_STRUCTURAL_MATCH, self.id, self.span, @@ -244,7 +212,7 @@ impl<'tcx> ConstToPat<'tcx> { // Always check for `PartialEq`, even if we emitted other lints. (But not if there were // any errors.) This ensures it shows up in cargo's future-compat reports as well. if !self.type_has_partial_eq_impl(cv.ty()) { - self.tcx().emit_spanned_lint( + self.tcx().emit_node_span_lint( lint::builtin::CONST_PATTERNS_WITHOUT_PARTIAL_EQ, self.id, self.span, @@ -298,7 +266,7 @@ impl<'tcx> ConstToPat<'tcx> { let field = FieldIdx::new(idx); // Patterns can only use monomorphic types. let ty = self.tcx().normalize_erasing_regions(self.param_env, ty); - Ok(FieldPat { field, pattern: self.recur(val, ty, false)? }) + Ok(FieldPat { field, pattern: self.recur(val, ty)? }) }) .collect() } @@ -309,7 +277,6 @@ impl<'tcx> ConstToPat<'tcx> { &self, cv: ValTree<'tcx>, ty: Ty<'tcx>, - mir_structural_match_violation: bool, ) -> Result>, FallbackToOpaqueConst> { let id = self.id; let span = self.span; @@ -317,16 +284,6 @@ impl<'tcx> ConstToPat<'tcx> { let param_env = self.param_env; let kind = match ty.kind() { - ty::Float(_) => { - self.saw_const_match_lint.set(true); - tcx.emit_spanned_lint( - lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - id, - span, - FloatPattern, - ); - return Err(FallbackToOpaqueConst); - } // If the type is not structurally comparable, just emit the constant directly, // causing the pattern match code to treat it opaquely. // FIXME: This code doesn't emit errors itself, the caller emits the errors. @@ -339,7 +296,7 @@ impl<'tcx> ConstToPat<'tcx> { ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => { if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, id, span, @@ -404,7 +361,7 @@ impl<'tcx> ConstToPat<'tcx> { prefix: cv .unwrap_branch() .iter() - .map(|val| self.recur(*val, *elem_ty, false)) + .map(|val| self.recur(*val, *elem_ty)) .collect::>()?, slice: None, suffix: Box::new([]), @@ -413,7 +370,7 @@ impl<'tcx> ConstToPat<'tcx> { prefix: cv .unwrap_branch() .iter() - .map(|val| self.recur(*val, *elem_ty, false)) + .map(|val| self.recur(*val, *elem_ty)) .collect::>()?, slice: None, suffix: Box::new([]), @@ -435,7 +392,7 @@ impl<'tcx> ConstToPat<'tcx> { && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, span, @@ -480,12 +437,28 @@ impl<'tcx> ConstToPat<'tcx> { _ => *pointee_ty, }; // References have the same valtree representation as their pointee. - let subpattern = self.recur(cv, pointee_ty, false)?; + let subpattern = self.recur(cv, pointee_ty)?; self.behind_reference.set(old); PatKind::Deref { subpattern } } } }, + ty::Float(flt) => { + let v = cv.unwrap_leaf(); + let is_nan = match flt { + ty::FloatTy::F32 => v.try_to_f32().unwrap().is_nan(), + ty::FloatTy::F64 => v.try_to_f64().unwrap().is_nan(), + }; + if is_nan { + // NaNs are not ever equal to anything so they make no sense as patterns. + // Also see . + let e = tcx.dcx().emit_err(NaNPattern { span }); + self.saw_const_match_error.set(Some(e)); + return Err(FallbackToOpaqueConst); + } else { + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + } + } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. @@ -505,25 +478,6 @@ impl<'tcx> ConstToPat<'tcx> { } }; - if self.saw_const_match_error.get().is_none() - && !self.saw_const_match_lint.get() - && mir_structural_match_violation - // FIXME(#73448): Find a way to bring const qualification into parity with - // `search_for_structural_match_violation` and then remove this condition. - - // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we - // could get `Option`, even though `Option` is annotated with derive. - && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty) - { - self.saw_const_match_lint.set(true); - tcx.emit_spanned_lint( - lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, - id, - span, - NontrivialStructuralMatch { non_sm_ty }, - ); - } - Ok(Box::new(Pat { span, ty, kind })) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index ff7e985bdfdcc..1a5cf13e28978 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -8,7 +8,7 @@ pub(crate) use self::check_match::check_match; use crate::errors::*; use crate::thir::util::UserAnnotatedTyHelpers; -use rustc_errors::error_code; +use rustc_errors::codes::*; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; @@ -209,7 +209,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { RangeEnd::Included => { self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { span, - teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), + teach: self.tcx.sess.teach(E0030).then_some(()), }) } RangeEnd::Excluded => { @@ -542,7 +542,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match const_value { Ok(const_) => { - let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id())); + let pattern = self.const_to_pat(const_, id, span); if !is_associated_const { return pattern; @@ -612,7 +612,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind, + Ok(c) => return self.const_to_pat(Const::Ty(c), id, span).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -635,17 +635,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) { - let subpattern = self.const_to_pat( - Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), - id, - span, - None, - ); + let subpattern = + self.const_to_pat(Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span); PatKind::InlineConstant { subpattern, def: def_id } } else { // If that fails, convert it to an opaque constant pattern. match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { - Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, + Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind, Err(ErrorHandled::TooGeneric(_)) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span }); @@ -681,9 +677,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(constant) => { - self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind - } + Ok(constant) => self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span).kind, Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 862876f53c76c..1b2f2cd9477fc 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -861,6 +861,9 @@ where let ty = self.place_ty(self.place); match ty.kind() { ty::Closure(_, args) => self.open_drop_for_tuple(args.as_closure().upvar_tys()), + ty::CoroutineClosure(_, args) => { + self.open_drop_for_tuple(args.as_coroutine_closure().upvar_tys()) + } // Note that `elaborate_drops` only drops the upvars of a coroutine, // and this is ok because `open_drop` here can only be reached // within that own coroutine's resume function. diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 815f204594257..1bd9167be12ed 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -185,8 +185,8 @@ where debug_assert_eq!(target.block, self.pos.block); let block_data = &self.body[target.block]; + #[rustfmt::skip] let next_effect = if A::Direction::IS_FORWARD { - #[rustfmt::skip] self.pos.curr_effect_index.map_or_else( || Effect::Before.at_index(0), EffectIndex::next_in_forward_order, diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 6653b99b3f503..720515f262db8 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -305,7 +305,10 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + /// There can be many more `MovePathIndex` than there are locals in a MIR body. + /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = MaybeReachable>; + const NAME: &'static str = "maybe_init"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { @@ -437,6 +440,8 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + /// There can be many more `MovePathIndex` than there are locals in a MIR body. + /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet; const NAME: &'static str = "maybe_uninit"; @@ -636,6 +641,8 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { + /// There can be many more `InitIndex` than there are locals in a MIR body. + /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet; const NAME: &'static str = "ever_init"; diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index cfa92ce60d080..f14ce1705db71 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,4 +1,4 @@ -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges, @@ -26,14 +26,14 @@ use crate::{Analysis, AnalysisDomain, Backward, GenKill, GenKillAnalysis}; pub struct MaybeLiveLocals; impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { - type Domain = ChunkedBitSet; + type Domain = BitSet; type Direction = Backward; const NAME: &'static str = "liveness"; fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { // bottom = not live - ChunkedBitSet::new_empty(body.local_decls.len()) + BitSet::new_empty(body.local_decls.len()) } fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { @@ -233,14 +233,14 @@ impl<'a> MaybeTransitiveLiveLocals<'a> { } impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> { - type Domain = ChunkedBitSet; + type Domain = BitSet; type Direction = Backward; const NAME: &'static str = "transitive liveness"; fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { // bottom = not live - ChunkedBitSet::new_empty(body.local_decls.len()) + BitSet::new_empty(body.local_decls.len()) } fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index b805f8ca23eb4..23111cc319956 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -3,9 +3,7 @@ #![feature(exact_size_is_empty)] #![feature(let_chains)] #![feature(min_specialization)] -#![feature(stmt_expr_attributes)] #![feature(try_blocks)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -16,15 +14,17 @@ extern crate rustc_middle; use rustc_middle::ty; +// Please change the public `use` directives cautiously, as they might be used by external tools. +// See issue #120130. pub use self::drop_flag_effects::{ drop_flag_effects_for_function_entry, drop_flag_effects_for_location, move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - fmt, lattice, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, - JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, + fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine, + Forward, GenKill, GenKillAnalysis, JoinSemiLattice, MaybeReachable, Results, ResultsCursor, + ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, }; -use self::framework::{Backward, SwitchIntEdgeEffects}; use self::move_paths::MoveData; pub mod debuginfo; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 38ee26c5a876e..30dd915521cd2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -154,7 +154,8 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -177,7 +178,10 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { union_path.get_or_insert(base); } } - ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (), + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(_, _) + | ty::Tuple(_) => (), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index ff17ce1fe079a..bbfb37d2a8265 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -1,5 +1,5 @@ use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor}; -use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::bit_set::BitSet; use rustc_index::interval::SparseIntervalMatrix; use rustc_index::Idx; use rustc_index::IndexVec; @@ -102,7 +102,7 @@ pub fn save_as_intervals<'tcx, N, R>( ) -> SparseIntervalMatrix where N: Idx, - R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet>, + R: ResultsVisitable<'tcx, FlowState = BitSet>, { let values = SparseIntervalMatrix::new(elements.num_points()); let mut visitor = Visitor { elements, values }; @@ -124,7 +124,7 @@ impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> where N: Idx, { - type FlowState = ChunkedBitSet; + type FlowState = BitSet; fn visit_statement_after_primary_effect( &mut self, diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 08a5d70fb6fc5..cbbf3548c07ef 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -12,7 +12,7 @@ use crate::MoveDataParamEnv; use crate::{Analysis, JoinSemiLattice, ResultsCursor}; use rustc_ast::MetaItem; use rustc_hir::def_id::DefId; -use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::MirPass; use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -275,7 +275,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &ChunkedBitSet, + flow_state: &BitSet, call: PeekCall, ) { info!(?place, "peek_at"); diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 90f5a75812ca2..a2bd0b5236f3e 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1149,6 +1149,12 @@ pub fn iter_fields<'tcx>( ty::Closure(_, args) => { iter_fields(args.as_closure().tupled_upvars_ty(), tcx, param_env, f); } + ty::Coroutine(_, args) => { + iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, param_env, f); + } + ty::CoroutineClosure(_, args) => { + iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, param_env, f); + } _ => (), } } diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index dfc7a9891f921..451d3be255fdf 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -39,6 +39,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { let body_abi = match body_ty.kind() { ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::Closure(..) => Abi::RustCall, + ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), }; diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 3195cd3622dc9..1f615c9d8d1a2 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -100,7 +100,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { && let Some((lint_root, span, item)) = self.should_lint_const_item_usage(lhs, def_id, loc) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( CONST_ITEM_MUTATION, lint_root, span, @@ -145,7 +145,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { if let Some((lint_root, span, item)) = self.should_lint_const_item_usage(place, def_id, lint_loc) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( CONST_ITEM_MUTATION, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 582c2c0c6b60b..fbb626953835e 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -128,7 +128,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { ), } } - &AggregateKind::Closure(def_id, _) | &AggregateKind::Coroutine(def_id, _) => { + &AggregateKind::Closure(def_id, _) + | &AggregateKind::CoroutineClosure(def_id, _) + | &AggregateKind::Coroutine(def_id, _) => { let def_id = def_id.expect_local(); let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = self.tcx.mir_unsafety_check_result(def_id); @@ -527,7 +529,7 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) { } else { None }; - tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent }); + tcx.emit_node_span_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent }); } pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { @@ -577,7 +579,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { }); } UnsafetyViolationKind::UnsafeFn => { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, lint_root, source_info.span, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c5824c3077028..eba62aae60f75 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -1,21 +1,12 @@ //! Propagates constants for early reporting of statically known //! assertion failures -use rustc_const_eval::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, FnArg, Frame, ImmTy, InterpCx, - InterpResult, OpTy, PlaceTy, Pointer, -}; -use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, ParamEnv, TyCtxt}; -use rustc_span::def_id::DefId; +use rustc_middle::ty::{ParamEnv, TyCtxt}; use rustc_target::abi::Size; -use rustc_target::spec::abi::Abi as CallAbi; /// The maximum number of bytes that we'll allocate space for a local or the return value. /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just @@ -43,168 +34,12 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{ fn add_args( self: Box, - _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>), + _: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue), ) {} } throw_machine_stop!(Zst) }} -pub(crate) struct ConstPropMachine<'mir, 'tcx> { - /// The virtual call stack. - stack: Vec>, - pub written_only_inside_own_block_locals: FxHashSet, - pub can_const_prop: IndexVec, -} - -impl ConstPropMachine<'_, '_> { - pub fn new(can_const_prop: IndexVec) -> Self { - Self { - stack: Vec::new(), - written_only_inside_own_block_locals: Default::default(), - can_const_prop, - } - } -} - -impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { - compile_time_machine!(<'mir, 'tcx>); - - const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`) - - const POST_MONO_CHECKS: bool = false; // this MIR is still generic! - - type MemoryKind = !; - - #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - false // no reason to enforce alignment - } - - #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { - false // for now, we don't enforce validity - } - - fn load_mir( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx Body<'tcx>> { - throw_machine_stop_str!("calling functions isn't supported in ConstProp") - } - - fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: &str) -> InterpResult<'tcx> { - throw_machine_stop_str!("panicking isn't supported in ConstProp") - } - - fn find_mir_or_eval_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _abi: CallAbi, - _args: &[FnArg<'tcx>], - _destination: &PlaceTy<'tcx>, - _target: Option, - _unwind: UnwindAction, - ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { - Ok(None) - } - - fn call_intrinsic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _args: &[OpTy<'tcx>], - _destination: &PlaceTy<'tcx>, - _target: Option, - _unwind: UnwindAction, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") - } - - fn assert_panic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _msg: &rustc_middle::mir::AssertMessage<'tcx>, - _unwind: rustc_middle::mir::UnwindAction, - ) -> InterpResult<'tcx> { - bug!("panics terminators are not evaluated in ConstProp") - } - - fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _bin_op: BinOp, - _left: &ImmTy<'tcx>, - _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> { - // We can't do this because aliasing of memory can differ between const eval and llvm - throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") - } - - fn before_access_local_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - frame: usize, - local: Local, - ) -> InterpResult<'tcx> { - assert_eq!(frame, 0); - match ecx.machine.can_const_prop[local] { - ConstPropMode::NoPropagation => { - throw_machine_stop_str!( - "tried to write to a local that is marked as not propagatable" - ) - } - ConstPropMode::OnlyInsideOwnBlock => { - ecx.machine.written_only_inside_own_block_locals.insert(local); - } - ConstPropMode::FullConstProp => {} - } - Ok(()) - } - - fn before_access_global( - _tcx: TyCtxtAt<'tcx>, - _machine: &Self, - _alloc_id: AllocId, - alloc: ConstAllocation<'tcx>, - _static_def_id: Option, - is_write: bool, - ) -> InterpResult<'tcx> { - if is_write { - throw_machine_stop_str!("can't write to global"); - } - // If the static allocation is mutable, then we can't const prop it as its content - // might be different at runtime. - if alloc.inner().mutability.is_mut() { - throw_machine_stop_str!("can't access mutable globals in ConstProp"); - } - - Ok(()) - } - - #[inline(always)] - fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> { - throw_machine_stop_str!("exposing pointers isn't supported in ConstProp") - } - - #[inline(always)] - fn init_frame_extra( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { - Ok(frame) - } - - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } -} - /// The mode that `ConstProp` is allowed to run in for a given `Local`. #[derive(Clone, Copy, Debug, PartialEq)] pub enum ConstPropMode { diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index d0bbca08a4068..f2448ee3d44af 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -3,37 +3,26 @@ use std::fmt::Debug; -use either::Left; - -use rustc_const_eval::interpret::Immediate; -use rustc_const_eval::interpret::{ - InterpCx, InterpResult, MemoryKind, OpTy, Scalar, StackPopCleanup, -}; -use rustc_const_eval::ReportErrorExt; +use rustc_const_eval::interpret::{ImmTy, Projectable}; +use rustc_const_eval::interpret::{InterpCx, InterpResult, Scalar}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; +use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::{ - self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, -}; +use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; -use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; +use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; use crate::const_prop::CanConstProp; -use crate::const_prop::ConstPropMachine; use crate::const_prop::ConstPropMode; -use crate::errors::AssertLint; +use crate::dataflow_const_prop::DummyMachine; +use crate::errors::{AssertLint, AssertLintKind}; use crate::MirLint; -/// The maximum number of bytes that we'll allocate space for a local or the return value. -/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just -/// Severely regress performance. -const MAX_ALLOC_LIMIT: u64 = 1024; - pub struct ConstPropLint; impl<'tcx> MirLint<'tcx> for ConstPropLint { @@ -81,11 +70,85 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint { /// Finds optimization opportunities on the MIR. struct ConstPropagator<'mir, 'tcx> { - ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, + ecx: InterpCx<'mir, 'tcx, DummyMachine>, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, worklist: Vec, visited_blocks: BitSet, + locals: IndexVec>, + body: &'mir Body<'tcx>, + written_only_inside_own_block_locals: FxHashSet, + can_const_prop: IndexVec, +} + +#[derive(Debug, Clone)] +enum Value<'tcx> { + Immediate(ImmTy<'tcx>), + Aggregate { variant: VariantIdx, fields: IndexVec> }, + Uninit, +} + +impl<'tcx> From> for Value<'tcx> { + fn from(v: ImmTy<'tcx>) -> Self { + Self::Immediate(v) + } +} + +impl<'tcx> Value<'tcx> { + fn project( + &self, + proj: &[PlaceElem<'tcx>], + prop: &ConstPropagator<'_, 'tcx>, + ) -> Option<&Value<'tcx>> { + let mut this = self; + for proj in proj { + this = match (*proj, this) { + (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => { + fields.get(idx).unwrap_or(&Value::Uninit) + } + (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => { + let idx = prop.get_const(idx.into())?.immediate()?; + let idx = prop.ecx.read_target_usize(idx).ok()?; + fields.get(FieldIdx::from_u32(idx.try_into().ok()?)).unwrap_or(&Value::Uninit) + } + ( + PlaceElem::ConstantIndex { offset, min_length: _, from_end: false }, + Value::Aggregate { fields, .. }, + ) => fields + .get(FieldIdx::from_u32(offset.try_into().ok()?)) + .unwrap_or(&Value::Uninit), + _ => return None, + }; + } + Some(this) + } + + fn project_mut(&mut self, proj: &[PlaceElem<'_>]) -> Option<&mut Value<'tcx>> { + let mut this = self; + for proj in proj { + this = match (proj, this) { + (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => { + fields.ensure_contains_elem(*idx, || Value::Uninit) + } + (PlaceElem::Field(..), val @ Value::Uninit) => { + *val = Value::Aggregate { + variant: VariantIdx::new(0), + fields: Default::default(), + }; + val.project_mut(&[*proj])? + } + _ => return None, + }; + } + Some(this) + } + + fn immediate(&self) -> Option<&ImmTy<'tcx>> { + match self { + Value::Immediate(op) => Some(op), + _ => None, + } + } } impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> { @@ -121,49 +184,10 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> { impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> { let def_id = body.source.def_id(); - let args = &GenericArgs::identity_for_item(tcx, def_id); let param_env = tcx.param_env_reveal_all_normalized(def_id); let can_const_prop = CanConstProp::check(tcx, param_env, body); - let mut ecx = InterpCx::new( - tcx, - tcx.def_span(def_id), - param_env, - ConstPropMachine::new(can_const_prop), - ); - - let ret_layout = ecx - .layout_of(body.bound_return_ty().instantiate(tcx, args)) - .ok() - // Don't bother allocating memory for large values. - // I don't know how return types can seem to be unsized but this happens in the - // `type/type-unsatisfiable.rs` test. - .filter(|ret_layout| { - ret_layout.is_sized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) - }) - .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap()); - - let ret = ecx - .allocate(ret_layout, MemoryKind::Stack) - .expect("couldn't perform small allocation") - .into(); - - ecx.push_stack_frame( - Instance::new(def_id, args), - body, - &ret, - StackPopCleanup::Root { cleanup: false }, - ) - .expect("failed to push initial stack frame"); - - for local in body.local_decls.indices() { - // Mark everything initially live. - // This is somewhat dicey since some of them might be unsized and it is incoherent to - // mark those as live... We rely on `local_to_place`/`local_to_op` in the interpreter - // stopping us before those unsized immediates can cause issues deeper in the - // interpreter. - ecx.frame_mut().locals[local].make_live_uninit(); - } + let ecx = InterpCx::new(tcx, tcx.def_span(def_id), param_env, DummyMachine); ConstPropagator { ecx, @@ -171,61 +195,47 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { param_env, worklist: vec![START_BLOCK], visited_blocks: BitSet::new_empty(body.basic_blocks.len()), + locals: IndexVec::from_elem_n(Value::Uninit, body.local_decls.len()), + body, + can_const_prop, + written_only_inside_own_block_locals: Default::default(), } } - fn body(&self) -> &'mir Body<'tcx> { - self.ecx.frame().body - } - fn local_decls(&self) -> &'mir LocalDecls<'tcx> { - &self.body().local_decls + &self.body.local_decls } - fn get_const(&self, place: Place<'tcx>) -> Option> { - let op = match self.ecx.eval_place_to_op(place, None) { - Ok(op) => { - if op - .as_mplace_or_imm() - .right() - .is_some_and(|imm| matches!(*imm, Immediate::Uninit)) - { - // Make sure nobody accidentally uses this value. - return None; - } - op - } - Err(e) => { - trace!("get_const failed: {:?}", e.into_kind().debug()); - return None; - } - }; - - // Try to read the local as an immediate so that if it is representable as a scalar, we can - // handle it as such, but otherwise, just return the value as is. - Some(match self.ecx.read_immediate_raw(&op) { - Ok(Left(imm)) => imm.into(), - _ => op, - }) + fn get_const(&self, place: Place<'tcx>) -> Option<&Value<'tcx>> { + self.locals[place.local].project(&place.projection, self) } /// Remove `local` from the pool of `Locals`. Allows writing to them, /// but not reading from them anymore. - fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { - ecx.frame_mut().locals[local].make_live_uninit(); - ecx.machine.written_only_inside_own_block_locals.remove(&local); + fn remove_const(&mut self, local: Local) { + self.locals[local] = Value::Uninit; + self.written_only_inside_own_block_locals.remove(&local); + } + + fn access_mut(&mut self, place: &Place<'_>) -> Option<&mut Value<'tcx>> { + match self.can_const_prop[place.local] { + ConstPropMode::NoPropagation => return None, + ConstPropMode::OnlyInsideOwnBlock => { + self.written_only_inside_own_block_locals.insert(place.local); + } + ConstPropMode::FullConstProp => {} + } + self.locals[place.local].project_mut(place.projection) } fn lint_root(&self, source_info: SourceInfo) -> Option { - source_info.scope.lint_root(&self.body().source_scopes) + source_info.scope.lint_root(&self.body.source_scopes) } - fn use_ecx(&mut self, location: Location, f: F) -> Option + fn use_ecx(&mut self, f: F) -> Option where F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { - // Overwrite the PC -- whatever the interpreter does to it does not make any sense anyway. - self.ecx.frame_mut().loc = Left(location); match f(self) { Ok(val) => Some(val), Err(error) => { @@ -244,7 +254,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } /// Returns the value, if any, of evaluating `c`. - fn eval_constant(&mut self, c: &ConstOperand<'tcx>, location: Location) -> Option> { + fn eval_constant(&mut self, c: &ConstOperand<'tcx>) -> Option> { // FIXME we need to revisit this for #67176 if c.has_param() { return None; @@ -258,46 +268,62 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // manually normalized. let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?; - self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None)) + self.use_ecx(|this| this.ecx.eval_mir_constant(&val, Some(c.span), None))? + .as_mplace_or_imm() + .right() } /// Returns the value, if any, of evaluating `place`. - fn eval_place(&mut self, place: Place<'tcx>, location: Location) -> Option> { - trace!("eval_place(place={:?})", place); - self.use_ecx(location, |this| this.ecx.eval_place_to_op(place, None)) + #[instrument(level = "trace", skip(self), ret)] + fn eval_place(&mut self, place: Place<'tcx>) -> Option> { + match self.get_const(place)? { + Value::Immediate(imm) => Some(imm.clone()), + Value::Aggregate { .. } => None, + Value::Uninit => None, + } } /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` /// or `eval_place`, depending on the variant of `Operand` used. - fn eval_operand(&mut self, op: &Operand<'tcx>, location: Location) -> Option> { + fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c, location), - Operand::Move(place) | Operand::Copy(place) => self.eval_place(place, location), + Operand::Constant(ref c) => self.eval_constant(c), + Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), } } - fn report_assert_as_lint(&self, source_info: &SourceInfo, lint: AssertLint) { + fn report_assert_as_lint( + &self, + location: Location, + lint_kind: AssertLintKind, + assert_kind: AssertKind, + ) { + let source_info = self.body.source_info(location); if let Some(lint_root) = self.lint_root(*source_info) { - self.tcx.emit_spanned_lint(lint.lint(), lint_root, source_info.span, lint); + let span = source_info.span; + self.tcx.emit_node_span_lint( + lint_kind.lint(), + lint_root, + span, + AssertLint { span, assert_kind, lint_kind }, + ); } } fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> { - if let (val, true) = self.use_ecx(location, |this| { - let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?; + let arg = self.eval_operand(arg)?; + if let (val, true) = self.use_ecx(|this| { + let val = this.ecx.read_immediate(&arg)?; let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?; Ok((val, overflow)) })? { // `AssertKind` only has an `OverflowNeg` variant, so make sure that is // appropriate to use. assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); - let source_info = self.body().source_info(location); self.report_assert_as_lint( - source_info, - AssertLint::ArithmeticOverflow( - source_info.span, - AssertKind::OverflowNeg(val.to_const_int()), - ), + location, + AssertLintKind::ArithmeticOverflow, + AssertKind::OverflowNeg(val.to_const_int()), ); return None; } @@ -312,11 +338,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { right: &Operand<'tcx>, location: Location, ) -> Option<()> { - let r = self.use_ecx(location, |this| { - this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?) - }); - let l = self - .use_ecx(location, |this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?)); + let r = + self.eval_operand(right).and_then(|r| self.use_ecx(|this| this.ecx.read_immediate(&r))); + let l = + self.eval_operand(left).and_then(|l| self.use_ecx(|this| this.ecx.read_immediate(&l))); // Check for exceeding shifts *even if* we cannot evaluate the LHS. if matches!(op, BinOp::Shr | BinOp::Shl) { let r = r.clone()?; @@ -328,7 +353,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let r_bits = r.to_scalar().to_bits(right_size).ok(); if r_bits.is_some_and(|b| b >= left_size.bits() as u128) { debug!("check_binary_op: reporting assert for {:?}", location); - let source_info = self.body().source_info(location); let panic = AssertKind::Overflow( op, match l { @@ -342,27 +366,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { }, r.to_const_int(), ); - self.report_assert_as_lint( - source_info, - AssertLint::ArithmeticOverflow(source_info.span, panic), - ); + self.report_assert_as_lint(location, AssertLintKind::ArithmeticOverflow, panic); return None; } } if let (Some(l), Some(r)) = (l, r) { // The remaining operators are handled through `overflowing_binary_op`. - if self.use_ecx(location, |this| { + if self.use_ecx(|this| { let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?; Ok(overflow) })? { - let source_info = self.body().source_info(location); self.report_assert_as_lint( - source_info, - AssertLint::ArithmeticOverflow( - source_info.span, - AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), - ), + location, + AssertLintKind::ArithmeticOverflow, + AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), ); return None; } @@ -411,7 +429,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // value the local has right now. // Thus, all locals that have their reference taken // must not take part in propagation. - Self::remove_const(&mut self.ecx, place.local); + self.remove_const(place.local); return None; } @@ -453,17 +471,17 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { cond: &Operand<'tcx>, location: Location, ) -> Option { - let value = &self.eval_operand(cond, location)?; + let value = &self.eval_operand(cond)?; trace!("assertion on {:?} should be {:?}", value, expected); let expected = Scalar::from_bool(expected); - let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(value))?; + let value_const = self.use_ecx(|this| this.ecx.read_scalar(value))?; if expected != value_const { // Poison all places this operand references so that further code // doesn't use the invalid value if let Some(place) = cond.place() { - Self::remove_const(&mut self.ecx, place.local); + self.remove_const(place.local); } enum DbgVal { @@ -481,7 +499,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let mut eval_to_int = |op| { // This can be `None` if the lhs wasn't const propagated and we just // triggered the assert on the value of the rhs. - self.eval_operand(op, location) + self.eval_operand(op) .and_then(|op| self.ecx.read_immediate(&op).ok()) .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) }; @@ -503,11 +521,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Need proper const propagator for these. _ => return None, }; - let source_info = self.body().source_info(location); - self.report_assert_as_lint( - source_info, - AssertLint::UnconditionalPanic(source_info.span, msg), - ); + self.report_assert_as_lint(location, AssertLintKind::UnconditionalPanic, msg); } None @@ -515,16 +529,177 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn ensure_not_propagated(&self, local: Local) { if cfg!(debug_assertions) { + let val = self.get_const(local.into()); assert!( - self.get_const(local.into()).is_none() + matches!(val, Some(Value::Uninit)) || self .layout_of(self.local_decls()[local].ty) .map_or(true, |layout| layout.is_zst()), - "failed to remove values for `{local:?}`, value={:?}", - self.get_const(local.into()), + "failed to remove values for `{local:?}`, value={val:?}", ) } } + + #[instrument(level = "trace", skip(self), ret)] + fn eval_rvalue( + &mut self, + rvalue: &Rvalue<'tcx>, + location: Location, + dest: &Place<'tcx>, + ) -> Option<()> { + if !dest.projection.is_empty() { + return None; + } + use rustc_middle::mir::Rvalue::*; + let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?; + trace!(?layout); + + let val: Value<'_> = match *rvalue { + ThreadLocalRef(_) => return None, + + Use(ref operand) => self.eval_operand(operand)?.into(), + + CopyForDeref(place) => self.eval_place(place)?.into(), + + BinaryOp(bin_op, box (ref left, ref right)) => { + let left = self.eval_operand(left)?; + let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?; + + let right = self.eval_operand(right)?; + let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; + + let val = + self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?; + val.into() + } + + CheckedBinaryOp(bin_op, box (ref left, ref right)) => { + let left = self.eval_operand(left)?; + let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?; + + let right = self.eval_operand(right)?; + let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; + + let (val, overflowed) = + self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?; + let overflowed = ImmTy::from_bool(overflowed, self.tcx); + Value::Aggregate { + variant: VariantIdx::new(0), + fields: [Value::from(val), overflowed.into()].into_iter().collect(), + } + } + + UnaryOp(un_op, ref operand) => { + let operand = self.eval_operand(operand)?; + let val = self.use_ecx(|this| this.ecx.read_immediate(&operand))?; + + let val = self.use_ecx(|this| this.ecx.wrapping_unary_op(un_op, &val))?; + val.into() + } + + Aggregate(ref kind, ref fields) => Value::Aggregate { + fields: fields + .iter() + .map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate)) + .collect(), + variant: match **kind { + AggregateKind::Adt(_, variant, _, _, _) => variant, + AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::Closure(_, _) + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), + }, + }, + + Repeat(ref op, n) => { + trace!(?op, ?n); + return None; + } + + Len(place) => { + let len = match self.get_const(place)? { + Value::Immediate(src) => src.len(&self.ecx).ok()?, + Value::Aggregate { fields, .. } => fields.len() as u64, + Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { + ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, + _ => return None, + }, + }; + ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() + } + + Ref(..) | AddressOf(..) => return None, + + NullaryOp(ref null_op, ty) => { + let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?; + let val = match null_op { + NullOp::SizeOf => op_layout.size.bytes(), + NullOp::AlignOf => op_layout.align.abi.bytes(), + NullOp::OffsetOf(fields) => { + op_layout.offset_of_subfield(self, fields.iter()).bytes() + } + }; + ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() + } + + ShallowInitBox(..) => return None, + + Cast(ref kind, ref value, to) => match kind { + CastKind::IntToInt | CastKind::IntToFloat => { + let value = self.eval_operand(value)?; + let value = self.ecx.read_immediate(&value).ok()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.int_to_int_or_float(&value, to).ok()?; + res.into() + } + CastKind::FloatToFloat | CastKind::FloatToInt => { + let value = self.eval_operand(value)?; + let value = self.ecx.read_immediate(&value).ok()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.float_to_float_or_int(&value, to).ok()?; + res.into() + } + CastKind::Transmute => { + let value = self.eval_operand(value)?; + let to = self.ecx.layout_of(to).ok()?; + // `offset` for immediates only supports scalar/scalar-pair ABIs, + // so bail out if the target is not one. + match (value.layout.abi, to.abi) { + (Abi::Scalar(..), Abi::Scalar(..)) => {} + (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} + _ => return None, + } + + value.offset(Size::ZERO, to, &self.ecx).ok()?.into() + } + _ => return None, + }, + + Discriminant(place) => { + let variant = match self.get_const(place)? { + Value::Immediate(op) => { + let op = op.clone(); + self.use_ecx(|this| this.ecx.read_discriminant(&op))? + } + Value::Aggregate { variant, .. } => *variant, + Value::Uninit => return None, + }; + let imm = self.use_ecx(|this| { + this.ecx.discriminant_for_variant( + place.ty(this.local_decls(), this.tcx).ty, + variant, + ) + })?; + imm.into() + } + }; + trace!(?val); + + *self.access_mut(dest)? = val; + + Some(()) + } } impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { @@ -546,7 +721,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - self.eval_constant(constant, location); + self.eval_constant(constant); } fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { @@ -554,15 +729,12 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { let Some(()) = self.check_rvalue(rvalue, location) else { return }; - match self.ecx.machine.can_const_prop[place.local] { + match self.can_const_prop[place.local] { // Do nothing if the place is indirect. _ if place.is_indirect() => {} ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => { - if self - .use_ecx(location, |this| this.ecx.eval_rvalue_into_place(rvalue, *place)) - .is_none() - { + if self.eval_rvalue(rvalue, location, place).is_none() { // Const prop failed, so erase the destination, ensuring that whatever happens // from here on, does not know about the previous value. // This is important in case we have @@ -578,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { Nuking the entire site from orbit, it's the only way to be sure", place, ); - Self::remove_const(&mut self.ecx, place.local); + self.remove_const(place.local); } } } @@ -592,28 +764,24 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.super_statement(statement, location); match statement.kind { - StatementKind::SetDiscriminant { ref place, .. } => { - match self.ecx.machine.can_const_prop[place.local] { + StatementKind::SetDiscriminant { ref place, variant_index } => { + match self.can_const_prop[place.local] { // Do nothing if the place is indirect. _ if place.is_indirect() => {} ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => { - if self.use_ecx(location, |this| this.ecx.statement(statement)).is_some() { - trace!("propped discriminant into {:?}", place); - } else { - Self::remove_const(&mut self.ecx, place.local); + match self.access_mut(place) { + Some(Value::Aggregate { variant, .. }) => *variant = variant_index, + _ => self.remove_const(place.local), } } } } StatementKind::StorageLive(local) => { - let frame = self.ecx.frame_mut(); - frame.locals[local].make_live_uninit(); + self.remove_const(local); } StatementKind::StorageDead(local) => { - let frame = self.ecx.frame_mut(); - // We don't actually track liveness, so the local remains live. But forget its value. - frame.locals[local].make_live_uninit(); + self.remove_const(local); } _ => {} } @@ -626,9 +794,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.check_assertion(*expected, msg, cond, location); } TerminatorKind::SwitchInt { ref discr, ref targets } => { - if let Some(ref value) = self.eval_operand(discr, location) - && let Some(value_const) = - self.use_ecx(location, |this| this.ecx.read_scalar(value)) + if let Some(ref value) = self.eval_operand(discr) + && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) && let Ok(constant) = value_const.try_to_int() && let Ok(constant) = constant.to_bits(constant.size()) { @@ -665,7 +832,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { // which were modified in the current block. // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. let mut written_only_inside_own_block_locals = - std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + std::mem::take(&mut self.written_only_inside_own_block_locals); // This loop can get very hot for some bodies: it check each local in each bb. // To avoid this quadratic behaviour, we only clear the locals that were modified inside @@ -673,17 +840,13 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { // The order in which we remove consts does not matter. #[allow(rustc::potential_query_instability)] for local in written_only_inside_own_block_locals.drain() { - debug_assert_eq!( - self.ecx.machine.can_const_prop[local], - ConstPropMode::OnlyInsideOwnBlock - ); - Self::remove_const(&mut self.ecx, local); + debug_assert_eq!(self.can_const_prop[local], ConstPropMode::OnlyInsideOwnBlock); + self.remove_const(local); } - self.ecx.machine.written_only_inside_own_block_locals = - written_only_inside_own_block_locals; + self.written_only_inside_own_block_locals = written_only_inside_own_block_locals; if cfg!(debug_assertions) { - for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { + for (local, &mode) in self.can_const_prop.iter_enumerated() { match mode { ConstPropMode::FullConstProp => {} ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index eaa36e0cc91eb..297b2fa143de2 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -50,6 +50,9 @@ //! For coroutines with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. +mod by_move_body; +pub use by_move_body::ByMoveBody; + use crate::abort_unwinding_calls; use crate::deref_separator::deref_finder; use crate::errors; @@ -1231,7 +1234,12 @@ fn create_coroutine_drop_shim<'tcx>( drop_clean: BasicBlock, ) -> Body<'tcx> { let mut body = body.clone(); - body.arg_count = 1; // make sure the resume argument is not included here + // Take the coroutine info out of the body, since the drop shim is + // not a coroutine body itself; it just has its drop built out of it. + let _ = body.coroutine.take(); + // Make sure the resume argument is not included here, since we're + // building a body for `drop_in_place`. + body.arg_count = 1; let source_info = SourceInfo::outermost(body.span); @@ -2071,7 +2079,7 @@ fn check_must_not_suspend_def( span: data.source_span, reason: s.as_str().to_string(), }); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( rustc_session::lint::builtin::MUST_NOT_SUSPEND, hir_id, data.source_span, diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs new file mode 100644 index 0000000000000..fcd4715b9e88c --- /dev/null +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -0,0 +1,156 @@ +//! A MIR pass which duplicates a coroutine's body and removes any derefs which +//! would be present for upvars that are taken by-ref. The result of which will +//! be a coroutine body that takes all of its upvars by-move, and which we stash +//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures. + +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::{self, dump_mir, MirPass}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; +use rustc_target::abi::FieldIdx; + +pub struct ByMoveBody; + +impl<'tcx> MirPass<'tcx> for ByMoveBody { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { + let Some(coroutine_def_id) = body.source.def_id().as_local() else { + return; + }; + let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) = + tcx.coroutine_kind(coroutine_def_id) + else { + return; + }; + let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!() }; + + let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); + if coroutine_kind == ty::ClosureKind::FnOnce { + return; + } + + let mut by_ref_fields = FxIndexSet::default(); + let by_move_upvars = Ty::new_tup_from_iter( + tcx, + tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| { + if capture.is_by_ref() { + by_ref_fields.insert(FieldIdx::from_usize(idx)); + } + capture.place.ty() + }), + ); + let by_move_coroutine_ty = Ty::new_coroutine( + tcx, + coroutine_def_id.to_def_id(), + ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args: args.as_coroutine().parent_args(), + kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce), + resume_ty: args.as_coroutine().resume_ty(), + yield_ty: args.as_coroutine().yield_ty(), + return_ty: args.as_coroutine().return_ty(), + witness: args.as_coroutine().witness(), + tupled_upvars_ty: by_move_upvars, + }, + ) + .args, + ); + + let mut by_move_body = body.clone(); + MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body); + dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); + by_move_body.source = mir::MirSource { + instance: InstanceDef::CoroutineKindShim { + coroutine_def_id: coroutine_def_id.to_def_id(), + target_kind: ty::ClosureKind::FnOnce, + }, + promoted: None, + }; + body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); + + // If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body. + // This is actually just a copy of the by-ref body, but with a different self type. + // FIXME(async_closures): We could probably unify this with the by-ref body somehow. + if coroutine_kind == ty::ClosureKind::Fn { + let by_mut_coroutine_ty = Ty::new_coroutine( + tcx, + coroutine_def_id.to_def_id(), + ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args: args.as_coroutine().parent_args(), + kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut), + resume_ty: args.as_coroutine().resume_ty(), + yield_ty: args.as_coroutine().yield_ty(), + return_ty: args.as_coroutine().return_ty(), + witness: args.as_coroutine().witness(), + tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(), + }, + ) + .args, + ); + let mut by_mut_body = body.clone(); + by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty; + dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(())); + by_mut_body.source = mir::MirSource { + instance: InstanceDef::CoroutineKindShim { + coroutine_def_id: coroutine_def_id.to_def_id(), + target_kind: ty::ClosureKind::FnMut, + }, + promoted: None, + }; + body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body); + } + } +} + +struct MakeByMoveBody<'tcx> { + tcx: TyCtxt<'tcx>, + by_ref_fields: FxIndexSet, + by_move_coroutine_ty: Ty<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_place( + &mut self, + place: &mut mir::Place<'tcx>, + context: mir::visit::PlaceContext, + location: mir::Location, + ) { + if place.local == ty::CAPTURE_STRUCT_LOCAL + && !place.projection.is_empty() + && let mir::ProjectionElem::Field(idx, ty) = place.projection[0] + && self.by_ref_fields.contains(&idx) + { + let (begin, end) = place.projection[1..].split_first().unwrap(); + // FIXME(async_closures): I'm actually a bit surprised to see that we always + // initially deref the by-ref upvars. If this is not actually true, then we + // will at least get an ICE that explains why this isn't true :^) + assert_eq!(*begin, mir::ProjectionElem::Deref); + // Peel one ref off of the ty. + let peeled_ty = ty.builtin_deref(true).unwrap().ty; + *place = mir::Place { + local: place.local, + projection: self.tcx.mk_place_elems_from_iter( + [mir::ProjectionElem::Field(idx, peeled_ty)] + .into_iter() + .chain(end.iter().copied()), + ), + }; + } + self.super_place(place, context, 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; + } + } +} diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index a11d224e8f1b5..3aa41250fd37b 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -59,167 +59,154 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { _ => {} } - trace!("InstrumentCoverage starting for {def_id:?}"); - Instrumentor::new(tcx, mir_body).inject_counters(); - trace!("InstrumentCoverage done for {def_id:?}"); + instrument_function_for_coverage(tcx, mir_body); } } -struct Instrumentor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - mir_body: &'a mut mir::Body<'tcx>, - hir_info: ExtractedHirInfo, - basic_coverage_blocks: CoverageGraph, -} +fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { + let def_id = mir_body.source.def_id(); + let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered(); -impl<'a, 'tcx> Instrumentor<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local()); + let hir_info = extract_hir_info(tcx, def_id.expect_local()); + let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); - debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id()); - - let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); + //////////////////////////////////////////////////// + // Compute coverage spans from the `CoverageGraph`. + let Some(coverage_spans) = + spans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) + else { + // No relevant spans were found in MIR, so skip instrumenting this function. + return; + }; - Self { tcx, mir_body, hir_info, basic_coverage_blocks } + //////////////////////////////////////////////////// + // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure + // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` + // and all `Expression` dependencies (operands) are also generated, for any other + // `BasicCoverageBlock`s not already associated with a coverage span. + let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); + let coverage_counters = + CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans); + + let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters); + if mappings.is_empty() { + // No spans could be converted into valid mappings, so skip this function. + debug!("no spans could be converted into valid mappings; skipping"); + return; } - fn inject_counters(&'a mut self) { - //////////////////////////////////////////////////// - // Compute coverage spans from the `CoverageGraph`. - let Some(coverage_spans) = CoverageSpans::generate_coverage_spans( - self.mir_body, - &self.hir_info, - &self.basic_coverage_blocks, - ) else { - // No relevant spans were found in MIR, so skip instrumenting this function. - return; - }; - - //////////////////////////////////////////////////// - // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure - // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` - // and all `Expression` dependencies (operands) are also generated, for any other - // `BasicCoverageBlock`s not already associated with a coverage span. - let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); - let coverage_counters = CoverageCounters::make_bcb_counters( - &self.basic_coverage_blocks, - bcb_has_coverage_spans, - ); + inject_coverage_statements( + mir_body, + &basic_coverage_blocks, + bcb_has_coverage_spans, + &coverage_counters, + ); - let mappings = self.create_mappings(&coverage_spans, &coverage_counters); - if mappings.is_empty() { - // No spans could be converted into valid mappings, so skip this function. - debug!("no spans could be converted into valid mappings; skipping"); - return; - } + mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { + function_source_hash: hir_info.function_source_hash, + num_counters: coverage_counters.num_counters(), + expressions: coverage_counters.into_expressions(), + mappings, + })); +} - self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters); +/// For each coverage span extracted from MIR, create a corresponding +/// mapping. +/// +/// Precondition: All BCBs corresponding to those spans have been given +/// coverage counters. +fn create_mappings<'tcx>( + tcx: TyCtxt<'tcx>, + hir_info: &ExtractedHirInfo, + coverage_spans: &CoverageSpans, + coverage_counters: &CoverageCounters, +) -> Vec { + let source_map = tcx.sess.source_map(); + let body_span = hir_info.body_span; + + let source_file = source_map.lookup_source_file(body_span.lo()); + use rustc_session::RemapFileNameExt; + let file_name = Symbol::intern(&source_file.name.for_codegen(tcx.sess).to_string_lossy()); + + let term_for_bcb = |bcb| { + coverage_counters + .bcb_counter(bcb) + .expect("all BCBs with spans were given counters") + .as_term() + }; - self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { - function_source_hash: self.hir_info.function_source_hash, - num_counters: coverage_counters.num_counters(), - expressions: coverage_counters.into_expressions(), - mappings, - })); - } + coverage_spans + .all_bcb_mappings() + .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| { + let kind = match bcb_mapping_kind { + BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)), + }; + let code_region = make_code_region(source_map, file_name, span, body_span)?; + Some(Mapping { kind, code_region }) + }) + .collect::>() +} - /// For each coverage span extracted from MIR, create a corresponding - /// mapping. - /// - /// Precondition: All BCBs corresponding to those spans have been given - /// coverage counters. - fn create_mappings( - &self, - coverage_spans: &CoverageSpans, - coverage_counters: &CoverageCounters, - ) -> Vec { - let source_map = self.tcx.sess.source_map(); - let body_span = self.hir_info.body_span; - - let source_file = source_map.lookup_source_file(body_span.lo()); - use rustc_session::RemapFileNameExt; - let file_name = - Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); - - let term_for_bcb = |bcb| { - coverage_counters - .bcb_counter(bcb) - .expect("all BCBs with spans were given counters") - .as_term() +/// For each BCB node or BCB edge that has an associated coverage counter, +/// inject any necessary coverage statements into MIR. +fn inject_coverage_statements<'tcx>( + mir_body: &mut mir::Body<'tcx>, + basic_coverage_blocks: &CoverageGraph, + bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + coverage_counters: &CoverageCounters, +) { + // Process the counters associated with BCB nodes. + for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // The only purpose of expression-used statements is to detect + // when a mapping is unreachable, so we only inject them for + // expressions with one or more mappings. + BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb), }; - - coverage_spans - .all_bcb_mappings() - .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| { - let kind = match bcb_mapping_kind { - BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)), - }; - let code_region = make_code_region(source_map, file_name, span, body_span)?; - Some(Mapping { kind, code_region }) - }) - .collect::>() + if do_inject { + inject_statement( + mir_body, + make_mir_coverage_kind(counter_kind), + basic_coverage_blocks[bcb].leader_bb(), + ); + } } - /// For each BCB node or BCB edge that has an associated coverage counter, - /// inject any necessary coverage statements into MIR. - fn inject_coverage_statements( - &mut self, - bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, - coverage_counters: &CoverageCounters, - ) { - // Process the counters associated with BCB nodes. - for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { - let do_inject = match counter_kind { - // Counter-increment statements always need to be injected. - BcbCounter::Counter { .. } => true, - // The only purpose of expression-used statements is to detect - // when a mapping is unreachable, so we only inject them for - // expressions with one or more mappings. - BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb), - }; - if do_inject { - inject_statement( - self.mir_body, - self.make_mir_coverage_kind(counter_kind), - self.basic_coverage_blocks[bcb].leader_bb(), - ); - } + // Process the counters associated with BCB edges. + for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() { + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // BCB-edge expressions never have mappings, so they never need + // a corresponding statement. + BcbCounter::Expression { .. } => false, + }; + if !do_inject { + continue; } - // Process the counters associated with BCB edges. - for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() { - let do_inject = match counter_kind { - // Counter-increment statements always need to be injected. - BcbCounter::Counter { .. } => true, - // BCB-edge expressions never have mappings, so they never need - // a corresponding statement. - BcbCounter::Expression { .. } => false, - }; - if !do_inject { - continue; - } + // We need to inject a coverage statement into a new BB between the + // last BB of `from_bcb` and the first BB of `to_bcb`. + let from_bb = basic_coverage_blocks[from_bcb].last_bb(); + let to_bb = basic_coverage_blocks[to_bcb].leader_bb(); - // We need to inject a coverage statement into a new BB between the - // last BB of `from_bcb` and the first BB of `to_bcb`. - let from_bb = self.basic_coverage_blocks[from_bcb].last_bb(); - let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb(); - - let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); - debug!( - "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ + let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb); + debug!( + "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}", - ); + ); - // Inject a counter into the newly-created BB. - inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb); - } + // Inject a counter into the newly-created BB. + inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb); } +} - fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { - match *counter_kind { - BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, - BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, - } +fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind { + match *counter_kind { + BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, + BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, } } @@ -329,7 +316,7 @@ fn make_code_region( start_line = source_map.doctest_offset_line(&file.name, start_line); end_line = source_map.doctest_offset_line(&file.name, end_line); - Some(CodeRegion { + check_code_region(CodeRegion { file_name, start_line: start_line as u32, start_col: start_col as u32, @@ -338,6 +325,39 @@ fn make_code_region( }) } +/// If `llvm-cov` sees a code region that is improperly ordered (end < start), +/// it will immediately exit with a fatal error. To prevent that from happening, +/// discard regions that are improperly ordered, or might be interpreted in a +/// way that makes them improperly ordered. +fn check_code_region(code_region: CodeRegion) -> Option { + let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region; + + // Line/column coordinates are supposed to be 1-based. If we ever emit + // coordinates of 0, `llvm-cov` might misinterpret them. + let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0); + // Coverage mappings use the high bit of `end_col` to indicate that a + // region is actually a "gap" region, so make sure it's unset. + let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0; + // If a region is improperly ordered (end < start), `llvm-cov` will exit + // with a fatal error, which is inconvenient for users and hard to debug. + let is_ordered = (start_line, start_col) <= (end_line, end_col); + + if all_nonzero && end_col_has_high_bit_unset && is_ordered { + Some(code_region) + } else { + debug!( + ?code_region, + ?all_nonzero, + ?end_col_has_high_bit_unset, + ?is_ordered, + "Skipping code region that would be misinterpreted or rejected by LLVM" + ); + // If this happens in a debug build, ICE to make it easier to notice. + debug_assert!(false, "Improper code region: {code_region:?}"); + None + } +} + fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // Only instrument functions, methods, and closures (not constants since they are evaluated // at compile time by Miri). @@ -351,7 +371,18 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } + // Don't instrument functions with `#[automatically_derived]` on their + // enclosing impl block, on the assumption that most users won't care about + // coverage for derived impls. + if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id()) + && tcx.is_automatically_derived(impl_of) + { + trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)"); + return false; + } + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)"); return false; } @@ -363,7 +394,9 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { struct ExtractedHirInfo { function_source_hash: u64, is_async_fn: bool, - fn_sig_span: Span, + /// The span of the function's signature, extended to the start of `body_span`. + /// Must have the same context and filename as the body span. + fn_sig_span_extended: Option, body_span: Span, } @@ -376,13 +409,25 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir hir::map::associated_body(hir_node).expect("HIR node is a function with body"); let hir_body = tcx.hir().body(fn_body_id); - let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async()); - let body_span = get_body_span(tcx, hir_body, def_id); + let maybe_fn_sig = hir_node.fn_sig(); + let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async()); + + let mut body_span = hir_body.value.span; + + use rustc_hir::{Closure, Expr, ExprKind, Node}; + // Unexpand a closure's body span back to the context of its declaration. + // This helps with closure bodies that consist of just a single bang-macro, + // and also with closure bodies produced by async desugaring. + if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) = + hir_node + { + body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span); + } // The actual signature span is only used if it has the same context and // filename as the body, and precedes the body. - let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span); - let fn_sig_span = maybe_fn_sig_span + let fn_sig_span_extended = maybe_fn_sig + .map(|fn_sig| fn_sig.span) .filter(|&fn_sig_span| { let source_map = tcx.sess.source_map(); let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); @@ -392,39 +437,15 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir && file_idx(fn_sig_span) == file_idx(body_span) }) // If so, extend it to the start of the body span. - .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo())) - // Otherwise, create a dummy signature span at the start of the body. - .unwrap_or_else(|| body_span.shrink_to_lo()); + .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo())); let function_source_hash = hash_mir_source(tcx, hir_body); - ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span } -} - -fn get_body_span<'tcx>( - tcx: TyCtxt<'tcx>, - hir_body: &rustc_hir::Body<'tcx>, - def_id: LocalDefId, -) -> Span { - let mut body_span = hir_body.value.span; - - if tcx.is_closure_or_coroutine(def_id.to_def_id()) { - // If the current function is a closure, and its "body" span was created - // by macro expansion or compiler desugaring, try to walk backwards to - // the pre-expansion call site or body. - body_span = body_span.source_callsite(); - } - - body_span + ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span_extended, body_span } } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { // FIXME(cjgillot) Stop hashing HIR manually here. let owner = hir_body.id().hir_id.owner; - tcx.hir_owner_nodes(owner) - .unwrap() - .opt_hash_including_bodies - .unwrap() - .to_smaller_hash() - .as_u64() + tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64() } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 81f6c8312061b..d3d0c7bcc9501 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -3,7 +3,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir; use rustc_span::{BytePos, Span, DUMMY_SP}; -use super::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::ExtractedHirInfo; mod from_mir; @@ -26,52 +26,63 @@ pub(super) struct CoverageSpans { } impl CoverageSpans { - /// Extracts coverage-relevant spans from MIR, and associates them with - /// their corresponding BCBs. - /// - /// Returns `None` if no coverage-relevant spans could be extracted. - pub(super) fn generate_coverage_spans( - mir_body: &mir::Body<'_>, - hir_info: &ExtractedHirInfo, - basic_coverage_blocks: &CoverageGraph, - ) -> Option { - let mut mappings = vec![]; - - let coverage_spans = CoverageSpansGenerator::generate_coverage_spans( + pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { + self.bcb_has_mappings.contains(bcb) + } + + pub(super) fn all_bcb_mappings(&self) -> impl Iterator { + self.mappings.iter() + } +} + +/// Extracts coverage-relevant spans from MIR, and associates them with +/// their corresponding BCBs. +/// +/// Returns `None` if no coverage-relevant spans could be extracted. +pub(super) fn generate_coverage_spans( + mir_body: &mir::Body<'_>, + hir_info: &ExtractedHirInfo, + basic_coverage_blocks: &CoverageGraph, +) -> Option { + let mut mappings = vec![]; + + if hir_info.is_async_fn { + // An async function desugars into a function that returns a future, + // with the user code wrapped in a closure. Any spans in the desugared + // outer function will be unhelpful, so just keep the signature span + // and ignore all of the spans in the MIR body. + if let Some(span) = hir_info.fn_sig_span_extended { + mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span }); + } + } else { + let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans( mir_body, hir_info, basic_coverage_blocks, ); + let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans); mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| { // Each span produced by the generator represents an ordinary code region. BcbMapping { kind: BcbMappingKind::Code(bcb), span } })); - - if mappings.is_empty() { - return None; - } - - // Identify which BCBs have one or more mappings. - let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - let mut insert = |bcb| { - bcb_has_mappings.insert(bcb); - }; - for &BcbMapping { kind, span: _ } in &mappings { - match kind { - BcbMappingKind::Code(bcb) => insert(bcb), - } - } - - Some(Self { bcb_has_mappings, mappings }) } - pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { - self.bcb_has_mappings.contains(bcb) + if mappings.is_empty() { + return None; } - pub(super) fn all_bcb_mappings(&self) -> impl Iterator { - self.mappings.iter() + // Identify which BCBs have one or more mappings. + let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut insert = |bcb| { + bcb_has_mappings.insert(bcb); + }; + for &BcbMapping { kind, span: _ } in &mappings { + match kind { + BcbMappingKind::Code(bcb) => insert(bcb), + } } + + Some(CoverageSpans { bcb_has_mappings, mappings }) } /// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that @@ -130,7 +141,7 @@ impl CoverageSpan { /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) -struct CoverageSpansGenerator<'a> { +struct SpansRefiner<'a> { /// The BasicCoverageBlock Control Flow Graph (BCB CFG). basic_coverage_blocks: &'a CoverageGraph, @@ -173,40 +184,15 @@ struct CoverageSpansGenerator<'a> { refined_spans: Vec, } -impl<'a> CoverageSpansGenerator<'a> { - /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be - /// counted. - /// - /// The basic steps are: - /// - /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each - /// `BasicCoverageBlockData`. - /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position - /// are sorted with longer spans before shorter spans; and equal spans are sorted - /// (deterministically) based on "dominator" relationship (if any). - /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, - /// if another span or spans are already counting the same code region), or should be merged - /// into a broader combined span (because it represents a contiguous, non-branching, and - /// uninterrupted region of source code). - /// - /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since - /// closures have their own MIR, their `Span` in their enclosing function should be left - /// "uncovered". - /// - /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need - /// to be). - pub(super) fn generate_coverage_spans( - mir_body: &mir::Body<'_>, - hir_info: &ExtractedHirInfo, +impl<'a> SpansRefiner<'a> { + /// Takes the initial list of (sorted) spans extracted from MIR, and "refines" + /// them by merging compatible adjacent spans, removing redundant spans, + /// and carving holes in spans when they overlap in unwanted ways. + fn refine_sorted_spans( basic_coverage_blocks: &'a CoverageGraph, + sorted_spans: Vec, ) -> Vec { - let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans( - mir_body, - hir_info, - basic_coverage_blocks, - ); - - let coverage_spans = Self { + let this = Self { basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, @@ -217,7 +203,7 @@ impl<'a> CoverageSpansGenerator<'a> { refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), }; - coverage_spans.to_refined_spans() + this.to_refined_spans() } /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 1b6dfccd57495..01fae7c0bec86 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -12,30 +12,32 @@ use crate::coverage::graph::{ use crate::coverage::spans::CoverageSpan; use crate::coverage::ExtractedHirInfo; +/// Traverses the MIR body to produce an initial collection of coverage-relevant +/// spans, each associated with a node in the coverage graph (BCB) and possibly +/// other metadata. +/// +/// The returned spans are sorted in a specific order that is expected by the +/// subsequent span-refinement step. pub(super) fn mir_to_initial_sorted_coverage_spans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> Vec { - let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info; - - let mut initial_spans = vec![SpanFromMir::for_fn_sig(fn_sig_span)]; - - if is_async_fn { - // An async function desugars into a function that returns a future, - // with the user code wrapped in a closure. Any spans in the desugared - // outer function will be unhelpful, so just keep the signature span - // and ignore all of the spans in the MIR body. - } else { - for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { - initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); - } + let &ExtractedHirInfo { body_span, .. } = hir_info; - // If no spans were extracted from the body, discard the signature span. - // FIXME: This preserves existing behavior; consider getting rid of it. - if initial_spans.len() == 1 { - initial_spans.clear(); - } + let mut initial_spans = vec![]; + + for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { + initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); + } + + // Only add the signature span if we found at least one span in the body. + if !initial_spans.is_empty() { + // If there is no usable signature span, add a fake one (before refinement) + // to avoid an ugly gap between the body start and the first real span. + // FIXME: Find a more principled way to solve this problem. + let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()); + initial_spans.push(SpanFromMir::for_fn_sig(fn_sig_span)); } initial_spans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); @@ -154,7 +156,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool { match statement.kind { StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { - AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) => true, + AggregateKind::Closure(_, _) + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(..) => true, _ => false, }, _ => false, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index ad12bce9b0232..6a37047a69387 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -696,6 +696,7 @@ fn try_write_constant<'tcx>( | ty::Bound(..) | ty::Placeholder(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"), diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 2ee660ddc9be1..30de40e226c33 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_errors::{ - Applicability, DecorateLint, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, + codes::*, Applicability, DecorateLint, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -33,7 +33,7 @@ pub(crate) enum ConstMutate { } #[derive(Diagnostic)] -#[diag(mir_transform_unaligned_packed_ref, code = "E0793")] +#[diag(mir_transform_unaligned_packed_ref, code = E0793)] #[note] #[note(mir_transform_note_ub)] #[help] @@ -66,7 +66,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for RequiresUnsafe { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::mir_transform_requires_unsafe); - diag.code("E0133".to_string()); + diag.code(E0133); diag.span(self.span); diag.span_label(self.span, self.details.label()); let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); @@ -125,7 +125,7 @@ impl RequiresUnsafeDetail { diag.arg( "missing_target_features", DiagnosticArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), ); diag.arg("missing_target_features_count", missing.len()); @@ -136,7 +136,7 @@ impl RequiresUnsafeDetail { DiagnosticArgValue::StrListSepByAnd( build_enabled .iter() - .map(|feature| Cow::from(feature.as_str())) + .map(|feature| Cow::from(feature.to_string())) .collect(), ), ); @@ -201,45 +201,39 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { } } -pub(crate) enum AssertLint

{ - ArithmeticOverflow(Span, AssertKind

), - UnconditionalPanic(Span, AssertKind

), +pub(crate) struct AssertLint

{ + pub span: Span, + pub assert_kind: AssertKind

, + pub lint_kind: AssertLintKind, +} + +pub(crate) enum AssertLintKind { + ArithmeticOverflow, + UnconditionalPanic, } impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint

{ fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { - let span = self.span(); - let assert_kind = self.panic(); - let message = assert_kind.diagnostic_message(); - assert_kind.add_args(&mut |name, value| { + let message = self.assert_kind.diagnostic_message(); + self.assert_kind.add_args(&mut |name, value| { diag.arg(name, value); }); - diag.span_label(span, message); + diag.span_label(self.span, message); } fn msg(&self) -> DiagnosticMessage { - match self { - AssertLint::ArithmeticOverflow(..) => fluent::mir_transform_arithmetic_overflow, - AssertLint::UnconditionalPanic(..) => fluent::mir_transform_operation_will_panic, + match self.lint_kind { + AssertLintKind::ArithmeticOverflow => fluent::mir_transform_arithmetic_overflow, + AssertLintKind::UnconditionalPanic => fluent::mir_transform_operation_will_panic, } } } -impl

AssertLint

{ +impl AssertLintKind { pub fn lint(&self) -> &'static Lint { match self { - AssertLint::ArithmeticOverflow(..) => lint::builtin::ARITHMETIC_OVERFLOW, - AssertLint::UnconditionalPanic(..) => lint::builtin::UNCONDITIONAL_PANIC, - } - } - pub fn span(&self) -> Span { - match self { - AssertLint::ArithmeticOverflow(sp, _) | AssertLint::UnconditionalPanic(sp, _) => *sp, - } - } - pub fn panic(self) -> AssertKind

Foo bar

"); + t( + "# Foo bar", + "

§Foo bar

", + ); t( "## Foo-bar_baz qux", "

\ - Foo-bar_baz qux

", + §\ + Foo-bar_baz qux\ + ", ); t( "### **Foo** *bar* baz!?!& -_qux_-%", "

\ - Foo \ - bar baz!?!& -qux-%\ + §\ + Foo bar baz!?!& -qux-%\

", ); t( "#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", "
\ - Foo? & *bar?!* \ - baz ❤ #qux\ + §\ + Foo? & *bar?!* baz ❤ #qux\
", ); + t( + "# Foo [bar](https://hello.yo)", + "

\ + §\ + Foo bar\ +

", + ); } #[test] @@ -351,12 +363,36 @@ fn test_header_ids_multiple_blocks() { assert_eq!(output, expect, "original: {}", input); } - t(&mut map, "# Example", "

Example

"); - t(&mut map, "# Panics", "

Panics

"); - t(&mut map, "# Example", "

Example

"); - t(&mut map, "# Search", "

Search

"); - t(&mut map, "# Example", "

Example

"); - t(&mut map, "# Panics", "

Panics

"); + t( + &mut map, + "# Example", + "

§Example

", + ); + t( + &mut map, + "# Panics", + "

§Panics

", + ); + t( + &mut map, + "# Example", + "

§Example

", + ); + t( + &mut map, + "# Search", + "

§Search

", + ); + t( + &mut map, + "# Example", + "

§Example

", + ); + t( + &mut map, + "# Panics", + "

§Panics

", + ); } #[test] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index bea5ccd7c860d..ac7ae291d29b3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1207,17 +1207,31 @@ impl<'a> AssocItemLink<'a> { } } -fn write_impl_section_heading(mut w: impl fmt::Write, title: &str, id: &str) { +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, - "

\ + "

\ {title}\ §\ -

" + {extra}", ) .unwrap(); } +fn write_impl_section_heading(w: &mut impl fmt::Write, title: &str, id: &str) { + write_section_heading(w, title, id, None, "") +} + pub(crate) fn render_all_impls( mut w: impl Write, cx: &mut Context<'_>, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3b91fbdcb29dd..71186319e07dd 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -19,8 +19,8 @@ use super::{ item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw, - render_stability_since_raw_with_extra, AssocItemLink, AssocItemRender, Context, - ImplRenderingParameters, RenderMode, + render_stability_since_raw_with_extra, write_section_heading, AssocItemLink, AssocItemRender, + Context, ImplRenderingParameters, RenderMode, }; use crate::clean; use crate::config::ModuleSorting; @@ -425,13 +425,12 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: w.write_str(ITEM_TABLE_CLOSE); } last_section = Some(my_section); - write!( + write_section_heading( w, - "

\ - {name}\ -

{ITEM_TABLE_OPEN}", - id = cx.derive_id(my_section.id()), - name = my_section.name(), + my_section.name(), + &cx.derive_id(my_section.id()), + None, + ITEM_TABLE_OPEN, ); } @@ -814,16 +813,6 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Trait documentation write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { - write!( - w, - "

\ - {1}§\ -

{2}", - id, title, extra_content - ) - } - fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) { let name = m.name.unwrap(); info!("Documenting {name} on {ty_name:?}", ty_name = t.name); @@ -857,10 +846,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } if !required_types.is_empty() { - write_small_section_header( + write_section_heading( w, - "required-associated-types", "Required Associated Types", + "required-associated-types", + None, "
", ); for t in required_types { @@ -869,10 +859,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); } if !provided_types.is_empty() { - write_small_section_header( + write_section_heading( w, - "provided-associated-types", "Provided Associated Types", + "provided-associated-types", + None, "
", ); for t in provided_types { @@ -882,10 +873,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } if !required_consts.is_empty() { - write_small_section_header( + write_section_heading( w, - "required-associated-consts", "Required Associated Constants", + "required-associated-consts", + None, "
", ); for t in required_consts { @@ -894,10 +886,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); } if !provided_consts.is_empty() { - write_small_section_header( + write_section_heading( w, - "provided-associated-consts", "Provided Associated Constants", + "provided-associated-consts", + None, "
", ); for t in provided_consts { @@ -908,10 +901,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Output the documentation for each function individually if !required_methods.is_empty() || must_implement_one_of_functions.is_some() { - write_small_section_header( + write_section_heading( w, - "required-methods", "Required Methods", + "required-methods", + None, "
", ); @@ -929,10 +923,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); } if !provided_methods.is_empty() { - write_small_section_header( + write_section_heading( w, - "provided-methods", "Provided Methods", + "provided-methods", + None, "
", ); for m in provided_methods { @@ -949,10 +944,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let mut extern_crates = FxHashSet::default(); if !t.is_object_safe(cx.tcx()) { - write_small_section_header( + write_section_heading( w, - "object-safety", "Object Safety", + "object-safety", + None, &format!( "
This trait is not \ \ @@ -996,7 +992,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: foreign.sort_by_cached_key(|i| ImplString::new(i, cx)); if !foreign.is_empty() { - write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); + 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); @@ -1021,10 +1017,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } } - write_small_section_header( + write_section_heading( w, - "implementors", "Implementors", + "implementors", + None, "
", ); for implementor in concrete { @@ -1033,10 +1030,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); if t.is_auto(tcx) { - write_small_section_header( + write_section_heading( w, - "synthetic-implementors", "Auto implementors", + "synthetic-implementors", + None, "
", ); for implementor in synthetic { @@ -1054,18 +1052,20 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } 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_small_section_header( + write_section_heading( w, - "implementors", "Implementors", + "implementors", + None, "
", ); if t.is_auto(tcx) { - write_small_section_header( + write_section_heading( w, - "synthetic-implementors", "Auto implementors", + "synthetic-implementors", + None, "
", ); } @@ -1248,11 +1248,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); if let Some(inner_type) = &t.inner_type { - write!( - w, - "

\ - Aliased Type§

" - ); + write_section_heading(w, "Aliased Type", "aliased-type", None, ""); match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { @@ -1673,16 +1669,14 @@ fn item_variants( enum_def_id: DefId, ) { let tcx = cx.tcx(); - write!( + write_section_heading( w, - "

\ - Variants{}§\ -

\ - {}\ -
", - document_non_exhaustive_header(it), - document_non_exhaustive(it) + &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() { @@ -1930,16 +1924,12 @@ fn item_fields( .peekable(); if let None | Some(CtorKind::Fn) = ctor_kind { if fields.peek().is_some() { - write!( - w, - "

\ - {}{}§\ -

\ - {}", + let title = format!( + "{}{}", if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it), - document_non_exhaustive(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()); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 6408e97df500d..fbd45b2b48ef9 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -593,11 +593,17 @@ else if (window.initSearch) window.initSearch(searchIndex); ret }) .collect::>(); - let impls = format!( - r#""{}":{}"#, - krate.name(cx.tcx()), - serde_json::to_string(&impls).expect("failed serde conversion"), - ); + + // FIXME: this fixes only rustdoc part of instability of trait impls + // for js files, see #120371 + // Manually collect to string and sort to make list not depend on order + let mut impls = impls + .iter() + .map(|i| serde_json::to_string(i).expect("failed serde conversion")) + .collect::>(); + impls.sort(); + + let impls = format!(r#""{}":[{}]"#, krate.name(cx.tcx()), impls.join(",")); let mut mydst = dst.clone(); for part in &aliased_type.target_fqp[..aliased_type.target_fqp.len() - 1] { @@ -702,11 +708,16 @@ else if (window.initSearch) window.initSearch(searchIndex); continue; } - let implementors = format!( - r#""{}":{}"#, - krate.name(cx.tcx()), - serde_json::to_string(&implementors).expect("failed serde conversion"), - ); + // FIXME: this fixes only rustdoc part of instability of trait impls + // for js files, see #120371 + // Manually collect to string and sort to make list not depend on order + let mut implementors = implementors + .iter() + .map(|i| serde_json::to_string(i).expect("failed serde conversion")) + .collect::>(); + implementors.sort(); + + let implementors = format!(r#""{}":[{}]"#, krate.name(cx.tcx()), implementors.join(",")); let mut mydst = dst.clone(); for part in &remote_path[..remote_path.len() - 1] { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index cd53fcb8b7c16..c01a25534f9f9 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -638,7 +638,7 @@ ul.block, .block li { .sidebar-crate h2 a { display: block; - margin: 0 calc(-24px + 0.25rem) 0 -0.5rem; + margin: 0 calc(-24px + 0.25rem) 0 -0.2rem; /* Align the sidebar crate link with the search bar, which have different font sizes. @@ -653,7 +653,7 @@ ul.block, .block li { x = ( 16px - 0.57rem ) / 2 */ padding: calc( ( 16px - 0.57rem ) / 2 ) 0.25rem; - padding-left: 0.5rem; + padding-left: 0.2rem; } .sidebar-crate h2 .version { @@ -661,8 +661,6 @@ ul.block, .block li { font-weight: normal; font-size: 1rem; overflow-wrap: break-word; - /* opposite of the link padding, cut in half again */ - margin-top: calc( ( -16px + 0.57rem ) / 2 ); } .sidebar-crate + .version { @@ -849,11 +847,30 @@ nav.sub { h2.section-header > .anchor { padding-right: 6px; } +a.doc-anchor { + color: var(--main-color); + display: none; + position: absolute; + left: -17px; + /* We add this padding so that when the cursor moves from the heading's text to the anchor, + the anchor doesn't disappear. */ + padding-right: 5px; + /* And this padding is used to make the anchor larger and easier to click on. */ + padding-left: 3px; +} +*:hover > .doc-anchor { + display: block; +} +/* If the first element of the top doc block is a heading, we don't want to ever display its anchor +because of the `[-]` element which would overlap with it. */ +.top-doc > .docblock > *:first-child > .doc-anchor { + display: none !important; +} .main-heading a:hover, .example-wrap .rust a:hover, .all-items a:hover, -.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, +.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor), .docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, .item-info a { text-decoration: underline; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 88901191cda25..b46701b55ea7a 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1721,6 +1721,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm } currentPointerId = e.pointerId; } + window.hideAllModals(false); e.preventDefault(); window.addEventListener("pointermove", resize, false); window.addEventListener("pointercancel", stopResize, false); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index ac9c6f377b82a..bda7b3c647e7e 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -101,6 +101,14 @@ const getVar = (function getVar(name) { }); function switchTheme(newThemeName, saveTheme) { + const themeNames = getVar("themes").split(",").filter(t => t); + themeNames.push(...builtinThemes); + + // Ensure that the new theme name is among the defined themes + if (themeNames.indexOf(newThemeName) === -1) { + return; + } + // If this new value comes from a system setting or from the previously // saved theme, no need to save it. if (saveTheme) { @@ -115,7 +123,7 @@ function switchTheme(newThemeName, saveTheme) { window.currentTheme = null; } } else { - const newHref = getVar("root-path") + newThemeName + + const newHref = getVar("root-path") + encodeURIComponent(newThemeName) + getVar("resource-suffix") + ".css"; if (!window.currentTheme) { // If we're in the middle of loading, document.write blocks diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index 8db7986fa7506..b1c1d5a63a03c 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -1,8 +1,8 @@

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

{# #} Fields§ {# #} @@ -12,13 +12,13 @@

{# #} {# #} § {# #} - {{ name }}: {{+ self.print_ty(ty) | safe }} {# #} + {{ name }}: {{+ self.print_ty(ty)|safe }} {# #} {% if let Some(stability_class) = self.stability_field(field) %} {% endif %} - {{ self.document_field(field) | safe }} + {{ self.document_field(field)|safe }} {% endfor %} {% endif %} -{{ self.render_assoc_items() | safe }} -{{ self.document_type_layout() | safe }} +{{ self.render_assoc_items()|safe }} +{{ self.document_type_layout()|safe }} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d962beda4beed..8c10f14116a0c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,7 +3,6 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] -#![feature(array_methods)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -796,7 +795,7 @@ fn main_args( compiler.enter(|queries| { let mut gcx = abort_on_err(queries.global_ctxt(), sess); - if sess.dcx().has_errors_or_lint_errors().is_some() { + if sess.dcx().has_errors().is_some() { sess.dcx().fatal("Compilation failed, aborting rustdoc"); } diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index a931e8804d9cb..0603aae553609 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -126,7 +126,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item if should_have_doc_example(cx, item) { debug!("reporting error for {item:?} (hir_id={hir_id:?})"); let sp = item.attr_span(cx.tcx); - cx.tcx.struct_span_lint_hir( + cx.tcx.node_span_lint( crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, @@ -137,7 +137,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item } else if tests.found_tests > 0 && !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id()) { - cx.tcx.struct_span_lint_hir( + cx.tcx.node_span_lint( crate::lint::PRIVATE_DOC_TESTS, hir_id, item.attr_span(cx.tcx), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 30b3e5c784dc1..fe02611b5d449 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -108,15 +108,13 @@ impl Res { Res::Primitive(_) => return Suggestion::Prefix("prim"), Res::Def(kind, _) => kind, }; - if kind == DefKind::Macro(MacroKind::Bang) { - return Suggestion::Macro; - } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return Suggestion::Function; - } else if kind == DefKind::Field { - return Suggestion::RemoveDisambiguator; - } let prefix = match kind { + DefKind::Fn | DefKind::AssocFn => return Suggestion::Function, + DefKind::Field => return Suggestion::RemoveDisambiguator, + DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro, + + DefKind::Macro(MacroKind::Derive) => "derive", DefKind::Struct => "struct", DefKind::Enum => "enum", DefKind::Trait => "trait", @@ -126,7 +124,6 @@ impl Res { "const" } DefKind::Static(_) => "static", - DefKind::Macro(MacroKind::Derive) => "derive", // Now handle things that don't have a specific disambiguator _ => match kind .ns() @@ -283,20 +280,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { debug!("looking for enum variant {path_str}"); let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = split - .next() - .map(|f| Symbol::intern(f)) - .expect("fold_item should ensure link is non-empty"); - let variant_name = - // we're not sure this is a variant at all, so use the full string - // If there's no second component, the link looks like `[path]`. - // So there's no partial res and we should say the whole link failed to resolve. - split.next().map(|f| Symbol::intern(f)).ok_or_else(no_res)?; - let path = split - .next() - // If there's no third component, we saw `[a::b]` before and it failed to resolve. - // So there's no partial res. - .ok_or_else(no_res)?; + let variant_field_name = Symbol::intern(split.next().unwrap()); + // We're not sure this is a variant at all, so use the full string. + // If there's no second component, the link looks like `[path]`. + // So there's no partial res and we should say the whole link failed to resolve. + let variant_name = Symbol::intern(split.next().ok_or_else(no_res)?); + + // If there's no third component, we saw `[a::b]` before and it failed to resolve. + // So there's no partial res. + let path = split.next().ok_or_else(no_res)?; let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?; match ty_res { @@ -447,41 +439,29 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } // Try looking for methods and associated items. - let mut split = path_str.rsplitn(2, "::"); - // NB: `split`'s first element is always defined, even if the delimiter was not present. - // NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`). - let item_str = split.next().unwrap(); - let item_name = Symbol::intern(item_str); - let path_root = split - .next() + // NB: `path_root` could be empty when resolving in the root namespace (e.g. `::std`). + let (path_root, item_str) = path_str.rsplit_once("::").ok_or_else(|| { // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. - .ok_or_else(|| { - debug!("found no `::`, assuming {item_name} was correctly not in scope"); - UnresolvedPath { - item_id, - module_id, - partial_res: None, - unresolved: item_str.into(), - } - })?; + debug!("found no `::`, assuming {path_str} was correctly not in scope"); + UnresolvedPath { item_id, module_id, partial_res: None, unresolved: path_str.into() } + })?; + let item_name = Symbol::intern(item_str); // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support // links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity // error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all // primitives. - match resolve_primitive(&path_root, TypeNS) - .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id)) - .and_then(|ty_res| { - let candidates = self - .resolve_associated_item(ty_res, item_name, ns, module_id) + match resolve_primitive(path_root, TypeNS) + .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id)) + .map(|ty_res| { + self.resolve_associated_item(ty_res, item_name, ns, module_id) .into_iter() .map(|(res, def_id)| (res, Some(def_id))) - .collect::>(); - if !candidates.is_empty() { Some(candidates) } else { None } + .collect::>() }) { - Some(r) => Ok(r), - None => { + Some(r) if !r.is_empty() => Ok(r), + _ => { if ns == Namespace::ValueNS { self.variant_field(path_str, item_id, module_id) .map(|(res, def_id)| vec![(res, Some(def_id))]) @@ -523,6 +503,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } ty::Alias(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Dynamic(..) @@ -1263,7 +1244,7 @@ impl LinkCollector<'_, '_> { self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item); return None; } else { - candidates = vec![candidates[0]]; + candidates = vec![*candidate]; } } @@ -1271,8 +1252,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 candidates.len() > 1 && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) { - candidates = vec![candidates[0]]; + if let [candidate, _candidate2, ..] = *candidates + && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) + { + candidates = vec![candidate]; } if let &[(res, def_id)] = candidates.as_slice() { @@ -1322,12 +1305,11 @@ impl LinkCollector<'_, '_> { let mut err = ResolutionFailure::NotResolved(err); for other_ns in [TypeNS, ValueNS, MacroNS] { if other_ns != expected_ns { - if let Ok(res) = - self.resolve(path_str, other_ns, item_id, module_id) - && !res.is_empty() + if let Ok(&[res, ..]) = + self.resolve(path_str, other_ns, item_id, module_id).as_deref() { err = ResolutionFailure::WrongNamespace { - res: full_res(self.cx.tcx, res[0]), + res: full_res(self.cx.tcx, res), expected_ns, }; break; @@ -1704,7 +1686,7 @@ fn report_diagnostic( let sp = item.attr_span(tcx); - tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| { + tcx.node_span_lint(lint, hir_id, sp, msg, |lint| { let (span, link_range) = match link_range { MarkdownLinkRange::Destination(md_range) => { let mut md_range = md_range.clone(); @@ -1748,7 +1730,6 @@ fn report_diagnostic( lint.note(format!( "the link appears in this line:\n\n{line}\n\ {indicator: Option<(&str, &str)> { - let mut splitter = path.rsplitn(2, "::"); - splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) - } // Check if _any_ parent of the path gets resolved. // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. let mut name = path_str; 'outer: loop { - let Some((start, end)) = split(name) else { + // FIXME(jynelson): this might conflict with my `Self` fix in #76467 + let Some((start, end)) = name.rsplit_once("::") else { // avoid bug that marked [Quux::Z] as missing Z, not Quux if partial_res.is_none() { *unresolved = name.into(); @@ -1829,8 +1805,8 @@ fn resolution_failure( for ns in [TypeNS, ValueNS, MacroNS] { if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) { debug!("found partial_res={v_res:?}"); - if !v_res.is_empty() { - *partial_res = Some(full_res(tcx, v_res[0])); + if let Some(&res) = v_res.first() { + *partial_res = Some(full_res(tcx, res)); *unresolved = end.into(); break 'outer; } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index fc7ef4bcdfa97..e2a7ef8556ea6 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -22,7 +22,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let tcx = cx.tcx; // We need to check if there are errors before running this pass because it would crash when // we try to get auto and blanket implementations. - if tcx.dcx().has_errors_or_lint_errors().is_some() { + if tcx.dcx().has_errors().is_some() { return krate; } diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index bffa17da3b4c7..c6989fbbf255e 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -24,7 +24,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings) .unwrap_or_else(|| item.attr_span(cx.tcx)); - cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { + cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { lint.note("bare URLs are not automatically turned into clickable links") .span_suggestion( sp, diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 782938f10943f..6649894f9c25d 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -99,7 +99,7 @@ fn check_rust_syntax( // All points of divergence have been handled earlier so this can be // done the same way whether the span is precise or not. let hir_id = cx.tcx.local_def_id_to_hir_id(local_id); - cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| { + cx.tcx.node_span_lint(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| { let explanation = if is_ignore { "`ignore` code blocks require valid Rust code for syntax highlighting; \ mark blocks that do not contain Rust code as text" @@ -156,7 +156,7 @@ impl Translate for BufferEmitter { } impl Emitter for BufferEmitter { - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, diag: Diagnostic) { let mut buffer = self.buffer.borrow_mut(); let fluent_args = to_fluent_args(diag.args()); diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 90874c01102e5..da3770aa927af 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -25,7 +25,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { Some(sp) => sp, None => item.attr_span(tcx), }; - tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| { + tcx.node_span_lint(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| { use rustc_lint_defs::Applicability; // If a tag looks like ``, it might actually be a generic. // We don't try to detect stuff `` because that's not valid HTML, diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 73f6a42636064..9069098bf1a37 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -176,7 +176,7 @@ fn check_inline_or_reference_unknown_redundancy( &item.attrs.doc_strings, )?; - cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { + cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { lint.span_label(explicit_span, "explicit target is redundant") .span_label(display_span, "because label contains path that resolves to same destination") .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") @@ -226,7 +226,7 @@ fn check_reference_redundancy( &item.attrs.doc_strings, )?; - cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { + cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { lint.span_label(explicit_span, "explicit target is redundant") .span_label(display_span, "because label contains path that resolves to same destination") .span_note(def_span, "referenced explicit link target defined here") diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index 0893cd0b40b52..dbbf39362e316 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -56,7 +56,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { ) .unwrap_or_else(|| item.attr_span(tcx)); - tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| { + tcx.node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| { let mut help_emitted = false; match element.prev_code_guess { diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index df955421ba487..1bea93c784218 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -56,13 +56,10 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { | clean::TraitItem(..) | clean::FunctionItem(..) | clean::VariantItem(..) - | clean::MethodItem(..) | clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | clean::ConstantItem(..) | clean::UnionItem(..) - | clean::AssocConstItem(..) - | clean::AssocTypeItem(..) | clean::TraitAliasItem(..) | clean::MacroItem(..) | clean::ForeignTypeItem => { @@ -80,6 +77,16 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { } } + clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { + let item_id = i.item_id; + if item_id.is_local() + && !self.effective_visibilities.is_reachable(self.tcx, item_id.expect_def_id()) + { + debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); + return None; + } + } + clean::StructFieldItem(..) => { if i.visibility(self.tcx) != Some(Visibility::Public) { return Some(strip_item(i)); @@ -192,16 +199,16 @@ impl<'a> DocFolder for ImplStripper<'a, '_> { && imp.items.iter().all(|i| { let item_id = i.item_id; item_id.is_local() - && !is_item_reachable( - self.tcx, - self.is_json_output, - &self.cache.effective_visibilities, - item_id, - ) + && !self + .cache + .effective_visibilities + .is_reachable(self.tcx, item_id.expect_def_id()) }) { + debug!("ImplStripper: no public item; removing {imp:?}"); return None; } else if imp.items.is_empty() && i.doc_value().is_empty() { + debug!("ImplStripper: no item and no doc; removing {imp:?}"); return None; } } @@ -212,13 +219,13 @@ impl<'a> DocFolder for ImplStripper<'a, '_> { && !imp.for_.is_assoc_ty() && !self.should_keep_impl(&i, did) { - debug!("ImplStripper: impl item for stripped type; removing"); + debug!("ImplStripper: impl item for stripped type; removing {imp:?}"); return None; } if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) && !self.should_keep_impl(&i, did) { - debug!("ImplStripper: impl item for stripped trait; removing"); + debug!("ImplStripper: impl item for stripped trait; removing {imp:?}"); return None; } if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { @@ -226,7 +233,7 @@ impl<'a> DocFolder for ImplStripper<'a, '_> { if let Some(did) = typaram.def_id(self.cache) && !self.should_keep_impl(&i, did) { - debug!("ImplStripper: stripped item in trait's generics; removing impl"); + debug!("ImplStripper: stripped item in trait's generics; removing {imp:?}"); return None; } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 74bec5a2e11fd..b7d9c16f34837 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -311,7 +311,7 @@ pub(crate) fn run( // The visitor might have found a type error, which we need to // promote to a fatal error - if tcx.dcx().has_errors_or_lint_errors().is_some() { + if tcx.dcx().has_errors().is_some() { return Err(String::from("Compilation failed, aborting rustdoc")); } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 9ac97236f19c8..1ef8cf7de3cd5 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -121,6 +121,7 @@ static TARGETS: &[&str] = &[ "powerpc64-unknown-linux-gnu", "powerpc64le-unknown-linux-gnu", "riscv32i-unknown-none-elf", + "riscv32im-risc0-zkvm-elf", "riscv32im-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", diff --git a/src/tools/cargo b/src/tools/cargo index 1ae631085f01c..cdf84b69d0416 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1ae631085f01c1a72d05df1ec81f3759a8360042 +Subproject commit cdf84b69d0416c57ac9dc3459af80dfb4883d27a diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 4d32bbec914a7..5fa45ceeb39be 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5606,6 +5606,7 @@ Released 2018-09-13 [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl +[`suspicious_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_open_options [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn [`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned @@ -5814,6 +5815,7 @@ Released 2018-09-13 [`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments [`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles +[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 3b62ae0524ab0..7f7aff92bf19b 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -212,7 +212,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -768,7 +768,19 @@ Additional dotfiles (files or directories starting with a dot) to allow * [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) +## `allowed-duplicate-crates` +A list of crate names to allow duplicates of + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`multiple_crate_versions`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions) + + ## `enforce-iter-loop-reborrow` +Whether to recommend using implicit into iter for reborrowed values. + #### Example ```no_run let mut vec = vec![1, 2, 3]; @@ -793,7 +805,7 @@ for _ in &mut *rmvec {} ## `check-private-items` - +Whether to also run the listed lints on private items. **Default Value:** `false` @@ -806,9 +818,10 @@ for _ in &mut *rmvec {} ## `pub-underscore-fields-behavior` +Lint "public" fields in a struct that are prefixed with an underscore based on their +exported visibility, or whether they are marked as "pub". - -**Default Value:** `"PublicallyExported"` +**Default Value:** `"PubliclyExported"` --- **Affected lints:** diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml index 4a1805f75235e..8c405ac6a4e82 100644 --- a/src/tools/clippy/clippy.toml +++ b/src/tools/clippy/clippy.toml @@ -2,6 +2,6 @@ avoid-breaking-exported-api = false # use the various `span_lint_*` methods instead, which also add a link to the docs disallowed-methods = [ - "rustc_lint::context::LintContext::struct_span_lint", - "rustc_middle::ty::context::TyCtxt::struct_span_lint_hir" + "rustc_lint::context::LintContext::span_lint", + "rustc_middle::ty::context::TyCtxt::node_span_lint" ] diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 5477d9b83a72c..4e9ddbf8259d3 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -2,7 +2,9 @@ use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::ClippyConfiguration; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_session::Session; +use rustc_span::edit_distance::edit_distance; use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; use serde::de::{IgnoredAny, IntoDeserializer, MapAccess, Visitor}; use serde::{Deserialize, Deserializer, Serialize}; @@ -26,7 +28,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", - "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", + "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", @@ -59,18 +61,25 @@ impl TryConf { #[derive(Debug)] struct ConfError { message: String, + suggestion: Option, span: Span, } impl ConfError { fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self { let span = error.span().unwrap_or(0..file.source_len.0 as usize); - Self::spanned(file, error.message(), span) + Self::spanned(file, error.message(), None, span) } - fn spanned(file: &SourceFile, message: impl Into, span: Range) -> Self { + fn spanned( + file: &SourceFile, + message: impl Into, + suggestion: Option, + span: Range, + ) -> Self { Self { message: message.into(), + suggestion, span: Span::new( file.start_pos + BytePos::from_usize(span.start), file.start_pos + BytePos::from_usize(span.end), @@ -147,16 +156,18 @@ macro_rules! define_Conf { match Field::deserialize(name.get_ref().as_str().into_deserializer()) { Err(e) => { let e: FieldError = e; - errors.push(ConfError::spanned(self.0, e.0, name.span())); + errors.push(ConfError::spanned(self.0, e.error, e.suggestion, name.span())); } $(Ok(Field::$name) => { - $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), name.span()));)? + $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? let raw_value = map.next_value::>()?; let value_span = raw_value.span(); match <$ty>::deserialize(raw_value.into_inner()) { - Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), value_span)), + Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), None, value_span)), Ok(value) => match $name { - Some(_) => errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), name.span())), + Some(_) => { + errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); + } None => { $name = Some(value); // $new_conf is the same as one of the defined `$name`s, so @@ -165,7 +176,7 @@ macro_rules! define_Conf { Some(_) => errors.push(ConfError::spanned(self.0, concat!( "duplicate field `", stringify!($new_conf), "` (provided as `", stringify!($name), "`)" - ), name.span())), + ), None, name.span())), None => $new_conf = $name.clone(), })? }, @@ -523,7 +534,11 @@ define_Conf! { /// /// Additional dotfiles (files or directories starting with a dot) to allow (allowed_dotfiles: FxHashSet = FxHashSet::default()), - /// Lint: EXPLICIT_ITER_LOOP + /// Lint: MULTIPLE_CRATE_VERSIONS. + /// + /// A list of crate names to allow duplicates of + (allowed_duplicate_crates: FxHashSet = FxHashSet::default()), + /// Lint: EXPLICIT_ITER_LOOP. /// /// Whether to recommend using implicit into iter for reborrowed values. /// @@ -543,15 +558,15 @@ define_Conf! { /// for _ in &mut *rmvec {} /// ``` (enforce_iter_loop_reborrow: bool = false), - /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC + /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC. /// /// Whether to also run the listed lints on private items. (check_private_items: bool = false), - /// Lint: PUB_UNDERSCORE_FIELDS + /// Lint: PUB_UNDERSCORE_FIELDS. /// /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". - (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PublicallyExported), + (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported), } /// Search for the configuration file. @@ -669,10 +684,16 @@ impl Conf { // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { - sess.dcx().span_err( + let mut diag = sess.dcx().struct_span_err( error.span, format!("error reading Clippy's configuration file: {}", error.message), ); + + if let Some(sugg) = error.suggestion { + diag.span_suggestion(error.span, sugg.message, sugg.suggestion, Applicability::MaybeIncorrect); + } + + diag.emit(); } for warning in warnings { @@ -689,19 +710,31 @@ impl Conf { const SEPARATOR_WIDTH: usize = 4; #[derive(Debug)] -struct FieldError(String); +struct FieldError { + error: String, + suggestion: Option, +} + +#[derive(Debug)] +struct Suggestion { + message: &'static str, + suggestion: &'static str, +} impl std::error::Error for FieldError {} impl Display for FieldError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.pad(&self.0) + f.pad(&self.error) } } impl serde::de::Error for FieldError { fn custom(msg: T) -> Self { - Self(msg.to_string()) + Self { + error: msg.to_string(), + suggestion: None, + } } fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { @@ -723,7 +756,20 @@ impl serde::de::Error for FieldError { write!(msg, "{:SEPARATOR_WIDTH$}{field:column_width$}", " ").unwrap(); } } - Self(msg) + + let suggestion = expected + .iter() + .filter_map(|expected| { + let dist = edit_distance(field, expected, 4)?; + Some((dist, expected)) + }) + .min_by_key(|&(dist, _)| dist) + .map(|(_, suggestion)| Suggestion { + message: "perhaps you meant", + suggestion, + }); + + Self { error: msg, suggestion } } } diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs index f5dcb16d670df..533e375a3104c 100644 --- a/src/tools/clippy/clippy_config/src/lib.rs +++ b/src/tools/clippy/clippy_config/src/lib.rs @@ -11,6 +11,7 @@ extern crate rustc_ast; extern crate rustc_data_structures; #[allow(unused_extern_crates)] extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_session; extern crate rustc_span; diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs index baee09629ac44..435aa9244c522 100644 --- a/src/tools/clippy/clippy_config/src/types.rs +++ b/src/tools/clippy/clippy_config/src/types.rs @@ -129,6 +129,6 @@ unimplemented_serialize! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum PubUnderscoreFieldsBehaviour { - PublicallyExported, + PubliclyExported, AllPubFields, } diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index ce738e3f4ec7c..5ec67554e7d89 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -4,11 +4,11 @@ version = "0.0.1" edition = "2021" [dependencies] -aho-corasick = "0.7" +aho-corasick = "1.0" clap = "4.1.4" indoc = "1.0" itertools = "0.11" -opener = "0.5" +opener = "0.6" shell-escape = "0.1" walkdir = "2.3" diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 6b76a44debff7..2222abff7adfb 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -504,9 +504,8 @@ fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option(replacements.iter().map(|&(x, _)| x.as_bytes())) + .build(replacements.iter().map(|&(x, _)| x.as_bytes())) .unwrap(); let mut result = String::with_capacity(contents.len() + 1024); @@ -928,7 +927,7 @@ fn remove_line_splices(s: &str) -> String { .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); - unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| { + unescape::unescape_unicode(s, unescape::Mode::Str, &mut |range, ch| { if ch.is_ok() { res.push_str(&s[range]); } diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 8cba35f3d871c..416e9a680dd73 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] arrayvec = { version = "0.7", default-features = false } -cargo_metadata = "0.15.3" +cargo_metadata = "0.18" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 657d52d0e9e17..1102c7fb236b5 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -14,10 +14,10 @@ declare_clippy_lint! { /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. /// /// ### Why is this bad? - /// `Arc` is an Atomic `RC` and guarantees that updates to the reference counter are - /// Atomic. This is useful in multiprocessing scenarios. To send an `Arc` across processes - /// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E), - /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` + /// `Arc` is a thread-safe `Rc` and guarantees that updates to the reference counter + /// use atomic operations. To send an `Arc` across thread boundaries and + /// share ownership between multiple threads, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#thread-safety), + /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs index 1417e230aee5f..ff4dffd06079f 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs @@ -67,6 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { ); if let ExprKind::Block(block, _) = &cond.kind { + if !block.span.eq_ctxt(expr.span) { + // If the block comes from a macro, or as an argument to a macro, + // do not lint. + return; + } if block.rules == BlockCheckMode::DefaultBlock { if block.stmts.is_empty() { if let Some(ex) = &block.expr { diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index fea6924d89e91..d8107f61f371c 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -6,6 +6,7 @@ mod wildcard_dependencies; use cargo_metadata::MetadataCommand; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::impl_lint_pass; @@ -128,6 +129,8 @@ declare_clippy_lint! { /// ### Known problems /// Because this can be caused purely by the dependencies /// themselves, it's not always possible to fix this issue. + /// In those cases, you can allow that specific crate using + /// the `allowed_duplicate_crates` configuration option. /// /// ### Example /// ```toml @@ -163,6 +166,7 @@ declare_clippy_lint! { } pub struct Cargo { + pub allowed_duplicate_crates: FxHashSet, pub ignore_publish: bool, } @@ -208,7 +212,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata); + multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs index ec681adb7aef2..3f30a77fcfe47 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -3,27 +3,40 @@ use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId}; use clippy_utils::diagnostics::span_lint; use itertools::Itertools; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; use rustc_span::DUMMY_SP; use super::MULTIPLE_CRATE_VERSIONS; -pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { +pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, allowed_duplicate_crates: &FxHashSet) { let local_name = cx.tcx.crate_name(LOCAL_CRATE); let mut packages = metadata.packages.clone(); packages.sort_by(|a, b| a.name.cmp(&b.name)); if let Some(resolve) = &metadata.resolve && let Some(local_id) = packages.iter().find_map(|p| { - if p.name == local_name.as_str() { + // p.name contains the original crate names with dashes intact + // local_name contains the crate name as a namespace, with the dashes converted to underscores + // the code below temporarily rectifies this discrepancy + if p.name + .as_bytes() + .iter() + .map(|b| if b == &b'-' { &b'_' } else { b }) + .eq(local_name.as_str().as_bytes()) + { Some(&p.id) } else { None } }) { - for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { + for (name, group) in &packages + .iter() + .filter(|p| !allowed_duplicate_crates.contains(&p.name)) + .group_by(|p| &p.name) + { let group: Vec<&Package> = group.collect(); if group.len() <= 1 { diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 3761ba81f5219..bb86b6f30759c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -107,7 +107,7 @@ pub(super) fn check<'tcx>( && let Some(src) = snippet_opt(cx, cast_expr.span) && cast_to.is_floating_point() && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) - && let from_nbits = 128 - n.leading_zeros() + && let from_nbits = 128 - n.get().leading_zeros() && let to_nbits = fp_ty_mantissa_nbits(cast_to) && from_nbits != 0 && to_nbits != 0 diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 20230106d5366..639edd8da3012 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -439,6 +439,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, + crate::methods::SUSPICIOUS_OPEN_OPTIONS_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, crate::methods::TYPE_ID_ON_BOX_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index 2472e2ee76f93..e617c19eff09b 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::last_path_segment; use clippy_utils::source::snippet_with_context; +use clippy_utils::{last_path_segment, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -42,12 +42,14 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && ty.span.ctxt() == ctxt { let mut applicability = Applicability::MachineApplicable; - let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability); + let Some(path) = std_or_core(cx) else { return }; + let path = format!("{path}::iter::empty"); + let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability, &path); span_lint_and_sugg( cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, expr.span, - "`std::iter::empty()` is the more idiomatic way", + &format!("`{path}()` is the more idiomatic way"), "try", sugg, applicability, @@ -61,6 +63,7 @@ fn make_sugg( ty_path: &rustc_hir::QPath<'_>, ctxt: SyntaxContext, applicability: &mut Applicability, + path: &str, ) -> String { if let Some(last) = last_path_segment(ty_path).args && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg { @@ -69,10 +72,10 @@ fn make_sugg( }) { format!( - "std::iter::empty::<{}>()", + "{path}::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 ) } else { - "std::iter::empty()".to_owned() + format!("{path}()") } } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 712bc075650fa..c4437a3c4b339 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::numeric_literal; use clippy_utils::source::snippet_opt; -use clippy_utils::{get_parent_node, numeric_literal}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; -use rustc_hir::{Block, Body, Expr, ExprKind, FnRetTy, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; +use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -50,11 +50,11 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - let is_parent_const = if let Some(Node::Item(item)) = get_parent_node(cx.tcx, body.id().hir_id) { - matches!(item.kind, ItemKind::Const(..)) - } else { - false - }; + let hir = cx.tcx.hir(); + let is_parent_const = matches!( + hir.body_const_context(hir.body_owner_def_id(body.id())), + Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) + ); let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const); visitor.visit_body(body); } 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 db01ff2cd2205..bfd89bfd2c72f 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { /// (ZST fields having an arbitrary offset is completely inconsequential, and /// if there is only one field left after ignoring ZST fields then the offset /// of that field does not matter either.) -fn is_union_with_two_non_zst_fields(cx: &LateContext<'_>, item: &Item<'_>) -> bool { +fn is_union_with_two_non_zst_fields<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { if let ItemKind::Union(..) = &item.kind && let ty::Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 8ff54dfcfa0dc..194cf69ea7ed0 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -881,6 +881,7 @@ impl TyCoercionStability { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Tuple(_) | ty::Alias(ty::Projection, _) => Self::Deref, diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index d1fe9f5cbece7..6144ec7b3caca 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; +use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; @@ -450,13 +450,14 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq) && let Some(def_id) = trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) + && !has_non_exhaustive_attr(cx.tcx, *adt) && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) - && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(),&[]) + && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[]) // If all of our fields implement `Eq`, we can implement `Eq` too && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(), &[])) + .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[])) { span_lint_and_sugg( cx, 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 8b018220c1715..8dde4f227ed15 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 @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::HumanEmitter; -use rustc_errors::DiagCtxt; +use rustc_errors::{DiagCtxt, DiagnosticBuilder}; use rustc_lint::LateContext; use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::parser::ForceCollect; @@ -53,7 +53,7 @@ pub fn check( let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); + errs.into_iter().for_each(DiagnosticBuilder::cancel); return (false, test_attr_spans); }, }; 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 fa1f98ba01343..1933a00891b0b 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -6,8 +6,8 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ - GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty, - TyKind, + FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, + PathSegment, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; @@ -197,10 +197,13 @@ fn convert_to_from( // fn into([mut] self) -> T -> fn into([mut] v: T) -> T // ~~~~ ~~~~ (self_ident.span, format!("val: {from}")), + ]; + + if let FnRetTy::Return(_) = sig.decl.output { // fn into(self) -> T -> fn into(self) -> Self // ~ ~~~~ - (sig.decl.output.span(), String::from("Self")), - ]; + suggestions.push((sig.decl.output.span(), String::from("Self"))); + } let mut finder = SelfFinder { cx, diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 788fe82872784..87f6f5e7959e1 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -210,7 +210,7 @@ enum ImplicitHasherType<'tcx> { impl<'tcx> ImplicitHasherType<'tcx> { /// Checks that `ty` is a target type without a `BuildHasher`. - fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option { + fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Option { if let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind { let params: Vec<_> = path .segments diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index cc74844f29427..b8d7e8f3b07c7 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -3,6 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -69,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { && clippy_utils::SpanlessEq::new(cx).eq_expr(l, target) && BinOpKind::Add == op1.node && let ExprKind::Lit(lit) = value.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(Pu128(1), LitIntType::Unsuffixed) = lit.node && block.expr.is_none() { let mut app = Applicability::MachineApplicable; 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 81df1a889c789..127c73ed637b2 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; use rustc_ast::ast::LitKind; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -86,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { match cond_num_val.kind { ExprKind::Lit(cond_lit) => { // Check if the constant is zero - if let LitKind::Int(0, _) = cond_lit.node { + if let LitKind::Int(Pu128(0), _) = cond_lit.node { if cx.typeck_results().expr_ty(cond_left).is_signed() { } else { print_lint_and_sugg(cx, var_name, expr); diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index fb7b82ec304ef..1127f00abde04 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -53,7 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); - let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return }; + let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { + return; + }; let inherent_impls = cx .tcx .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true)); diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index efdd392594977..feb4d188f3978 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -574,6 +574,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { warn_on_all_wildcard_imports, check_private_items, pub_underscore_fields_behavior, + ref allowed_duplicate_crates, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -719,7 +720,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate)); store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef)); - store.register_late_pass(|_| Box::new(no_effect::NoEffect)); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv()))); store.register_late_pass(move |_| { @@ -947,6 +948,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, + allowed_duplicate_crates: allowed_duplicate_crates.clone(), }) }); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); 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 c7980060807c3..814ccaa36f5aa 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 @@ -118,7 +118,7 @@ fn is_ref_iterable<'tcx>( .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output && let param_env = cx.tcx.param_env(fn_id) - && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, fn_id, &[]) + && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, Some(fn_id), &[]) && let Some(into_iter_ty) = make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty]) && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty) diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index fda6c9749d434..58f713d81871f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -461,7 +461,7 @@ fn is_array_length_equal_to_range(cx: &LateContext<'_>, start: &Expr<'_>, end: & if let ExprKind::Lit(lit) = expr.kind && let ast::LitKind::Int(value, _) = lit.node { - Some(value) + Some(value.get()) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 4acf46f73c902..08b8a9e2ff072 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -209,8 +209,8 @@ fn is_end_eq_array_len<'tcx>( && let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env) { return match limits { - ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(), - ast::RangeLimits::HalfOpen => end_int >= arr_len.into(), + ast::RangeLimits::Closed => end_int.get() + 1 >= arr_len.into(), + ast::RangeLimits::HalfOpen => end_int.get() >= arr_len.into(), }; } 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 c245eaf1ab44d..920a887a6fd1b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( vec.span, "it looks like the same item is being pushed into this Vec", None, - &format!("try using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), + &format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), ); } diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 96c652283daa5..aa02e4e7a434f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -3,6 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; use rustc_ast::ast::LitKind; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -62,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { && let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr) && matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_)) && let ExprKind::Lit(lit) = &other_expr.kind - && let LitKind::Int(8, _) = lit.node + && let LitKind::Int(Pu128(8), _) = lit.node { let mut app = Applicability::MachineApplicable; let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0; diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index d585290f7773c..ec60de92c4ba2 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -45,7 +45,7 @@ fn expr_as_i128(expr: &Expr<'_>) -> Option { && let LitKind::Int(num, _) = lit.node { // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now. - num.try_into().ok() + num.get().try_into().ok() } else { None } diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 7b04fd28b896f..bcd0243600245 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -161,7 +161,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t .. }) = expr.kind { - constant_length(cx, pattern).map_or(false, |length| length == *n) + constant_length(cx, pattern).map_or(false, |length| *n == length) } else { len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg)) } 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 5ca161e93096d..d645e6c6c05c9 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 @@ -293,7 +293,7 @@ impl<'a> NormalizedPat<'a> { LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Char(val) => Self::LitInt(val.into()), - LitKind::Int(val, _) => Self::LitInt(val), + LitKind::Int(val, _) => Self::LitInt(val.get()), LitKind::Bool(val) => Self::LitBool(val), LitKind::Float(..) | LitKind::Err => Self::Wild, }, @@ -305,7 +305,7 @@ impl<'a> NormalizedPat<'a> { None => 0, Some(e) => match &e.kind { ExprKind::Lit(lit) => match lit.node { - LitKind::Int(val, _) => val, + LitKind::Int(val, _) => val.get(), LitKind::Char(val) => val.into(), LitKind::Byte(val) => val.into(), _ => return Self::Wild, @@ -317,7 +317,7 @@ impl<'a> NormalizedPat<'a> { None => (u128::MAX, RangeEnd::Included), Some(e) => match &e.kind { ExprKind::Lit(lit) => match lit.node { - LitKind::Int(val, _) => (val, bounds), + LitKind::Int(val, _) => (val.get(), bounds), LitKind::Char(val) => (val.into(), bounds), LitKind::Byte(val) => (val.into(), bounds), _ => return Self::Wild, diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index c22f76484d03d..fa4f4a47e38e2 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators, std_or_core}; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; @@ -128,6 +128,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' // check if replacement is mem::MaybeUninit::uninit().assume_init() && cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id) { + let Some(top_crate) = std_or_core(cx) else { return }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -136,7 +137,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' "replacing with `mem::MaybeUninit::uninit().assume_init()`", "consider using", format!( - "std::ptr::read({})", + "{top_crate}::ptr::read({})", snippet_with_applicability(cx, dest.span, "", &mut applicability) ), applicability, @@ -149,6 +150,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() { if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) { + let Some(top_crate) = std_or_core(cx) else { return }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -157,7 +159,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' "replacing with `mem::uninitialized()`", "consider using", format!( - "std::ptr::read({})", + "{top_crate}::ptr::read({})", snippet_with_applicability(cx, dest.span, "", &mut applicability) ), applicability, @@ -184,14 +186,17 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< return; } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { + let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_then( cx, MEM_REPLACE_WITH_DEFAULT, expr_span, - "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", + &format!( + "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`" + ), |diag| { if !expr_span.from_expansion() { - let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); + let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, "")); diag.span_suggestion( expr_span, diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs index e1f1e4893558e..55fcf37289404 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -20,7 +21,7 @@ pub(super) fn check<'tcx>( && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && let identity = cx.tcx.type_of(impl_id).instantiate_identity() && let hir::ExprKind::Lit(Spanned { - node: LitKind::Int(0, _), + node: LitKind::Int(Pu128(0), _), .. }) = arg.kind { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs index e1f950d5a4a5f..262a57ab591a6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs @@ -11,7 +11,7 @@ use rustc_span::sym; use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - if let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id)) + if let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id)) && let def_id = item.owner_id.to_def_id() && is_trait_method(cx, expr, sym::Iterator) && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 70abe4891d985..4c7c56e7174a0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_no_std_crate, is_res_lang_ctor, path_res}; +use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -58,10 +58,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re return; } + let Some(top_crate) = std_or_core(cx) else { return }; if let Some(i) = item { let sugg = format!( - "{}::iter::once({}{})", - if is_no_std_crate(cx) { "core" } else { "std" }, + "{top_crate}::iter::once({}{})", iter_type.ref_prefix(), snippet(cx, i.span, "...") ); @@ -81,11 +81,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re expr.span, &format!("`{method_name}` call on an empty collection"), "try", - if is_no_std_crate(cx) { - "core::iter::empty()".to_string() - } else { - "std::iter::empty()".to_string() - }, + format!("{top_crate}::iter::empty()"), Applicability::MaybeIncorrect, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs index 29e69b111de6e..f198849c5c0c6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -13,7 +13,7 @@ fn expr_as_u128(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { if let ExprKind::Lit(lit) = expr_or_init(cx, e).kind && let LitKind::Int(n, _) = lit.node { - Some(n) + Some(n.get()) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs index 02f28779cf6ee..aa1ec60d434a5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a ) .span_suggestion( expr_span, - "if this is intentional, try using `Path::new` instead", + "if this is intentional, consider using `Path::new`", format!("PathBuf::from({arg_str})"), Applicability::Unspecified, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 04bdbc1ea25fe..bf437db7e72ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -50,7 +50,7 @@ pub fn check( super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - &format!("try using `saturating_{arith}`"), + &format!("consider using `saturating_{arith}`"), format!( "{}.saturating_{arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index f9f636bbbf71b..27e17b43b01cc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -113,9 +113,15 @@ fn handle_path( if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id() && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD) { - // FIXME: It would be better to infer the type to check if it's copyable or not - // to suggest to use `.copied()` instead of `.cloned()` where applicable. - lint_path(cx, e.span, recv.span); + // The `copied` and `cloned` methods are only available on `&T` and `&mut T` in `Option` + // and `Result`. + if let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind() + && let args = args.as_slice() + && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type()) + && ty.is_ref() + { + lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); + } } } @@ -139,17 +145,19 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { ); } -fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span) { +fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { let mut applicability = Applicability::MachineApplicable; + let replacement = if is_copy { "copied" } else { "cloned" }; + span_lint_and_sugg( cx, MAP_CLONE, replace, "you are explicitly cloning with `.map()`", - "consider calling the dedicated `cloned` method", + &format!("consider calling the dedicated `{replacement}` method"), format!( - "{}.cloned()", + "{}.{replacement}()", snippet_with_applicability(cx, root, "..", &mut applicability), ), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 89ea3597dc0fd..03bcf108914a0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2827,6 +2827,44 @@ declare_clippy_lint! { "nonsensical combination of options for opening a file" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the suspicious use of `OpenOptions::create()` + /// without an explicit `OpenOptions::truncate()`. + /// + /// ### Why is this bad? + /// `create()` alone will either create a new file or open an + /// existing file. If the file already exists, it will be + /// overwritten when written to, but the file will not be + /// truncated by default. + /// If less data is written to the file + /// than it already contains, the remainder of the file will + /// remain unchanged, and the end of the file will contain old + /// data. + /// In most cases, one should either use `create_new` to ensure + /// the file is created from scratch, or ensure `truncate` is + /// called so that the truncation behaviour is explicit. `truncate(true)` + /// will ensure the file is entirely overwritten with new data, whereas + /// `truncate(false)` will explicitely keep the default behavior. + /// + /// ### Example + /// ```rust,no_run + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().create(true); + /// ``` + /// Use instead: + /// ```rust,no_run + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().create(true).truncate(true); + /// ``` + #[clippy::version = "1.75.0"] + pub SUSPICIOUS_OPEN_OPTIONS, + suspicious, + "suspicious combination of options for opening a file" +} + declare_clippy_lint! { /// ### What it does ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) @@ -4033,6 +4071,7 @@ impl_lint_pass!(Methods => [ MAP_ERR_IGNORE, MUT_MUTEX_LOCK, NONSENSICAL_OPEN_OPTIONS, + SUSPICIOUS_OPEN_OPTIONS, PATH_BUF_PUSH_OVERWRITE, RANGE_ZIP_WITH_LEN, REPEAT_ONCE, diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index 65c986dcaccea..77484ab91a9d7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -1,46 +1,74 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_type_diagnostic_item; +use rustc_data_structures::fx::FxHashMap; + +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{match_any_def_paths, paths}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_middle::ty::Ty; use rustc_span::source_map::Spanned; use rustc_span::{sym, Span}; -use super::NONSENSICAL_OPEN_OPTIONS; +use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; + +fn is_open_options(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || match_type(cx, ty, &paths::TOKIO_IO_OPEN_OPTIONS) +} pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions) + && is_open_options(cx, cx.tcx.type_of(impl_id).instantiate_identity()) { let mut options = Vec::new(); - get_open_options(cx, recv, &mut options); - check_open_options(cx, &options, e.span); + if get_open_options(cx, recv, &mut options) { + check_open_options(cx, &options, e.span); + } } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone, Debug)] enum Argument { - True, - False, + Set(bool), Unknown, } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Hash, Clone)] enum OpenOption { - Write, + Append, + Create, + CreateNew, Read, Truncate, - Create, - Append, + Write, +} +impl std::fmt::Display for OpenOption { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OpenOption::Append => write!(f, "append"), + OpenOption::Create => write!(f, "create"), + OpenOption::CreateNew => write!(f, "create_new"), + OpenOption::Read => write!(f, "read"), + OpenOption::Truncate => write!(f, "truncate"), + OpenOption::Write => write!(f, "write"), + } + } } -fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind { +/// Collects information about a method call chain on `OpenOptions`. +/// Returns false if an unexpected expression kind was found "on the way", +/// and linting should then be avoided. +fn get_open_options( + cx: &LateContext<'_>, + argument: &Expr<'_>, + options: &mut Vec<(OpenOption, Argument, Span)>, +) -> bool { + if let ExprKind::MethodCall(path, receiver, arguments, span) = argument.kind { let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() { + if !arguments.is_empty() && is_open_options(cx, obj_ty) { let argument_option = match arguments[0].kind { ExprKind::Lit(span) => { if let Spanned { @@ -48,11 +76,12 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec .. } = span { - if *lit { Argument::True } else { Argument::False } + Argument::Set(*lit) } else { // The function is called with a literal which is not a boolean literal. // This is theoretically possible, but not very likely. - return; + // We'll ignore it for now + return get_open_options(cx, receiver, options); } }, _ => Argument::Unknown, @@ -60,106 +89,77 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec match path.ident.as_str() { "create" => { - options.push((OpenOption::Create, argument_option)); + options.push((OpenOption::Create, argument_option, span)); + }, + "create_new" => { + options.push((OpenOption::CreateNew, argument_option, span)); }, "append" => { - options.push((OpenOption::Append, argument_option)); + options.push((OpenOption::Append, argument_option, span)); }, "truncate" => { - options.push((OpenOption::Truncate, argument_option)); + options.push((OpenOption::Truncate, argument_option, span)); }, "read" => { - options.push((OpenOption::Read, argument_option)); + options.push((OpenOption::Read, argument_option, span)); }, "write" => { - options.push((OpenOption::Write, argument_option)); + options.push((OpenOption::Write, argument_option, span)); + }, + _ => { + // Avoid linting altogether if this method is from a trait. + // This might be a user defined extension trait with a method like `truncate_write` + // which would be a false positive + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(argument.hir_id) + && cx.tcx.trait_of_item(method_def_id).is_some() + { + return false; + } }, - _ => (), } - get_open_options(cx, receiver, options); + get_open_options(cx, receiver, options) + } else { + false } + } else if let ExprKind::Call(callee, _) = argument.kind + && let ExprKind::Path(path) = callee.kind + && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() + { + match_any_def_paths( + cx, + did, + &[ + &paths::TOKIO_IO_OPEN_OPTIONS_NEW, + &paths::OPEN_OPTIONS_NEW, + &paths::FILE_OPTIONS, + &paths::TOKIO_FILE_OPTIONS, + ], + ) + .is_some() + } else { + false } } -fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], span: Span) { - let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false); - let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = - (false, false, false, false, false); - // This code is almost duplicated (oh, the irony), but I haven't found a way to - // unify it. - - for option in options { - match *option { - (OpenOption::Create, arg) => { - if create { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `create` is called more than once", - ); - } else { - create = true; - } - create_arg = create_arg || (arg == Argument::True); - }, - (OpenOption::Append, arg) => { - if append { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `append` is called more than once", - ); - } else { - append = true; - } - append_arg = append_arg || (arg == Argument::True); - }, - (OpenOption::Truncate, arg) => { - if truncate { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `truncate` is called more than once", - ); - } else { - truncate = true; - } - truncate_arg = truncate_arg || (arg == Argument::True); - }, - (OpenOption::Read, arg) => { - if read { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `read` is called more than once", - ); - } else { - read = true; - } - read_arg = read_arg || (arg == Argument::True); - }, - (OpenOption::Write, arg) => { - if write { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `write` is called more than once", - ); - } else { - write = true; - } - write_arg = write_arg || (arg == Argument::True); - }, +fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, Span)], span: Span) { + // The args passed to these methods, if they have been called + let mut options = FxHashMap::default(); + for (option, arg, sp) in settings { + if let Some((_, prev_span)) = options.insert(option.clone(), (arg.clone(), *sp)) { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + prev_span, + &format!("the method `{}` is called more than once", &option), + ); } } - if read && truncate && read_arg && truncate_arg && !(write && write_arg) { + if let Some((Argument::Set(true), _)) = options.get(&OpenOption::Read) + && let Some((Argument::Set(true), _)) = options.get(&OpenOption::Truncate) + && let None | Some((Argument::Set(false), _)) = options.get(&OpenOption::Write) + { span_lint( cx, NONSENSICAL_OPEN_OPTIONS, @@ -167,7 +167,10 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "file opened with `truncate` and `read`", ); } - if append && truncate && append_arg && truncate_arg { + + if let Some((Argument::Set(true), _)) = options.get(&OpenOption::Append) + && let Some((Argument::Set(true), _)) = options.get(&OpenOption::Truncate) + { span_lint( cx, NONSENSICAL_OPEN_OPTIONS, @@ -175,4 +178,29 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "file opened with `append` and `truncate`", ); } + + if let Some((Argument::Set(true), create_span)) = options.get(&OpenOption::Create) + && let None = options.get(&OpenOption::Truncate) + && let None | Some((Argument::Set(false), _)) = options.get(&OpenOption::Append) + { + span_lint_and_then( + cx, + SUSPICIOUS_OPEN_OPTIONS, + *create_span, + "file opened with `create`, but `truncate` behavior not defined", + |diag| { + diag.span_suggestion( + create_span.shrink_to_hi(), + "add", + ".truncate(true)".to_string(), + rustc_errors::Applicability::MaybeIncorrect, + ) + .help("if you intend to overwrite an existing file entirely, call `.truncate(true)`") + .help( + "if you instead know that you may want to keep some parts of the old file, call `.truncate(false)`", + ) + .help("alternatively, use `.append(true)` to append to the file instead of overwriting it"); + }, + ); + } } 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 756dbe62d84d6..88e2af15658ff 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 @@ -97,7 +97,7 @@ pub(super) fn check( }; let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); - let suggestion = format!("try using {method_hint} instead"); + let suggestion = format!("consider using {method_hint}"); let msg = format!("called `{current_method}` on an `Option` value"); span_lint_and_sugg( 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 index 91e39d5a1cd27..4e424d4c066a6 100644 --- 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 @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( OPTION_MAP_OR_ERR_OK, expr.span, msg, - "try using `ok_or` instead", + "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_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs index ff4d8cc9e3e1a..193deafccf650 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs @@ -72,7 +72,7 @@ pub(super) fn check<'tcx>( OPTION_MAP_OR_NONE, expr.span, msg, - "try using `map` instead", + "consider using `map`", format!("{self_snippet}.map({arg_snippet} {func_snippet})"), Applicability::MachineApplicable, ); @@ -85,7 +85,7 @@ pub(super) fn check<'tcx>( OPTION_MAP_OR_NONE, expr.span, msg, - "try using `and_then` instead", + "consider using `and_then`", format!("{self_snippet}.and_then({func_snippet})"), Applicability::MachineApplicable, ); @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( RESULT_MAP_OR_INTO_OPTION, expr.span, msg, - "try using `ok` instead", + "consider using `ok`", format!("{self_snippet}.ok()"), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs index bc16a11281620..3b0dc506305b5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( RESULT_MAP_OR_INTO_OPTION, expr.span, msg, - "try using `ok` instead", + "consider using `ok`", format!("{self_snippet}.ok()"), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index 6339011c92f58..ef1baa6c98820 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -63,7 +63,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "use `any()` instead", + "consider using", format!( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, expr.span, &msg, - "use `!_.any()` instead", + "consider using", format!( "!{iter}.any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -118,7 +118,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "use `contains()` instead", + "consider using", format!("contains({find_arg})"), applicability, ); @@ -132,7 +132,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, expr.span, &msg, - "use `!_.contains()` instead", + "consider using", format!("!{string}.contains({find_arg})"), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs index 63d41677feed2..e45c7962f13f4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs @@ -1,4 +1,5 @@ use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -41,7 +42,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) // check if argument of `SeekFrom::Current` is `0` if args.len() == 1 && let ExprKind::Lit(lit) = args[0].kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node { return true; } diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 9f38460357ba6..cc4cb47e35c63 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; use clippy_utils::{is_expr_used_or_unified, match_def_path, paths}; use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -31,7 +32,7 @@ pub(super) fn check<'tcx>( && match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && args1.len() == 1 && let ExprKind::Lit(lit) = args1[0].kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node { let method_call_span = expr.span.with_lo(name_span.lo()); span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs index 3983f0c0cabd4..363b1f2b81229 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs @@ -57,7 +57,7 @@ pub(super) fn check( SINGLE_CHAR_PATTERN, arg.span, "single-character string constant used as pattern", - "try using a `char` instead", + "consider using a `char`", hint, applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index ebbdde48b450f..f3577ef6082bf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs}; use rustc_ast::ast; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; @@ -150,7 +151,7 @@ pub(super) fn check( }, ); }, - ast::LitKind::Int(0, _) => check_fold_with_op( + ast::LitKind::Int(Pu128(0), _) => check_fold_with_op( cx, expr, acc, @@ -162,7 +163,7 @@ pub(super) fn check( method_name: "sum", }, ), - ast::LitKind::Int(1, _) => { + ast::LitKind::Int(Pu128(1), _) => { check_fold_with_op( cx, expr, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs index e2b389e96dae0..c3ad4db387592 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( UNNECESSARY_JOIN, span.with_hi(expr.span.hi()), r#"called `.collect::>().join("")` on an iterator"#, - "try using", + "consider using", "collect::()".to_owned(), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 696e5e74d60a5..6911da69b945e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -203,7 +203,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_SORT_BY, expr.span, - "use Vec::sort_by_key here instead", + "consider using `sort_by_key`", "try", format!( "{}.sort{}_by_key(|{}| {})", @@ -226,7 +226,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_SORT_BY, expr.span, - "use Vec::sort here instead", + "consider using `sort`", "try", format!( "{}.sort{}()", 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 66727e5a29dc6..514015af0455c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; -use clippy_utils::{get_parent_expr, is_diag_trait_item, match_def_path, paths, peel_blocks}; +use clippy_utils::{ + get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs, +}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -108,9 +110,12 @@ fn check_qpath(cx: &LateContext<'_>, qpath: hir::QPath<'_>, hir_id: hir::HirId) fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { match arg.kind { - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) // If it's a closure, we need to check what is called. - let closure_body = cx.tcx.hir().body(body); + if let closure_body = cx.tcx.hir().body(body) + && let [param] = closure_body.params + && let hir::PatKind::Binding(_, local_id, ..) = strip_pat_refs(param.pat).kind => + { let closure_expr = peel_blocks(closure_body.value); match closure_expr.kind { hir::ExprKind::MethodCall(method, obj, [], _) => { @@ -122,14 +127,17 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) + && path_to_local_id(obj, local_id) { true } else { false } }, - hir::ExprKind::Call(call, [_]) => { - if let hir::ExprKind::Path(qpath) = call.kind { + hir::ExprKind::Call(call, [recv]) => { + if let hir::ExprKind::Path(qpath) = call.kind + && path_to_local_id(recv, local_id) + { check_qpath(cx, qpath, call.hir_id) } else { false diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs index 9e87fb45aa65a..3e271a606115a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -20,7 +21,7 @@ pub(super) fn check<'tcx>( && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec) && let ExprKind::Lit(Spanned { - node: LitKind::Int(0, _), + node: LitKind::Int(Pu128(0), _), .. }) = count_arg.kind && let ExprKind::Lit(Spanned { 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 34b8e0dbe6a7e..41168230752a8 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -93,9 +93,7 @@ impl Visitor<'_> for IdentVisitor<'_, '_> { // reimplement it even if we wanted to cx.tcx.opt_hir_node(hir_id) } else { - let Some(owner) = cx.tcx.hir_owner_nodes(hir_id.owner).as_owner() else { - return; - }; + let owner = cx.tcx.hir_owner_nodes(hir_id.owner); owner.nodes.get(hir_id.local_id).copied().flatten().map(|p| p.node) }; let Some(node) = node else { diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index bbc4d0a0f9a54..0e4d39c999020 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -7,6 +7,7 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr; use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; +use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; @@ -102,8 +103,8 @@ fn len_comparison<'hir>( ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> { macro_rules! int_lit_pat { ($id:ident) => { - ExprKind::Lit(Spanned { - node: LitKind::Int($id, _), + ExprKind::Lit(&Spanned { + node: LitKind::Int(Pu128($id), _), .. }) }; @@ -112,13 +113,13 @@ fn len_comparison<'hir>( // normalize comparison, `v.len() > 4` becomes `4 < v.len()` // this simplifies the logic a bit let (op, left, right) = normalize_comparison(bin_op.node, left, right)?; - match (op, &left.kind, &right.kind) { - (Rel::Lt, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanLength, *left as usize, right)), - (Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, *right as usize, left)), - (Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, *left as usize, right)), - (Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, *right as usize, left)), - (Rel::Eq, int_lit_pat!(left), _) => Some((LengthComparison::LengthEqualInt, *left as usize, right)), - (Rel::Eq, _, int_lit_pat!(right)) => Some((LengthComparison::LengthEqualInt, *right as usize, left)), + match (op, left.kind, right.kind) { + (Rel::Lt, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanLength, left as usize, right)), + (Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, right as usize, left)), + (Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, left as usize, right)), + (Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, right as usize, left)), + (Rel::Eq, int_lit_pat!(left), _) => Some((LengthComparison::LengthEqualInt, left as usize, right)), + (Rel::Eq, _, int_lit_pat!(right)) => Some((LengthComparison::LengthEqualInt, right as usize, left)), _ => None, } } @@ -206,14 +207,14 @@ impl<'hir> IndexEntry<'hir> { /// for `..=5` this returns `Some(5)` fn upper_index_expr(expr: &Expr<'_>) -> Option { if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Int(index, _) = lit.node + && let LitKind::Int(Pu128(index), _) = lit.node { Some(index as usize) } else if let Some(higher::Range { end: Some(end), limits, .. }) = higher::Range::hir(expr) && let ExprKind::Lit(lit) = &end.kind - && let LitKind::Int(index @ 1.., _) = lit.node + && let LitKind::Int(Pu128(index @ 1..), _) = lit.node { match limits { RangeLimits::HalfOpen => Some(index as usize - 1), 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 64ef709e2fa2d..d2eef6ae4338e 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,16 +5,15 @@ use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{ BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, - PatKind, QPath, + PatKind, }; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::associated_body; -use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; @@ -234,12 +233,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - cx.tcx.hir().visit_all_item_likes_in_crate(&mut FnNeedsMutVisitor { - cx, - used_fn_def_ids: &mut self.used_fn_def_ids, - }); + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + // #11182; do not lint if mutability is required elsewhere + if let ExprKind::Path(..) = expr.kind + && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) + && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(expr).kind() + && let Some(def_id) = def_id.as_local() + { + if let Node::Expr(e) = parent + && let ExprKind::Call(call, _) = e.kind + && call.hir_id == expr.hir_id + { + return; + } + // We don't need to check each argument individually as you cannot coerce a function + // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's + // passed as a `fn`-like argument (or is unified) and should ignore every "unused" + // argument entirely + self.used_fn_def_ids.insert(def_id); + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { for (fn_def_id, unused) in self .fn_def_ids_to_maybe_unused_mut .iter() @@ -501,48 +517,3 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } } - -/// A final pass to check for paths referencing this function that require the argument to be -/// `&mut`, basically if the function is ever used as a `fn`-like argument. -struct FnNeedsMutVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - used_fn_def_ids: &'a mut FxHashSet, -} - -impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> { - type NestedFilter = OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, _: Span) { - walk_qpath(self, qpath, hir_id); - - let Self { cx, used_fn_def_ids } = self; - - // #11182; do not lint if mutability is required elsewhere - if let Node::Expr(expr) = cx.tcx.hir_node(hir_id) - && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) - && let ty::FnDef(def_id, _) = cx - .tcx - .typeck(cx.tcx.hir().enclosing_body_owner(hir_id)) - .expr_ty(expr) - .kind() - && let Some(def_id) = def_id.as_local() - { - if let Node::Expr(e) = parent - && let ExprKind::Call(call, _) = e.kind - && call.hir_id == expr.hir_id - { - return; - } - - // We don't need to check each argument individually as you cannot coerce a function - // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's - // passed as a `fn`-like argument (or is unified) and should ignore every "unused" - // argument entirely - used_fn_def_ids.insert(def_id); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 6bbe427ea2988..0d234f7f9b52c 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,16 +1,18 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; -use clippy_utils::{get_parent_node, is_lint_allowed, peel_blocks}; +use clippy_utils::{any_parent_is_automatically_derived, get_parent_node, is_lint_allowed, path_to_local, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, ItemKind, Node, PatKind, Stmt, StmtKind, UnsafeSource, + is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, Node, PatKind, Stmt, + StmtKind, UnsafeSource, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; +use rustc_span::Span; use std::ops::Deref; declare_clippy_lint! { @@ -74,94 +76,125 @@ declare_clippy_lint! { "outer expressions with no effect" } -declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]); +#[derive(Default)] +pub struct NoEffect { + underscore_bindings: HirIdMap, + local_bindings: Vec>, +} + +impl_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]); impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if check_no_effect(cx, stmt) { + if self.check_no_effect(cx, stmt) { return; } check_unnecessary_operation(cx, stmt); } -} -fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { - if let StmtKind::Semi(expr) = stmt.kind { - // move `expr.span.from_expansion()` ahead - if expr.span.from_expansion() { - return false; + fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) { + self.local_bindings.push(Vec::default()); + } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) { + for hir_id in self.local_bindings.pop().unwrap() { + if let Some(span) = self.underscore_bindings.remove(&hir_id) { + span_lint_hir( + cx, + NO_EFFECT_UNDERSCORE_BINDING, + hir_id, + span, + "binding to `_` prefixed variable with no side-effect", + ); + } } - let expr = peel_blocks(expr); + } - if is_operator_overridden(cx, expr) { - // Return `true`, to prevent `check_unnecessary_operation` from - // linting on this statement as well. - return true; + fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + if let Some(def_id) = path_to_local(expr) { + self.underscore_bindings.remove(&def_id); } - if has_no_effect(cx, expr) { - span_lint_hir_and_then( - cx, - NO_EFFECT, - expr.hir_id, - stmt.span, - "statement with no effect", - |diag| { - for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { - if let Node::Item(item) = parent.1 - && let ItemKind::Fn(..) = item.kind - && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) - && let [.., final_stmt] = block.stmts - && final_stmt.hir_id == stmt.hir_id - { - let expr_ty = cx.typeck_results().expr_ty(expr); - let mut ret_ty = cx - .tcx - .fn_sig(item.owner_id) - .instantiate_identity() - .output() - .skip_binder(); + } +} + +impl NoEffect { + fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { + if let StmtKind::Semi(expr) = stmt.kind { + // move `expr.span.from_expansion()` ahead + if expr.span.from_expansion() { + return false; + } + let expr = peel_blocks(expr); - // Remove `impl Future` to get `T` - if cx.tcx.ty_is_opaque_future(ret_ty) - && let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + if is_operator_overridden(cx, expr) { + // Return `true`, to prevent `check_unnecessary_operation` from + // linting on this statement as well. + return true; + } + if has_no_effect(cx, expr) { + span_lint_hir_and_then( + cx, + NO_EFFECT, + expr.hir_id, + stmt.span, + "statement with no effect", + |diag| { + for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { + if let Node::Item(item) = parent.1 + && let ItemKind::Fn(..) = item.kind + && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) + && let [.., final_stmt] = block.stmts + && final_stmt.hir_id == stmt.hir_id { - ret_ty = true_ret_ty; - } + let expr_ty = cx.typeck_results().expr_ty(expr); + let mut ret_ty = cx + .tcx + .fn_sig(item.owner_id) + .instantiate_identity() + .output() + .skip_binder(); + + // Remove `impl Future` to get `T` + if cx.tcx.ty_is_opaque_future(ret_ty) + && let Some(true_ret_ty) = + cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + { + ret_ty = true_ret_ty; + } - if !ret_ty.is_unit() && ret_ty == expr_ty { - diag.span_suggestion( - stmt.span.shrink_to_lo(), - "did you mean to return it?", - "return ", - Applicability::MaybeIncorrect, - ); + if !ret_ty.is_unit() && ret_ty == expr_ty { + diag.span_suggestion( + stmt.span.shrink_to_lo(), + "did you mean to return it?", + "return ", + Applicability::MaybeIncorrect, + ); + } } } - } - }, - ); - return true; - } - } else if let StmtKind::Local(local) = stmt.kind { - if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) - && let Some(init) = local.init - && local.els.is_none() - && !local.pat.span.from_expansion() - && has_no_effect(cx, init) - && let PatKind::Binding(_, _, ident, _) = local.pat.kind - && ident.name.to_ident_string().starts_with('_') - { - span_lint_hir( - cx, - NO_EFFECT_UNDERSCORE_BINDING, - init.hir_id, - stmt.span, - "binding to `_` prefixed variable with no side-effect", - ); - return true; + }, + ); + return true; + } + } else if let StmtKind::Local(local) = stmt.kind { + if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) + && let Some(init) = local.init + && local.els.is_none() + && !local.pat.span.from_expansion() + && has_no_effect(cx, init) + && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind + && ident.name.to_ident_string().starts_with('_') + && !any_parent_is_automatically_derived(cx.tcx, local.hir_id) + { + if let Some(l) = self.local_bindings.last_mut() { + l.push(hir_id); + self.underscore_bindings.insert(hir_id, ident.span); + } + return true; + } } + false } - false } fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index c081dec9b6b75..96ea063aa74d6 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -1,11 +1,11 @@ use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::consts::{constant, constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::type_diagnostic_name; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -88,37 +88,44 @@ impl ArithmeticSideEffects { } /// Verifies built-in types that have specific allowed operations - fn has_specific_allowed_type_and_operation( - cx: &LateContext<'_>, - lhs_ty: Ty<'_>, + fn has_specific_allowed_type_and_operation<'tcx>( + cx: &LateContext<'tcx>, + lhs_ty: Ty<'tcx>, op: &Spanned, - rhs_ty: Ty<'_>, + rhs_ty: Ty<'tcx>, ) -> bool { let is_div_or_rem = matches!(op.node, hir::BinOpKind::Div | hir::BinOpKind::Rem); - let is_non_zero_u = |symbol: Option| { - matches!( - symbol, - Some( - sym::NonZeroU128 - | sym::NonZeroU16 - | sym::NonZeroU32 - | sym::NonZeroU64 - | sym::NonZeroU8 - | sym::NonZeroUsize - ) - ) + let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| { + let tcx = cx.tcx; + + let ty::Adt(adt, substs) = ty.kind() else { return false }; + + if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + return false; + }; + + let int_type = substs.type_at(0); + let unsigned_int_types = [ + tcx.types.u8, + tcx.types.u16, + tcx.types.u32, + tcx.types.u64, + tcx.types.u128, + tcx.types.usize, + ]; + + unsigned_int_types.contains(&int_type) }; let is_sat_or_wrap = |ty: Ty<'_>| { - let is_sat = type_diagnostic_name(cx, ty) == Some(sym::Saturating); - let is_wrap = type_diagnostic_name(cx, ty) == Some(sym::Wrapping); - is_sat || is_wrap + is_type_diagnostic_item(cx, ty, sym::Saturating) || is_type_diagnostic_item(cx, ty, sym::Wrapping) }; - // If the RHS is NonZeroU*, then division or module by zero will never occur - if is_non_zero_u(type_diagnostic_name(cx, rhs_ty)) && is_div_or_rem { + // If the RHS is `NonZero`, then division or module by zero will never occur. + if is_non_zero_u(cx, rhs_ty) && is_div_or_rem { return true; } - // `Saturation` and `Wrapping` can overflow if the RHS is zero in a division or module + + // `Saturation` and `Wrapping` can overflow if the RHS is zero in a division or module. if is_sat_or_wrap(lhs_ty) { return !is_div_or_rem; } @@ -151,7 +158,7 @@ impl ArithmeticSideEffects { if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { - return Some(n); + return Some(n.get()); } if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs index 9db2e24630aac..a69989e400be4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs +++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; +use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use super::PTR_EQ; -static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, @@ -26,13 +25,14 @@ pub(super) fn check<'tcx>( && let Some(left_snip) = snippet_opt(cx, left_var.span) && let Some(right_snip) = snippet_opt(cx, right_var.span) { + let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_sugg( cx, PTR_EQ, expr.span, - LINT_MSG, + &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", - format!("std::ptr::eq({left_snip}, {right_snip})"), + format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs index fbf65e92b322a..a6aba33e431a4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; use rustc_ast::ast::LitKind; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -19,9 +20,9 @@ pub(super) fn check<'tcx>( && let ExprKind::Binary(op1, left1, right1) = &left.kind && BinOpKind::BitAnd == op1.node && let ExprKind::Lit(lit) = &right1.kind - && let LitKind::Int(n, _) = lit.node + && let LitKind::Int(Pu128(n), _) = lit.node && let ExprKind::Lit(lit1) = &right.kind - && let LitKind::Int(0, _) = lit1.node + && let LitKind::Int(Pu128(0), _) = lit1.node && n.leading_zeros() == n.count_zeros() && n > u128::from(threshold) { 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 00465ce43813e..88b5a6cfe2aa7 100644 --- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs +++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields { }; let is_visible = |field: &FieldDef<'_>| match self.behavior { - PubUnderscoreFieldsBehaviour::PublicallyExported => cx.effective_visibilities.is_reachable(field.def_id), + PubUnderscoreFieldsBehaviour::PubliclyExported => cx.effective_visibilities.is_reachable(field.def_id), PubUnderscoreFieldsBehaviour::AllPubFields => { // If there is a visibility span then the field is marked pub in some way. !field.vis_span.is_empty() 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 62f3c09aa7e26..650324d4249eb 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 @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::get_enclosing_block; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; -use core::ops::ControlFlow; -use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; + +use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -49,57 +51,40 @@ declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]); impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &hir::Block<'tcx>) { - for (idx, stmt) in block.stmts.iter().enumerate() { - if !stmt.span.from_expansion() - // matches `let v = Vec::new();` - && let StmtKind::Local(local) = stmt.kind - && let Local { pat, init: Some(init), .. } = local - && let PatKind::Binding(_, _, ident, _) = pat.kind + for stmt in block.stmts { + if stmt.span.from_expansion() { + return; + } + + if let StmtKind::Local(local) = stmt.kind + && let Local { + pat, init: Some(init), .. + } = local + && let PatKind::Binding(_, id, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) { - let visitor = |expr: &Expr<'_>| { - if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { - ident: read_or_read_exact, - .. - } = *path - && matches!(read_or_read_exact.as_str(), "read" | "read_exact") - && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind - && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind - && let [inner_seg] = inner_path.segments - && ident.name == inner_seg.ident.name - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + let mut visitor = ReadVecVisitor { + local_id: id, + read_zero_expr: None, + has_resize: false, }; - let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { - // case { .. stmt; stmt; .. } - (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) - } else if let Some(e) = block.expr { - // case { .. stmt; expr } - (for_each_expr(e, visitor).is_some(), e.span) - } else { + let Some(enclosing_block) = get_enclosing_block(cx, id) else { return; }; + visitor.visit_block(enclosing_block); - if read_found && !next_stmt_span.from_expansion() { + if let Some(expr) = visitor.read_zero_expr { let applicability = Applicability::MaybeIncorrect; match vec_init_kind { VecInitKind::WithConstCapacity(len) => { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", - format!( - "{}.resize({len}, 0); {}", - ident.as_str(), - snippet(cx, next_stmt_span, "..") - ), + format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), applicability, ); }, @@ -108,25 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", format!( "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), - snippet(cx, next_stmt_span, "..") + snippet(cx, expr.span, "..") ), applicability, ); }, _ => { - span_lint( - cx, - READ_ZERO_BYTE_VEC, - next_stmt_span, - "reading zero byte data to `Vec`", - ); + span_lint(cx, READ_ZERO_BYTE_VEC, expr.span, "reading zero byte data to `Vec`"); }, } } @@ -134,3 +114,47 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } } } + +struct ReadVecVisitor<'tcx> { + local_id: HirId, + read_zero_expr: Option<&'tcx Expr<'tcx>>, + has_resize: bool, +} + +impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(path, receiver, args, _) = e.kind { + let PathSegment { ident, .. } = *path; + + match ident.as_str() { + "read" | "read_exact" => { + let [arg] = args else { return }; + if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind + && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind + && let [inner_seg] = inner_path.segments + && let Res::Local(res_id) = inner_seg.res + && self.local_id == res_id + { + self.read_zero_expr = Some(e); + return; + } + }, + "resize" => { + // If the Vec is resized, then it's a valid read + if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind + && let Res::Local(res_id) = inner_path.res + && self.local_id == res_id + { + self.has_resize = true; + return; + } + }, + _ => {}, + } + } + + if !self.has_resize && self.read_zero_expr.is_none() { + walk_expr(self, e); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 2293b53b42b91..e01750465873d 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { && let ExprKind::Ret(Some(ret)) = expr.kind && let ExprKind::Match(.., MatchSource::TryDesugar(_)) = ret.kind // Ensure this is not the final stmt, otherwise removing it would cause a compile error - && let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id)) + && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id)) && let ItemKind::Fn(_, _, body) = item.kind && let block = cx.tcx.hir().body(body).value && let ExprKind::Block(block, _) = block.kind diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 2cd3e57f885a2..6540626f7d5a3 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -5,6 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::{ExpnKind, MacroKind, Span}; declare_clippy_lint! { /// ### What it does @@ -39,6 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if !block.span.from_expansion() && let Some(expr) = block.expr + && !from_attr_macro(expr.span) && let t_expr = cx.typeck_results().expr_ty(expr) && t_expr.is_unit() && let mut app = Applicability::MachineApplicable @@ -63,3 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { } } } + +fn from_attr_macro(span: Span) -> bool { + matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Attr, _)) +} diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index 8e181c3ccc743..0387742077447 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::{is_from_proc_macro, is_in_test_function}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; @@ -88,16 +88,18 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn { }; cx.tcx.hir().visit_all_item_likes_in_crate(&mut v); - for usage in self.def_id_to_usage.values() { + for (&def_id, usage) in &self.def_id_to_usage { let single_call_fn_span = usage.0; if let [caller_span] = *usage.1 { - span_lint_and_help( + span_lint_hir_and_then( cx, SINGLE_CALL_FN, + cx.tcx.local_def_id_to_hir_id(def_id), single_call_fn_span, "this function is only used once", - Some(caller_span), - "used here", + |diag| { + diag.span_help(caller_span, "used here"); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index e4054393d0ad7..768623b5d0347 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -390,6 +390,14 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &' } } +fn get_ty_res(ty: Ty<'_>) -> Option { + match ty.kind { + TyKind::Path(QPath::Resolved(_, path)) => Some(path.res), + TyKind::Path(QPath::TypeRelative(ty, _)) => get_ty_res(*ty), + _ => None, + } +} + // FIXME: ComparableTraitRef does not support nested bounds needed for associated_type_bounds fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ComparableTraitRef( @@ -401,10 +409,8 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { .filter_map(|segment| { // get trait bound type arguments Some(segment.args?.args.iter().filter_map(|arg| { - if let GenericArg::Type(ty) = arg - && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - { - return Some(path.res); + if let GenericArg::Type(ty) = arg { + return get_ty_res(**ty); } None })) diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs index 7d31c375f8cf2..2a6c248125459 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_CHAR; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg; +use clippy_utils::{std_or_core, sugg}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; @@ -25,6 +25,7 @@ pub(super) fn check<'tcx>( e.span, &format!("transmute from a `{from_ty}` to a `char`"), |diag| { + let Some(top_crate) = std_or_core(cx) else { return }; let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(_) = from_ty.kind() { arg.as_ty(ast::UintTy::U32.name_str()) @@ -34,7 +35,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("std::char::from_u32({arg}).unwrap()"), + format!("{top_crate}::char::from_u32({arg}).unwrap()"), Applicability::Unspecified, ); }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 5df645491ff81..97068efd43cd8 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -16,40 +16,55 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, ) -> bool { - let (ty::Int(_) | ty::Uint(_), Some(to_ty_adt)) = (&from_ty.kind(), to_ty.ty_adt_def()) else { + let tcx = cx.tcx; + + let (ty::Int(_) | ty::Uint(_), ty::Adt(adt, substs)) = (&from_ty.kind(), to_ty.kind()) else { return false; }; - let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_adt.did()) else { + + if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { return false; }; - if !matches!( - to_type_sym, - sym::NonZeroU8 - | sym::NonZeroU16 - | sym::NonZeroU32 - | sym::NonZeroU64 - | sym::NonZeroU128 - | sym::NonZeroI8 - | sym::NonZeroI16 - | sym::NonZeroI32 - | sym::NonZeroI64 - | sym::NonZeroI128 - ) { + // FIXME: This can be simplified once `NonZero` is stable. + let coercable_types = [ + ("NonZeroU8", tcx.types.u8), + ("NonZeroU16", tcx.types.u16), + ("NonZeroU32", tcx.types.u32), + ("NonZeroU64", tcx.types.u64), + ("NonZeroU128", tcx.types.u128), + ("NonZeroUsize", tcx.types.usize), + ("NonZeroI8", tcx.types.i8), + ("NonZeroI16", tcx.types.i16), + ("NonZeroI32", tcx.types.i32), + ("NonZeroI64", tcx.types.i64), + ("NonZeroI128", tcx.types.i128), + ("NonZeroIsize", tcx.types.isize), + ]; + + let int_type = substs.type_at(0); + + let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { + if *t == int_type && *t == from_ty { + Some(nonzero_alias) + } else { + None + } + }) else { return false; - } + }; span_lint_and_then( cx, TRANSMUTE_INT_TO_NON_ZERO, e.span, - &format!("transmute from a `{from_ty}` to a `{to_type_sym}`"), + &format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( e.span, "consider using", - format!("{to_type_sym}::{}({arg})", sym::new_unchecked), + format!("{nonzero_alias}::{}({arg})", sym::new_unchecked), Applicability::Unspecified, ); }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 98e9ea2d7751f..6c885ebdea11d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,7 +1,7 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; +use clippy_utils::{std_or_core, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; @@ -25,6 +25,8 @@ pub(super) fn check<'tcx>( && let ty::Uint(ty::UintTy::U8) = slice_ty.kind() && from_mutbl == to_mutbl { + let Some(top_crate) = std_or_core(cx) else { return true }; + let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" }; let snippet = snippet(cx, arg.span, ".."); @@ -36,9 +38,9 @@ pub(super) fn check<'tcx>( &format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { - format!("std::str::from_utf8_unchecked{postfix}({snippet})") + format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") } else { - format!("std::str::from_utf8{postfix}({snippet}).unwrap()") + format!("{top_crate}::str::from_utf8{postfix}({snippet}).unwrap()") }, Applicability::MaybeIncorrect, ); diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 1cf6cf8548a64..7a7bb9f9c94c3 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -37,12 +37,6 @@ pub(super) fn check_cast<'tcx>( let inherited = Inherited::new(cx.tcx, local_def_id); let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id); - // If we already have errors, we can't be sure we can pointer cast. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" - ); - if let Ok(check) = cast::CastCheck::new( &fn_ctxt, e, @@ -53,17 +47,7 @@ pub(super) fn check_cast<'tcx>( DUMMY_SP, hir::Constness::NotConst, ) { - let res = check.do_check(&fn_ctxt); - - // do_check's documentation says that it might return Ok and create - // errors in the fcx instead of returning Err in some cases. Those cases - // should be filtered out before getting here. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "`fn_ctxt` contained errors after cast check!" - ); - - res.ok() + check.do_check(&fn_ctxt).ok() } else { None } diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 81efec65343d1..7882bfdd09fad 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -314,9 +314,9 @@ impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BO impl<'tcx> LateLintPass<'tcx> for Types { fn check_fn( &mut self, - cx: &LateContext<'_>, + cx: &LateContext<'tcx>, fn_kind: FnKind<'_>, - decl: &FnDecl<'_>, + decl: &FnDecl<'tcx>, _: &Body<'_>, _: Span, def_id: LocalDefId, @@ -346,7 +346,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { ); } - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); match item.kind { @@ -363,7 +363,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { match item.kind { ImplItemKind::Const(ty, _) => { let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx @@ -391,7 +391,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } - fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { + fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &hir::FieldDef<'tcx>) { let is_exported = cx.effective_visibilities.is_exported(field.def_id); self.check_ty( @@ -404,7 +404,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { ); } - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) { + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); let context = CheckTyContext { @@ -421,7 +421,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { if let Some(ty) = local.ty { self.check_ty( cx, @@ -444,7 +444,7 @@ impl Types { } } - fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, context: CheckTyContext) { + fn check_fn_decl<'tcx>(&mut self, cx: &LateContext<'tcx>, decl: &FnDecl<'tcx>, context: CheckTyContext) { // Ignore functions in trait implementations as they are usually forced by the trait definition. // // FIXME: ideally we would like to warn *if the complicated type can be simplified*, but it's hard @@ -466,7 +466,7 @@ impl Types { /// lint found. /// /// The parameter `is_local` distinguishes the context of the type. - fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, mut context: CheckTyContext) { + fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, mut context: CheckTyContext) { if hir_ty.span.from_expansion() { return; } diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 5a986254fad5e..a0d609501a0c0 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::sym; use super::{utils, REDUNDANT_ALLOCATION}; -pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: &QPath<'tcx>, def_id: DefId) -> bool { let mut applicability = Applicability::MaybeIncorrect; let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() { "Box" diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 9d5066199bde5..a285f771f1b1c 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -13,10 +13,10 @@ use rustc_span::symbol::sym; use super::VEC_BOX; -pub(super) fn check( - cx: &LateContext<'_>, +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>, - qpath: &QPath<'_>, + qpath: &QPath<'tcx>, def_id: DefId, box_size_threshold: u64, ) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index e90306ded61c4..209035804e43e 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -77,7 +77,7 @@ fn get_ty_def_id(ty: Ty<'_>) -> Option { } } -fn get_hir_ty_def_id(tcx: TyCtxt<'_>, hir_ty: rustc_hir::Ty<'_>) -> Option { +fn get_hir_ty_def_id<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: rustc_hir::Ty<'tcx>) -> Option { let TyKind::Path(qpath) = hir_ty.kind else { return None }; match qpath { QPath::Resolved(_, path) => path.res.opt_def_id(), @@ -167,7 +167,15 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca false } }, - ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => { + ExprKind::MethodCall(segment, receiver, &[_arg], _) if segment.ident.name == name.name => { + if let Some(ty) = cx.typeck_results().expr_ty_opt(receiver) + && let Some(ty_id) = get_ty_def_id(ty) + && self_arg != ty_id + { + // Since this called on a different type, the lint should not be + // triggered here. + return; + } if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) && trait_id == trait_def_id @@ -229,7 +237,7 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local } } -fn is_default_method_on_current_ty(tcx: TyCtxt<'_>, qpath: QPath<'_>, implemented_ty_id: DefId) -> bool { +fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>, implemented_ty_id: DefId) -> bool { match qpath { QPath::Resolved(_, path) => match path.segments { [first, .., last] => last.ident.name == kw::Default && first.res.opt_def_id() == Some(implemented_ty_id), diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs index 903593ecfd7df..6732a43a19ec5 100644 --- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs +++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs @@ -57,11 +57,11 @@ impl LateLintPass<'_> for UninhabitedReferences { } } - fn check_fn( + fn check_fn<'tcx>( &mut self, - cx: &LateContext<'_>, + cx: &LateContext<'tcx>, kind: FnKind<'_>, - fndecl: &'_ FnDecl<'_>, + fndecl: &'_ FnDecl<'tcx>, _: &'_ Body<'_>, span: Span, _: LocalDefId, diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 1de9adfcb963a..adc66e15ff501 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -1,9 +1,10 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths}; +use hir::{ExprKind, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -45,126 +46,219 @@ declare_clippy_lint! { declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]); +#[derive(Copy, Clone)] +enum IoOp { + AsyncWrite(bool), + AsyncRead(bool), + SyncRead(bool), + SyncWrite(bool), +} + impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { - fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = s.kind else { - return; - }; + /// We perform the check on the block level. + /// If we want to catch match and if expressions that act as returns of the block + /// we need to check them at `check_expr` or `check_block` as they are not stmts + /// but we can't check them at `check_expr` because we need the broader context + /// because we should do this only for the final expression of the block, and not for + /// `StmtKind::Local` which binds values => the io amount is used. + /// + /// To check for unused io amount in stmts, we only consider `StmtKind::Semi`. + /// `StmtKind::Local` is not considered because it binds values => the io amount is used. + /// `StmtKind::Expr` is not considered because requires unit type => the io amount is used. + /// `StmtKind::Item` is not considered because it's not an expression. + /// + /// We then check the individual expressions via `check_expr`. We use the same logic for + /// semi expressions and the final expression as we need to check match and if expressions + /// for binding of the io amount to `Ok(_)`. + /// + /// We explicitly check for the match source to be Normal as it needs special logic + /// to consider the arms, and we want to avoid breaking the logic for situations where things + /// get desugared to match. + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) { + for stmt in block.stmts { + if let hir::StmtKind::Semi(exp) = stmt.kind { + check_expr(cx, exp); + } + } - match expr.kind { - hir::ExprKind::Match(res, _, _) if is_try(cx, expr).is_some() => { - if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind { - if matches!( - func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) - ) { - check_map_error(cx, arg_0, expr); + if let Some(exp) = block.expr + && matches!(exp.kind, hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, _)) + { + check_expr(cx, exp); + } + } +} + +fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { + match expr.kind { + hir::ExprKind::If(cond, _, _) + if let ExprKind::Let(hir::Let { pat, init, .. }) = cond.kind + && pattern_is_ignored_ok(cx, pat) + && let Some(op) = should_lint(cx, init) => + { + emit_lint(cx, cond.span, op, &[pat.span]); + }, + hir::ExprKind::Match(expr, arms, hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { + let found_arms: Vec<_> = arms + .iter() + .filter_map(|arm| { + if pattern_is_ignored_ok(cx, arm.pat) { + Some(arm.span) + } else { + None } - } else { - check_map_error(cx, res, expr); - } - }, - hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() { - "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" | "is_ok" | "is_err" => { - check_map_error(cx, arg_0, expr); - }, - _ => (), - }, - _ => (), + }) + .collect(); + if !found_arms.is_empty() { + emit_lint(cx, expr.span, op, found_arms.as_slice()); + } + }, + _ if let Some(op) = should_lint(cx, expr) => { + emit_lint(cx, expr.span, op, &[]); + }, + _ => {}, + }; +} + +fn should_lint<'a>(cx: &LateContext<'a>, mut inner: &'a hir::Expr<'a>) -> Option { + inner = unpack_match(inner); + inner = unpack_try(inner); + inner = unpack_call_chain(inner); + inner = unpack_await(inner); + // we type-check it to get whether it's a read/write or their vectorized forms + // and keep only the ones that are produce io amount + check_io_mode(cx, inner) +} + +fn pattern_is_ignored_ok(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> bool { + // the if checks whether we are in a result Ok( ) pattern + // and the return checks whether it is unhandled + + if let PatKind::TupleStruct(ref path, inner_pat, ddp) = pat.kind + // we check against Result::Ok to avoid linting on Err(_) or something else. + && is_res_lang_ctor(cx, cx.qpath_res(path, pat.hir_id), hir::LangItem::ResultOk) + { + return match (inner_pat, ddp.as_opt_usize()) { + // Ok(_) pattern + ([inner_pat], None) if matches!(inner_pat.kind, PatKind::Wild) => true, + // Ok(..) pattern + ([], Some(0)) => true, + _ => false, + }; + } + false +} + +fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + while let hir::ExprKind::MethodCall(path, receiver, ..) = expr.kind { + if matches!( + path.ident.as_str(), + "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or" + ) { + expr = receiver; + } else { + break; } } + expr +} + +fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + while let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind + && matches!( + func.kind, + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) + ) + { + expr = arg_0; + } + expr +} + +fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + while let hir::ExprKind::Match(res, _, _) = expr.kind { + expr = res; + } + expr } /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. -fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> { +fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { if matches!( func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) ) { - return Some(arg_0); + return arg_0; } } } - - None + expr } -fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { - let mut call = call; - while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind { - if matches!(path.ident.as_str(), "or" | "or_else" | "ok") { - call = receiver; - } else { - break; - } - } +/// Check whether the current expr is a function call for an IO operation +fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option { + let hir::ExprKind::MethodCall(path, ..) = call.kind else { + return None; + }; - if let Some(call) = try_remove_await(call) { - check_method_call(cx, call, expr, true); - } else { - check_method_call(cx, call, expr, false); + let vectorized = match path.ident.as_str() { + "write_vectored" | "read_vectored" => true, + "write" | "read" => false, + _ => { + return None; + }, + }; + + match ( + is_trait_method(cx, call, sym::IoRead), + is_trait_method(cx, call, sym::IoWrite), + match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) + || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT), + match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) + || match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT), + ) { + (true, _, _, _) => Some(IoOp::SyncRead(vectorized)), + (_, true, _, _) => Some(IoOp::SyncWrite(vectorized)), + (_, _, true, _) => Some(IoOp::AsyncRead(vectorized)), + (_, _, _, true) => Some(IoOp::AsyncWrite(vectorized)), + _ => None, } } -fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) { - if let hir::ExprKind::MethodCall(path, ..) = call.kind { - let symbol = path.ident.as_str(); - let read_trait = if is_await { - match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) - || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT) - } else { - is_trait_method(cx, call, sym::IoRead) - }; - let write_trait = if is_await { - match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT) - || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) - } else { - is_trait_method(cx, call, sym::IoWrite) - }; +fn emit_lint(cx: &LateContext<'_>, span: Span, op: IoOp, wild_cards: &[Span]) { + let (msg, help) = match op { + IoOp::AsyncRead(false) => ( + "read amount is not handled", + Some("use `AsyncReadExt::read_exact` instead, or handle partial reads"), + ), + IoOp::SyncRead(false) => ( + "read amount is not handled", + Some("use `Read::read_exact` instead, or handle partial reads"), + ), + IoOp::SyncWrite(false) => ( + "written amount is not handled", + Some("use `Write::write_all` instead, or handle partial writes"), + ), + IoOp::AsyncWrite(false) => ( + "written amount is not handled", + Some("use `AsyncWriteExt::write_all` instead, or handle partial writes"), + ), + IoOp::SyncRead(true) | IoOp::AsyncRead(true) => ("read amount is not handled", None), + IoOp::SyncWrite(true) | IoOp::AsyncWrite(true) => ("written amount is not handled", None), + }; - match (read_trait, write_trait, symbol, is_await) { - (true, _, "read", false) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "read amount is not handled", - None, - "use `Read::read_exact` instead, or handle partial reads", - ), - (true, _, "read", true) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "read amount is not handled", - None, - "use `AsyncReadExt::read_exact` instead, or handle partial reads", - ), - (true, _, "read_vectored", _) => { - span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled"); - }, - (_, true, "write", false) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "written amount is not handled", - None, - "use `Write::write_all` instead, or handle partial writes", - ), - (_, true, "write", true) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "written amount is not handled", - None, - "use `AsyncWriteExt::write_all` instead, or handle partial writes", - ), - (_, true, "write_vectored", _) => { - span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled"); - }, - _ => (), + span_lint_and_then(cx, UNUSED_IO_AMOUNT, span, msg, |diag| { + if let Some(help_str) = help { + diag.help(help_str); } - } + for span in wild_cards { + diag.span_note( + *span, + "the result is consumed here, but the amount of I/O bytes remains unhandled", + ); + } + }); } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index fa033838ef355..a1b08d105b9d9 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } - fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { + fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) { if !hir_ty.span.from_expansion() && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index b26ebe5cee321..288df0fd663f0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -490,6 +490,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})") }, }, + ClosureKind::CoroutineClosure(desugaring) => format!( + "ClosureKind::CoroutineClosure(CoroutineDesugaring::{desugaring:?})" + ), }; let ret_ty = match fn_decl.output { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 5ddedb24b15a4..4822970e47ef5 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { ident.span, "non-standard lint formulation", None, - &format!("try using `{}` instead", formulation.correction), + &format!("consider using `{}`", formulation.correction), ); } return; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index 5059712d69c14..df37619227c86 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -41,7 +41,6 @@ impl CompilerLintFunctions { pub fn new() -> Self { let mut map = FxHashMap::default(); map.insert("span_lint", "utils::span_lint"); - map.insert("struct_span_lint", "utils::span_lint"); map.insert("lint", "utils::span_lint"); map.insert("span_lint_note", "utils::span_lint_and_note"); map.insert("span_lint_help", "utils::span_lint_and_help"); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 4fb615e1d579e..c62ae8d718dba 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -71,7 +71,9 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { SimplifiedType::Str, ] .iter() - .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied()); + .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter()) + .flatten() + .copied(); for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { let lang_item_path = cx.get_def_path(item_def_id); if path_syms.starts_with(&lang_item_path) { 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 b36c4ef91dc61..81d4a26e9da43 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 @@ -44,7 +44,7 @@ declare_clippy_lint! { declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]); impl LateLintPass<'_> for ZeroSizedMapValues { - fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { + fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) { if !hir_ty.span.from_expansion() && !in_trait_impl(cx, hir_ty.hir_id) && let ty = ty_from_hir_ty(cx, hir_ty) @@ -82,7 +82,7 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool { false } -fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { +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 { diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index ad8619f0d3d96..2d0c2cf125364 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -1,5 +1,6 @@ use rustc_ast::{ast, attr}; use rustc_errors::Applicability; +use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; use rustc_span::sym; use std::str::FromStr; @@ -159,3 +160,14 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { .filter_map(ast::Attribute::meta_item_list) .any(|l| attr::list_contains_name(&l, sym::hidden)) } + +pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { + adt.is_variant_list_non_exhaustive() + || tcx.has_attr(adt.did(), sym::non_exhaustive) + || adt.variants().iter().any(|variant_def| { + variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive) + }) + || adt + .all_fields() + .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive)) +} diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 727f93c832742..61b38391d9e09 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -275,7 +275,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option>) -> Constan LitKind::Byte(b) => Constant::Int(u128::from(b)), LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)), LitKind::Char(c) => Constant::Char(c), - LitKind::Int(n, _) => Constant::Int(n), + LitKind::Int(n, _) => Constant::Int(n.get()), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()), ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()), diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 7562961538e30..56978eb2ee805 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -47,7 +47,7 @@ fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { /// ``` pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into, msg: &str) { #[expect(clippy::disallowed_methods)] - cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { + cx.span_lint(lint, sp, msg.to_string(), |diag| { docs_link(diag, lint); }); } @@ -81,7 +81,7 @@ pub fn span_lint_and_help( help: &str, ) { #[expect(clippy::disallowed_methods)] - cx.struct_span_lint(lint, span, msg.to_string(), |diag| { + cx.span_lint(lint, span, msg.to_string(), |diag| { let help = help.to_string(); if let Some(help_span) = help_span { diag.span_help(help_span, help.to_string()); @@ -124,7 +124,7 @@ pub fn span_lint_and_note( note: &str, ) { #[expect(clippy::disallowed_methods)] - cx.struct_span_lint(lint, span, msg.to_string(), |diag| { + cx.span_lint(lint, span, msg.to_string(), |diag| { let note = note.to_string(); if let Some(note_span) = note_span { diag.span_note(note_span, note); @@ -146,7 +146,7 @@ where F: FnOnce(&mut Diagnostic), { #[expect(clippy::disallowed_methods)] - cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { + cx.span_lint(lint, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); }); @@ -154,7 +154,7 @@ where pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { #[expect(clippy::disallowed_methods)] - cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { + cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| { docs_link(diag, lint); }); } @@ -168,7 +168,7 @@ pub fn span_lint_hir_and_then( f: impl FnOnce(&mut Diagnostic), ) { #[expect(clippy::disallowed_methods)] - cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { + cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); }); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 979b117db256a..4fa93ad23c369 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -134,7 +134,7 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + use TokenKind::{Semi, Whitespace}; if left.stmts.len() != right.stmts.len() { return false; } @@ -177,7 +177,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) { return false; } @@ -212,7 +212,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index d264e46f13320..4e499ff4cc612 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -80,6 +80,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; @@ -535,7 +536,12 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), #[allow(trivial_casts)] - _ => return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]).into_iter().flatten().copied(), + _ => { + return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]) + .into_iter() + .flatten() + .copied(); + }, }; tcx.incoherent_impls(ty).into_iter().flatten().copied() @@ -838,7 +844,7 @@ pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match &e.kind { ExprKind::Lit(lit) => match lit.node { - LitKind::Bool(false) | LitKind::Int(0, _) => true, + LitKind::Bool(false) | LitKind::Int(Pu128(0), _) => true, LitKind::Str(s, _) => s.is_empty(), _ => false, }, @@ -1711,7 +1717,6 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), - PatKind::Lit(..) | PatKind::Range(..) => true, PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set @@ -1735,7 +1740,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Err(_) => true, + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) => true, } } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 0a820a1754cae..0051f78451467 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -26,6 +26,7 @@ pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; +pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates @@ -50,6 +51,7 @@ 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 MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; +pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; @@ -89,9 +91,15 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"]; +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"]; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 61d0663aa8399..11bb16ff6c5bf 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -214,36 +214,22 @@ pub fn implements_trait<'tcx>( trait_id: DefId, args: &[GenericArg<'tcx>], ) -> bool { - let callee_id = cx - .enclosing_body - .map(|body| cx.tcx.hir().body_owner(body).owner.to_def_id()); - implements_trait_with_env_from_iter( - cx.tcx, - cx.param_env, - ty, - trait_id, - callee_id, - args.iter().map(|&x| Some(x)), - ) + implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, None, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. +/// +/// The `callee_id` argument is used to determine whether this is a function call in a `const fn` +/// environment, used for checking const traits. pub fn implements_trait_with_env<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, - callee_id: DefId, + callee_id: Option, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter( - tcx, - param_env, - ty, - trait_id, - Some(callee_id), - args.iter().map(|&x| Some(x)), - ) + implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait_from_env` but takes the arguments as an iterator. @@ -258,6 +244,13 @@ pub fn implements_trait_with_env_from_iter<'tcx>( // Clippy shouldn't have infer types assert!(!ty.has_infer()); + // If a `callee_id` is passed, then we assert that it is a body owner + // through calling `body_owner_kind`, which would panic if the callee + // does not have a body. + if let Some(callee_id) = callee_id { + let _ = tcx.hir().body_owner_kind(callee_id); + } + let ty = tcx.erase_regions(ty); if ty.has_escaping_bound_vars() { return false; diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 2589d46e7da07..d2d56e59ee3fb 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-01-11" +channel = "nightly-2024-01-25" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.stderr new file mode 100644 index 0000000000000..8f0ca76492497 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.stderr @@ -0,0 +1,6 @@ +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 + | + = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::multiple_crate_versions)]` + +error: could not compile `multiple-crate-versions` (bin "multiple-crate-versions") due to 1 previous error diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.toml new file mode 100644 index 0000000000000..d39ad6c909a8b --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.toml @@ -0,0 +1,14 @@ +# Should not lint for dev or build dependencies. See issue 5041. + +[package] +# purposefully separated by - instead of _ +name = "multiple-crate-versions" +version = "0.1.0" +publish = false + +[workspace] + +# One of the versions of winapi is only a dev dependency: allowed +[dependencies] +winapi = "0.2" +ansi_term = "=0.11.0" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/src/main.rs new file mode 100644 index 0000000000000..4bc61dd62992f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/Cargo.toml new file mode 100644 index 0000000000000..79317659ac072 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "multiple_crate_versions" +version = "0.1.0" +publish = false + +[workspace] + +[dependencies] +winapi = "0.2" +ansi_term = "=0.11.0" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/clippy.toml new file mode 100644 index 0000000000000..121361de2fe0b --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/clippy.toml @@ -0,0 +1 @@ +allowed-duplicate-crates = ["winapi"] diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/src/main.rs new file mode 100644 index 0000000000000..4bc61dd62992f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-internal/check_formulation.stderr b/src/tools/clippy/tests/ui-internal/check_formulation.stderr index 96fa617601ff4..42a872d9a83f7 100644 --- a/src/tools/clippy/tests/ui-internal/check_formulation.stderr +++ b/src/tools/clippy/tests/ui-internal/check_formulation.stderr @@ -4,7 +4,7 @@ error: non-standard lint formulation LL | /// Check for lint formulations that are correct | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try using `Checks for` instead + = help: consider using `Checks for` = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::almost_standard_lint_formulation)]` @@ -14,7 +14,7 @@ error: non-standard lint formulation LL | /// Detects uses of incorrect formulations | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try using `Checks for` instead + = help: consider using `Checks for` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs similarity index 83% rename from src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs rename to src/tools/clippy/tests/ui-internal/disallow_span_lint.rs index c81d54918cbbb..b9b4a07d29d0e 100644 --- a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs @@ -11,7 +11,7 @@ use rustc_lint::{Lint, LintContext}; use rustc_middle::ty::TyCtxt; pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into, msg: impl Into) { - cx.struct_span_lint(lint, span, msg, |_| {}); + cx.span_lint(lint, span, msg, |_| {}); } pub fn b( @@ -21,7 +21,7 @@ pub fn b( span: impl Into, msg: impl Into, ) { - tcx.struct_span_lint_hir(lint, hir_id, span, msg, |_| {}); + tcx.node_span_lint(lint, hir_id, span, msg, |_| {}); } fn main() {} diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr new file mode 100644 index 0000000000000..5ca183d41a93a --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr @@ -0,0 +1,17 @@ +error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` + --> $DIR/disallow_span_lint.rs:14:5 + | +LL | cx.span_lint(lint, span, msg, |_| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 `rustc_middle::ty::context::TyCtxt::node_span_lint` + --> $DIR/disallow_span_lint.rs:24:5 + | +LL | tcx.node_span_lint(lint, hir_id, span, msg, |_| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr deleted file mode 100644 index 7d424124f2b12..0000000000000 --- a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: use of a disallowed method `rustc_lint::context::LintContext::struct_span_lint` - --> $DIR/disallow_struct_span_lint.rs:14:5 - | -LL | cx.struct_span_lint(lint, span, msg, |_| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 `rustc_middle::ty::context::TyCtxt::struct_span_lint_hir` - --> $DIR/disallow_struct_span_lint.rs:24:5 - | -LL | tcx.struct_span_lint_hir(lint, hir_id, span, msg, |_| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml index 94a0d3554bc7b..9e472bd14ba53 100644 --- a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml @@ -1 +1 @@ -pub-underscore-fields-behavior = "PublicallyExported" \ No newline at end of file +pub-underscore-fields-behavior = "PubliclyExported" diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml index b77b4580051ef..2b63f6e5c26f7 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml @@ -3,6 +3,9 @@ foobar = 42 # so is this one barfoo = 53 +# when using underscores instead of dashes, suggest the correct one +allow_mixed_uninlined_format_args = true + # that one is ignored [third-party] clippy-feature = "nightly" 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 38009627757c2..49139b60a9f43 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,3 +1,4 @@ +//@no-rustfix //@error-in-other-file: unknown field `foobar`, expected one of 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 ed4fb84df1ae1..fc683e514ba40 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 @@ -11,6 +11,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-private-module-inception allow-unwrap-in-tests allowed-dotfiles + allowed-duplicate-crates allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed @@ -87,6 +88,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-private-module-inception allow-unwrap-in-tests allowed-dotfiles + allowed-duplicate-crates allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed @@ -150,5 +152,82 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect LL | barfoo = 53 | ^^^^^^ -error: aborting due to 2 previous errors +error: error reading Clippy's configuration file: unknown field `allow_mixed_uninlined_format_args`, expected one of + absolute-paths-allowed-crates + absolute-paths-max-segments + accept-comment-above-attributes + accept-comment-above-statement + allow-dbg-in-tests + allow-expect-in-tests + allow-mixed-uninlined-format-args + allow-one-hash-in-raw-strings + allow-print-in-tests + allow-private-module-inception + allow-unwrap-in-tests + allowed-dotfiles + allowed-duplicate-crates + allowed-idents-below-min-chars + allowed-scripts + arithmetic-side-effects-allowed + arithmetic-side-effects-allowed-binary + arithmetic-side-effects-allowed-unary + array-size-threshold + avoid-breaking-exported-api + await-holding-invalid-types + blacklisted-names + cargo-ignore-publish + check-private-items + cognitive-complexity-threshold + cyclomatic-complexity-threshold + disallowed-macros + disallowed-methods + disallowed-names + disallowed-types + doc-valid-idents + enable-raw-pointer-heuristic-for-send + enforce-iter-loop-reborrow + enforced-import-renames + enum-variant-name-threshold + enum-variant-size-threshold + excessive-nesting-threshold + future-size-threshold + ignore-interior-mutability + large-error-threshold + literal-representation-threshold + matches-for-let-else + max-fn-params-bools + max-include-file-size + max-struct-bools + max-suggested-slice-pattern-length + max-trait-bounds + min-ident-chars-threshold + missing-docs-in-crate-items + msrv + pass-by-value-size-limit + pub-underscore-fields-behavior + semicolon-inside-block-ignore-singleline + semicolon-outside-block-ignore-multiline + single-char-binding-names-threshold + stack-size-threshold + standard-macro-braces + struct-field-name-threshold + suppress-restriction-lint-in-const + third-party + too-large-for-stack + too-many-arguments-threshold + too-many-lines-threshold + trivial-copy-size-limit + type-complexity-threshold + unnecessary-box-size + unreadable-literal-lint-fractions + upper-case-acronyms-aggressive + vec-box-size-threshold + verbose-bit-mask-threshold + warn-on-all-wildcard-imports + --> $DIR/$DIR/clippy.toml:7:1 + | +LL | allow_mixed_uninlined_format_args = true + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: perhaps you meant: `allow-mixed-uninlined-format-args` + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 8c4d71e68f80f..579f137f861e1 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind { // report your lint here } -if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind +if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::CoroutineClosure(CoroutineDesugaring::Async), .. } = expr.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr1 = &cx.tcx.hir().body(body_id).value - && let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind + && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind && let FnRetTy::DefaultReturn(_) = fn_decl1.output && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs index c58795575160b..ac544737099c6 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs @@ -11,8 +11,8 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_macro_input, parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, - TraitItem, Type, + parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, + Signature, TraitItem, Type, }; #[proc_macro_attribute] @@ -95,3 +95,33 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea TokenStream::from(quote!(#item)) } + +#[proc_macro_attribute] +pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut item = parse_macro_input!(item as ItemFn); + let span = item.block.brace_token.span; + + if item.sig.asyncness.is_some() { + item.sig.asyncness = None; + } + + let crate_name = quote! { fake_crate }; + let block = item.block; + item.block = syn::parse_quote_spanned! { + span => + { + #crate_name::block_on(async { + #block + }) + } + }; + + quote! { + mod #crate_name { + pub fn block_on(_fut: F) {} + } + + #item + } + .into() +} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index 2ab441bbd0c69..efef60567a979 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -85,4 +85,18 @@ fn block_in_match_expr(num: i32) -> i32 { } } +// issue #12162 +macro_rules! timed { + ($name:expr, $body:expr $(,)?) => {{ + let __scope = (); + $body + }}; +} + +fn issue_12162() { + if timed!("check this!", false) { + println!(); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index dd5ae4fb486b7..8bd8a939eb16e 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -85,4 +85,18 @@ fn block_in_match_expr(num: i32) -> i32 { } } +// issue #12162 +macro_rules! timed { + ($name:expr, $body:expr $(,)?) => {{ + let __scope = (); + $body + }}; +} + +fn issue_12162() { + if timed!("check this!", false) { + println!(); + } +} + fn main() {} 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 44f8b2eabce3b..9af81f6f7cdda 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,17 +9,16 @@ fn simple_examples() { // Simple if true { - //~^ ERROR: all if blocks contain the same code at the start 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 { - //~^ ERROR: all if blocks contain the same code at the start let y = 9; println!("The value y was set to: `{}`", y); let _z = y; @@ -38,6 +37,7 @@ 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 { @@ -60,7 +60,6 @@ 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 { - //~^ ERROR: all if blocks contain the same code at the start let used_value_name = "Different type"; println!("Str: {}", used_value_name); let _ = 1; @@ -69,6 +68,7 @@ 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 @@ -101,11 +101,11 @@ fn check_if_same_than_else_mask() { } if x == 2019 { - //~^ ERROR: this `if` has identical blocks println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } else { println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } + //~^^^^^ ERROR: this `if` has identical blocks } #[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 9d4d42fb689e4..317d1577226ca 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,7 +2,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:11:5 | LL | / if true { -LL | | LL | | println!("Hello World!"); | |_________________________________^ | @@ -21,7 +20,6 @@ error: all if blocks contain the same code at the start --> $DIR/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; @@ -54,7 +52,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:62:5 | LL | / if x == 10 { -LL | | LL | | let used_value_name = "Different type"; LL | | println!("Str: {}", used_value_name); | |_____________________________________________^ @@ -105,13 +102,12 @@ error: this `if` has identical blocks | LL | if x == 2019 { | __________________^ -LL | | LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); LL | | } else { | |_____^ | note: same as this - --> $DIR/shared_at_top.rs:106:12 + --> $DIR/shared_at_top.rs:105:12 | LL | } else { | ____________^ 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 2aeacb89c0cb6..b63819d7c3932 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 @@ -107,9 +107,9 @@ fn valid_examples() { // Let's test empty blocks if false { - //~^ ERROR: this `if` has identical blocks } else { } + //~^^^ ERROR: this `if` has identical blocks } /// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint @@ -119,7 +119,6 @@ fn trigger_other_lint() { // Same block if x == 0 { - //~^ ERROR: this `if` has identical blocks let u = 19; println!("How are u today?"); let _ = "This is a string"; @@ -128,6 +127,7 @@ fn trigger_other_lint() { println!("How are u today?"); let _ = "This is a string"; } + //~^^^^^^^^^ ERROR: this `if` has identical blocks // Only same expression let _ = if x == 6 { 7 } else { 7 }; @@ -138,28 +138,24 @@ fn trigger_other_lint() { println!("Well I'm the most important block"); "I'm a pretty string" } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below if y == 90 { "=^.^=" } else { ":D" } } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); if y == 90 { "=^.^=" } else { ":D" } }; + //~^^^^^^^^^ ERROR: this `if` has identical blocks if x == 0 { println!("I'm single"); } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); } + //~^^^^^ ERROR: this `if` has identical blocks } fn main() {} diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr index fcbf12235aa16..0daf2ff6967cd 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr @@ -3,12 +3,11 @@ error: this `if` has identical blocks | LL | if false { | ______________^ -LL | | LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:111:12 + --> $DIR/valid_if_blocks.rs:110:12 | LL | } else { | ____________^ @@ -25,7 +24,6 @@ error: this `if` has identical blocks | LL | if x == 0 { | _______________^ -LL | | LL | | let u = 19; LL | | println!("How are u today?"); LL | | let _ = "This is a string"; @@ -33,7 +31,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:126:12 + --> $DIR/valid_if_blocks.rs:125:12 | LL | } else { | ____________^ @@ -60,20 +58,17 @@ error: this `if` has identical blocks | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:146:12 + --> $DIR/valid_if_blocks.rs:144:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } @@ -81,22 +76,19 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:155:23 + --> $DIR/valid_if_blocks.rs:153:23 | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:159:12 + --> $DIR/valid_if_blocks.rs:155:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs index 2ae426cf789de..8af60890390e7 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs @@ -11,8 +11,6 @@ fn main() { // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) match FOO_REF_REF { FOO_REF_REF => {}, - //~^ ERROR: to use a constant of type `Foo` in a pattern, `Foo` must be annotated - //~| NOTE: for more information, see issue #62411 {}, } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr deleted file mode 100644 index 7a34e6cceeea7..0000000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/ice-6254.rs:13:9 - | -LL | FOO_REF_REF => {}, - | ^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `-D indirect-structural-match` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(indirect_structural_match)]` - -error: aborting due to 1 previous error - diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr index 00b65f00d787c..67589d1a8ab32 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr @@ -2,7 +2,7 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/ice-9041.rs:5:19 | LL | things.iter().find(|p| is_thing_ready(p)).is_some() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|p| is_thing_ready(&p))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|p| is_thing_ready(&p))` | = note: `-D clippy::search-is-some` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` 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 new file mode 100644 index 0000000000000..7300bd9bd2abd --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed @@ -0,0 +1,28 @@ +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[derive(Default)] +struct Iter { + iter: core::iter::Empty, +} + +fn main() { + // Do lint. + let _ = core::iter::empty::(); + let _foo: core::iter::Empty = core::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 new file mode 100644 index 0000000000000..0bc5c7169d129 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs @@ -0,0 +1,28 @@ +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[derive(Default)] +struct Iter { + iter: core::iter::Empty, +} + +fn main() { + // Do lint. + let _ = core::iter::Empty::::default(); + let _foo: core::iter::Empty = core::iter::Empty::default(); + + // 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 new file mode 100644 index 0000000000000..747a31ecbf366 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr @@ -0,0 +1,17 @@ +error: `core::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty_no_std.rs:23:13 + | +LL | let _ = core::iter::Empty::::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty::()` + | + = note: `-D clippy::default-instead-of-iter-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_instead_of_iter_empty)]` + +error: `core::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty_no_std.rs:24:42 + | +LL | let _foo: core::iter::Empty = core::iter::Empty::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty()` + +error: aborting due to 2 previous errors + 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 c364c6830578f..e7038082c089c 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed @@ -216,4 +216,44 @@ mod type_already_inferred { } } +mod issue12159 { + #![allow(non_upper_case_globals, clippy::exhaustive_structs)] + pub struct Foo; + + static F: i32 = 1; + impl Foo { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + + const fn consts() { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + } + } +} + fn main() {} 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 ffa7b961d1ced..d8eeda7049194 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs @@ -216,4 +216,44 @@ mod type_already_inferred { } } +mod issue12159 { + #![allow(non_upper_case_globals, clippy::exhaustive_structs)] + pub struct Foo; + + static F: i32 = 1; + impl Foo { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + + const fn consts() { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + } + } +} + fn main() {} 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 a7f5d3ec7cd08..aa7a95405e02f 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 @@ -121,4 +121,36 @@ pub fn _from_mod() -> _hidden::InPubFn { #[derive(PartialEq)] struct InternalTy; +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub struct MissingEqNonExhaustive { + foo: u32, + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub struct MissingEqNonExhaustive1 { + foo: u32, + #[non_exhaustive] + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub enum MissingEqNonExhaustive2 { + Foo, + Bar, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub enum MissingEqNonExhaustive3 { + Foo, + #[non_exhaustive] + Bar, +} + fn main() {} 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 476d2aee23a88..90ac7a7989e00 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 @@ -121,4 +121,36 @@ pub fn _from_mod() -> _hidden::InPubFn { #[derive(PartialEq)] struct InternalTy; +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub struct MissingEqNonExhaustive { + foo: u32, + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub struct MissingEqNonExhaustive1 { + foo: u32, + #[non_exhaustive] + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub enum MissingEqNonExhaustive2 { + Foo, + Bar, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub enum MissingEqNonExhaustive3 { + Foo, + #[non_exhaustive] + Bar, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index bff46e55722ba..16f7bafd44b78 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -64,7 +64,7 @@ fn test_units() { /// NaN NaNs /// OAuth GraphQL /// OCaml -/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS +/// OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry /// WebGL WebGL2 WebGPU /// TensorFlow /// TrueType diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 4e162a97dee9b..4058b2bad74f7 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -64,7 +64,7 @@ fn test_units() { /// NaN NaNs /// OAuth GraphQL /// OCaml -/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS +/// OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry /// WebGL WebGL2 WebGPU /// TensorFlow /// TrueType 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 3811421dc7158..72097bfabd726 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 @@ -20,12 +20,8 @@ mod rustc_ok { pub fn rustc_lints() { let x = 42.0; - #[expect(illegal_floating_point_literal_pattern)] - match x { - 5.0 => {} - 6.0 => {} - _ => {} - } + #[expect(invalid_nan_comparisons)] + let _b = x == f32::NAN; } } @@ -38,13 +34,9 @@ mod rustc_warn { pub fn rustc_lints() { let x = 42; - #[expect(illegal_floating_point_literal_pattern)] + #[expect(invalid_nan_comparisons)] //~^ ERROR: this lint expectation is unfulfilled - match x { - 5 => {} - 6 => {} - _ => {} - } + 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 3f8d0b7243620..2a418d8456635 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 @@ -1,5 +1,5 @@ error: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:35:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:31:14 | LL | #[expect(dead_code)] | ^^^^^^^^^ @@ -8,31 +8,31 @@ LL | #[expect(dead_code)] = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]` error: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:41:18 + --> $DIR/expect_tool_lint_rfc_2383.rs:37:18 | -LL | #[expect(illegal_floating_point_literal_pattern)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[expect(invalid_nan_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:116:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:108:14 | LL | #[expect(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:124:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:116:14 | LL | #[expect(clippy::bytes_nth)] | ^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:130:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:122:14 | LL | #[expect(clippy::if_same_then_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:136:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:128:14 | LL | #[expect(clippy::overly_complex_bool_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed index 18d285693e603..4a68505ee0b1c 100644 --- a/src/tools/clippy/tests/ui/from_over_into.fixed +++ b/src/tools/clippy/tests/ui/from_over_into.fixed @@ -89,4 +89,12 @@ fn msrv_1_41() { } } +fn issue_12138() { + struct Hello; + + impl From for () { + fn from(val: Hello) {} + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs index 779ef709e9284..bf3ed0c2b6422 100644 --- a/src/tools/clippy/tests/ui/from_over_into.rs +++ b/src/tools/clippy/tests/ui/from_over_into.rs @@ -89,4 +89,12 @@ fn msrv_1_41() { } } +fn issue_12138() { + struct Hello; + + impl Into<()> for Hello { + fn into(self) {} + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index 784843ce5fd55..f1370ed844fa9 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -86,5 +86,19 @@ LL ~ fn from(val: Vec) -> Self { LL ~ FromOverInto(val) | -error: aborting due to 6 previous errors +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into.rs:95:5 + | +LL | impl Into<()> for Hello { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `impl From for Foreign` is allowed by the orphan rules, for more information see + https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence +help: replace the `Into` implementation with `From` + | +LL ~ impl From for () { +LL ~ fn from(val: Hello) {} + | + +error: aborting due to 7 previous errors 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 e84b20e9fef07..d53e1383d845c 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else.rs @@ -21,7 +21,6 @@ fn foo() -> bool { fn if_same_then_else() { if true { - //~^ ERROR: this `if` has identical blocks Foo { bar: 42 }; 0..10; ..; @@ -38,6 +37,7 @@ fn if_same_then_else() { 0..=10; foo(); } + //~^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { Foo { bar: 42 }; @@ -64,19 +64,11 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 0.0 - } else { - 0.0 - }; + let _ = if true { 0.0 } else { 0.0 }; + //~^ ERROR: this `if` has identical blocks - let _ = if true { - //~^ ERROR: this `if` has identical blocks - -0.0 - } else { - -0.0 - }; + let _ = if true { -0.0 } else { -0.0 }; + //~^ ERROR: this `if` has identical blocks let _ = if true { 0.0 } else { -0.0 }; @@ -87,15 +79,10 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 42 - } else { - 42 - }; + let _ = if true { 42 } else { 42 }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks let bar = if true { 42 } else { 43 }; while foo() { @@ -110,6 +97,7 @@ fn if_same_then_else() { } bar + 1; } + //~^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { let _ = match 42 { diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr index fb33e94e6c3de..281f30f88b46d 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | Foo { bar: 42 }; LL | | 0..10; +LL | | ..; ... | LL | | foo(); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:32:12 + --> $DIR/if_same_then_else.rs:31:12 | LL | } else { | ____________^ @@ -29,75 +29,54 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else.rs:67:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:70:12 + --> $DIR/if_same_then_else.rs:67:34 | -LL | } else { - | ____________^ -LL | | 0.0 -LL | | }; - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:74:21 + --> $DIR/if_same_then_else.rs:70:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | -0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:77:12 + --> $DIR/if_same_then_else.rs:70:35 | -LL | } else { - | ____________^ -LL | | -0.0 -LL | | }; - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:90:21 + --> $DIR/if_same_then_else.rs:82:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 42 -LL | | } else { - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:93:12 + --> $DIR/if_same_then_else.rs:82:33 | -LL | } else { - | ____________^ -LL | | 42 -LL | | }; - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:97:13 + --> $DIR/if_same_then_else.rs:85:13 | LL | if true { | _____________^ -LL | | LL | | let bar = if true { 42 } else { 43 }; LL | | +LL | | while foo() { ... | LL | | bar + 1; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:105:12 + --> $DIR/if_same_then_else.rs:92:12 | LL | } else { | ____________^ @@ -110,7 +89,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:250:14 + --> $DIR/if_same_then_else.rs:238:14 | LL | if x { | ______________^ @@ -119,7 +98,7 @@ LL | | } else { | |_________^ | note: same as this - --> $DIR/if_same_then_else.rs:252:16 + --> $DIR/if_same_then_else.rs:240:16 | LL | } 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 0b171f21d0cc4..e23c77b082744 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs @@ -13,7 +13,6 @@ fn if_same_then_else2() -> Result<&'static str, ()> { if true { - //~^ ERROR: this `if` has identical blocks for _ in &[42] { let foo: &Option<_> = &Some::(42); if foo.is_some() { @@ -32,20 +31,21 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } } } + //~^^^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let Some(a) = Some(42) {} } else { if let Some(a) = Some(42) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let (1, .., 3) = (1, 2, 3) {} } else { if let (1, .., 3) = (1, 2, 3) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { if let (1, .., 3) = (1, 2, 3) {} @@ -90,19 +90,15 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } // Same NaNs - let _ = if true { - //~^ ERROR: this `if` has identical blocks - f32::NAN - } else { - f32::NAN - }; + let _ = if true { f32::NAN } else { f32::NAN }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks Ok("foo")?; } else { Ok("foo")?; } + //~^^^^^ ERROR: this `if` has identical blocks if true { let foo = ""; @@ -122,13 +118,13 @@ fn if_same_then_else2() -> Result<&'static str, ()> { let foo = "bar"; return Ok(&foo[0..]); } else if true { - //~^ ERROR: this `if` has identical blocks let foo = ""; return Ok(&foo[0..]); } else { let foo = ""; return Ok(&foo[0..]); } + //~^^^^^^^ ERROR: this `if` has identical blocks // 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_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr index fe68ef2711b59..4e7a7c87dc54b 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | for _ in &[42] { LL | | let foo: &Option<_> = &Some::(42); +LL | | if foo.is_some() { ... | LL | | } LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:25:12 + --> $DIR/if_same_then_else2.rs:24:12 | LL | } else { | ____________^ @@ -31,13 +31,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let Some(a) = Some(42) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:39:12 + --> $DIR/if_same_then_else2.rs:38:12 | LL | } else { | ____________^ @@ -50,13 +49,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:46:12 + --> $DIR/if_same_then_else2.rs:45:12 | LL | } else { | ____________^ @@ -67,34 +65,26 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:93:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | f32::NAN -LL | | } else { - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else2.rs:96:12 + --> $DIR/if_same_then_else2.rs:93:39 | -LL | } else { - | ____________^ -LL | | f32::NAN -LL | | }; - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:100:13 + --> $DIR/if_same_then_else2.rs:96:13 | LL | if true { | _____________^ -LL | | LL | | Ok("foo")?; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:103:12 + --> $DIR/if_same_then_else2.rs:98:12 | LL | } else { | ____________^ @@ -103,18 +93,17 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:124:20 + --> $DIR/if_same_then_else2.rs:120:20 | LL | } else if true { | ____________________^ -LL | | LL | | let foo = ""; LL | | return Ok(&foo[0..]); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:128:12 + --> $DIR/if_same_then_else2.rs:123:12 | LL | } else { | ____________^ diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.fixed b/src/tools/clippy/tests/ui/ineffective_open_options.fixed index 3af8f3c5aaa44..88489dc46bbb4 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.fixed +++ b/src/tools/clippy/tests/ui/ineffective_open_options.fixed @@ -26,16 +26,23 @@ fn main() { .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(true) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(false) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap(); - let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap(); + let file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .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 4eaf6293c408e..db8bca3e2acdb 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.rs +++ b/src/tools/clippy/tests/ui/ineffective_open_options.rs @@ -26,16 +26,23 @@ fn main() { .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(true) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(false) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap(); - let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap(); + let file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open("dump.json") + .unwrap(); } diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.stderr b/src/tools/clippy/tests/ui/join_absolute_paths.stderr index 0c2f89d9978b3..ab4d189ca3a22 100644 --- a/src/tools/clippy/tests/ui/join_absolute_paths.stderr +++ b/src/tools/clippy/tests/ui/join_absolute_paths.stderr @@ -11,7 +11,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join("sh"); | ~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from("/sh"); | ~~~~~~~~~~~~~~~~~~~~ @@ -27,7 +27,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join("\user"); | ~~~~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from("\\user"); | ~~~~~~~~~~~~~~~~~~~~~~~ @@ -43,7 +43,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join("sh"); | ~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from("/sh"); | ~~~~~~~~~~~~~~~~~~~~ @@ -59,7 +59,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join(r#"sh"#); | ~~~~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from(r#"/sh"#); | ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.rs b/src/tools/clippy/tests/ui/let_underscore_lock.rs index ccac73be79e4d..28d8dd498319f 100644 --- a/src/tools/clippy/tests/ui/let_underscore_lock.rs +++ b/src/tools/clippy/tests/ui/let_underscore_lock.rs @@ -26,6 +26,7 @@ fn main() { let _ = p_rw; } +#[allow(let_underscore_lock)] fn uplifted() { // shouldn't lint std locks as they were uplifted as rustc's `let_underscore_lock` diff --git a/src/tools/clippy/tests/ui/manual_ok_or.stderr b/src/tools/clippy/tests/ui/manual_ok_or.stderr index b277d22e59b63..89df6cdbedbcc 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.stderr +++ b/src/tools/clippy/tests/ui/manual_ok_or.stderr @@ -17,7 +17,7 @@ error: called `map_or(Err(_), Ok)` on an `Option` value --> $DIR/manual_ok_or.rs:14:5 | LL | foo.map_or(Err("error"), Ok); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `foo.ok_or("error")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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)]` diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr index dc36a5ee7c692..3ce108b1ca81e 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr @@ -2,7 +2,7 @@ error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:6:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` | = note: `-D clippy::manual-saturating-arithmetic` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]` @@ -11,13 +11,13 @@ error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:7:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:8:13 | LL | let _ = 1u8.checked_add(1).unwrap_or(255); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u8.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u8.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:9:13 @@ -26,49 +26,49 @@ LL | let _ = 1u128 | _____________^ LL | | .checked_add(1) LL | | .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); - | |_______________________________________________________________________^ help: try using `saturating_add`: `1u128.saturating_add(1)` + | |_______________________________________________________________________^ help: consider using `saturating_add`: `1u128.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:14:13 | LL | let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_mul`: `1u32.saturating_mul(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_mul`: `1u32.saturating_mul(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:16:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:17:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:18:13 | LL | let _ = 1u8.checked_sub(1).unwrap_or(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u8.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u8.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:22:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:23:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:24:13 | LL | let _ = 1i8.checked_add(1).unwrap_or(127); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:25:13 @@ -77,25 +77,25 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_add(1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); - | |_______________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(1)` + | |_______________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:28:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:29:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:30:13 | LL | let _ = 1i8.checked_add(-1).unwrap_or(-128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:31:13 @@ -104,25 +104,25 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_add(-1) LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); - | |________________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(-1)` + | |________________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:38:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:39:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:40:13 | LL | let _ = 1i8.checked_sub(1).unwrap_or(-128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:41:13 @@ -131,25 +131,25 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_sub(1) LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); - | |________________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(1)` + | |________________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:44:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:45:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:46:13 | LL | let _ = 1i8.checked_sub(-1).unwrap_or(127); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:47:13 @@ -158,7 +158,7 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_sub(-1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); - | |_______________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(-1)` + | |_______________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(-1)` error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed index 08b155a1aeaf8..395eea69294dd 100644 --- a/src/tools/clippy/tests/ui/map_clone.fixed +++ b/src/tools/clippy/tests/ui/map_clone.fixed @@ -69,15 +69,48 @@ fn main() { //~^ ERROR: you are explicitly cloning with `.map()` let y = x.cloned(); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method let y = x.cloned(); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + 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 + let y = x.copied(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Option = Some(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // Testing with `Result` now. 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 let y = x.cloned(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + 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 + let y = x.copied(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Result = Ok(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // We ensure that no warning is emitted here because `useless_asref` is taking over. let x = Some(String::new()); diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs index 901d9b278b47f..82a103edf5a9c 100644 --- a/src/tools/clippy/tests/ui/map_clone.rs +++ b/src/tools/clippy/tests/ui/map_clone.rs @@ -69,15 +69,48 @@ fn main() { //~^ ERROR: you are explicitly cloning with `.map()` let y = x.map(Clone::clone); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method let y = x.map(String::clone); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + 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 + let y = x.map(|x| Clone::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Option = Some(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // Testing with `Result` now. 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()` - let y = x.map(|x| String::clone(x)); + //~| HELP: consider calling the dedicated `cloned` method + let y = x.map(|x| Clone::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + 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 + let y = x.map(|x| Clone::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Result = Ok(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // We ensure that no warning is emitted here because `useless_asref` is taking over. let x = Some(String::new()); diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr index 9d7e9317b58ce..2c86a67fab8d6 100644 --- a/src/tools/clippy/tests/ui/map_clone.stderr +++ b/src/tools/clippy/tests/ui/map_clone.stderr @@ -50,22 +50,46 @@ LL | let y = x.map(Clone::clone); | ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> $DIR/map_clone.rs:72:13 + --> $DIR/map_clone.rs:73:13 | LL | let y = x.map(String::clone); | ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> $DIR/map_clone.rs:78:13 + --> $DIR/map_clone.rs:79:13 | -LL | let y = x.map(|x| String::clone(x)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` +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()` - --> $DIR/map_clone.rs:80:13 + --> $DIR/map_clone.rs:82: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()` + --> $DIR/map_clone.rs:94:13 | LL | let y = x.map(|x| String::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` -error: aborting due to 11 previous errors +error: you are explicitly cloning with `.map()` + --> $DIR/map_clone.rs:97: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()` + --> $DIR/map_clone.rs:103: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()` + --> $DIR/map_clone.rs:106:13 + | +LL | let y = x.map(|x| Clone::clone(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 525a355f40355..3428ff4590602 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -13,7 +13,6 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { 42 => { - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm foo(); let mut a = 42 + [23].len() as i32; if true { @@ -32,6 +31,7 @@ fn match_same_arms() { a }, }; + //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm let _ = match 42 { 42 => foo(), @@ -146,13 +146,13 @@ fn match_same_arms() { empty!(0); }, 1 => { - //~^ ERROR: this match arm has an identical body to another arm empty!(0); }, x => { empty!(x); }, } + //~^^^^^^^ ERROR: this match arm has an identical body to another arm match_expr_like_matches_macro_priority(); } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 40b20c7e16d28..512ca7413a795 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -2,9 +2,9 @@ error: this match arm has an identical body to the `_` wildcard arm --> $DIR/match_same_arms2.rs:15:9 | LL | / 42 => { -LL | | LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; +LL | | if true { ... | LL | | a LL | | }, @@ -12,7 +12,7 @@ LL | | }, | = help: or try changing either arm body note: `_` wildcard arm here - --> $DIR/match_same_arms2.rs:25:9 + --> $DIR/match_same_arms2.rs:24:9 | LL | / _ => { LL | | foo(); @@ -122,7 +122,6 @@ LL | 1 => { | ^ help: try merging the arm patterns: `1 | 0` | _________| | | -LL | | LL | | empty!(0); LL | | }, | |_________^ diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed new file mode 100644 index 0000000000000..c970f2ba2814b --- /dev/null +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed @@ -0,0 +1,82 @@ +#![allow(unused)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] +#![feature(lang_items)] +#![no_std] + +use core::mem; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn replace_option_with_none() { + let mut an_option = Some(1); + let _ = an_option.take(); + let an_option = &mut Some(1); + let _ = an_option.take(); +} + +fn replace_with_default() { + let mut refstr = "hello"; + let _ = core::mem::take(&mut refstr); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = core::mem::take(&mut slice); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = mem::replace(&mut pint, 0); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); + dont_lint_primitive(); +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> core::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> core::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: u8, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1), val: 12 }; + + // replace option with none + let _ = f.0.take(); + let _ = (*f).take(); + let _ = b.opt.take(); + // 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 new file mode 100644 index 0000000000000..673d5c7b4f45a --- /dev/null +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.rs @@ -0,0 +1,82 @@ +#![allow(unused)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] +#![feature(lang_items)] +#![no_std] + +use core::mem; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn replace_option_with_none() { + let mut an_option = Some(1); + let _ = mem::replace(&mut an_option, None); + let an_option = &mut Some(1); + let _ = mem::replace(an_option, None); +} + +fn replace_with_default() { + let mut refstr = "hello"; + let _ = mem::replace(&mut refstr, ""); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = mem::replace(&mut slice, &[]); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = mem::replace(&mut pint, 0); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); + dont_lint_primitive(); +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> core::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> core::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: u8, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1), val: 12 }; + + // replace option with none + let _ = mem::replace(&mut f.0, None); + let _ = mem::replace(&mut *f, None); + let _ = mem::replace(&mut b.opt, 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 new file mode 100644 index 0000000000000..744fb5a15876e --- /dev/null +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr @@ -0,0 +1,50 @@ +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:24:13 + | +LL | let _ = mem::replace(&mut an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` + | + = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` + +error: replacing an `Option` with `None` + --> $DIR/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` + --> $DIR/mem_replace_no_std.rs:31:13 + | +LL | let _ = mem::replace(&mut refstr, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)` + | + = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = 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` + --> $DIR/mem_replace_no_std.rs:34:13 + | +LL | let _ = mem::replace(&mut slice, &[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:77:13 + | +LL | let _ = mem::replace(&mut f.0, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:78:13 + | +LL | let _ = mem::replace(&mut *f, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:79:13 + | +LL | let _ = mem::replace(&mut b.opt, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/modulo_one.rs b/src/tools/clippy/tests/ui/modulo_one.rs index c1dbe9d9a8787..c332a15f15778 100644 --- a/src/tools/clippy/tests/ui/modulo_one.rs +++ b/src/tools/clippy/tests/ui/modulo_one.rs @@ -33,7 +33,6 @@ fn main() { INT_MIN % NEG_ONE; //~^ ERROR: this operation will panic at runtime //~| ERROR: any number modulo -1 will panic/overflow or result in 0 - // ONLY caught by rustc + // Not caught by lint, we don't look into static items, even if entirely immutable. INT_MIN % STATIC_NEG_ONE; - //~^ ERROR: this operation will panic at runtime } diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr index cc211ab6cd345..06bbb0f5d9a80 100644 --- a/src/tools/clippy/tests/ui/modulo_one.stderr +++ b/src/tools/clippy/tests/ui/modulo_one.stderr @@ -12,12 +12,6 @@ error: this operation will panic at runtime LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow -error: this operation will panic at runtime - --> $DIR/modulo_one.rs:37:5 - | -LL | INT_MIN % STATIC_NEG_ONE; - | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow - error: any number modulo 1 will be 0 --> $DIR/modulo_one.rs:8:5 | @@ -57,5 +51,5 @@ error: any number modulo -1 will panic/overflow or result in 0 LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index 777b1e52c2da6..dabeda72f0c8c 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -181,6 +181,8 @@ fn main() { //~^ ERROR: binding to `_` prefixed variable with no side-effect let _cat = [2, 4, 6, 8][2]; //~^ ERROR: binding to `_` prefixed variable with no side-effect + let _issue_12166 = 42; + let underscore_variable_above_can_be_used_dont_lint = _issue_12166; #[allow(clippy::no_effect)] 0; diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index f5ba234b4cbf6..8140ba1feee9c 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -152,31 +152,31 @@ LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:175:5 + --> $DIR/no_effect.rs:175:9 | LL | let _unused = 1; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:178:5 + --> $DIR/no_effect.rs:178:9 | LL | let _penguin = || println!("Some helpful closure"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:180:5 + --> $DIR/no_effect.rs:180:9 | LL | let _duck = Struct { field: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:182:5 + --> $DIR/no_effect.rs:182:9 | LL | let _cat = [2, 4, 6, 8][2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 29 previous errors diff --git a/src/tools/clippy/tests/ui/open_options.rs b/src/tools/clippy/tests/ui/open_options.rs index 0cdc5bf2bb592..4acb3780df43e 100644 --- a/src/tools/clippy/tests/ui/open_options.rs +++ b/src/tools/clippy/tests/ui/open_options.rs @@ -1,7 +1,18 @@ +#![allow(unused_must_use)] +#![warn(clippy::nonsensical_open_options)] + use std::fs::OpenOptions; -#[allow(unused_must_use)] -#[warn(clippy::nonsensical_open_options)] +trait OpenOptionsExt { + fn truncate_write(&mut self, opt: bool) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn truncate_write(&mut self, opt: bool) -> &mut Self { + self.truncate(opt).write(opt) + } +} + fn main() { OpenOptions::new().read(true).truncate(true).open("foo.txt"); //~^ ERROR: file opened with `truncate` and `read` @@ -11,12 +22,31 @@ fn main() { OpenOptions::new().read(true).read(false).open("foo.txt"); //~^ ERROR: the method `read` is called more than once - OpenOptions::new().create(true).create(false).open("foo.txt"); - //~^ ERROR: the method `create` is called more than once + 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 + .open("foo.txt"); OpenOptions::new().write(true).write(false).open("foo.txt"); //~^ ERROR: the method `write` is called more than once OpenOptions::new().append(true).append(false).open("foo.txt"); //~^ ERROR: the method `append` is called more than once OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); //~^ ERROR: the method `truncate` is called more than once + + std::fs::File::options().read(true).read(false).open("foo.txt"); + //~^ ERROR: the method `read` is called more than once + + let mut options = std::fs::OpenOptions::new(); + options.read(true); + options.read(false); + // Possible future improvement: recognize open options method call chains across statements. + options.open("foo.txt"); + + let mut options = std::fs::OpenOptions::new(); + options.truncate(true); + options.create(true).open("foo.txt"); + + OpenOptions::new().create(true).truncate_write(true).open("foo.txt"); } diff --git a/src/tools/clippy/tests/ui/open_options.stderr b/src/tools/clippy/tests/ui/open_options.stderr index 7ac826f52fa9d..4f84d1d09f984 100644 --- a/src/tools/clippy/tests/ui/open_options.stderr +++ b/src/tools/clippy/tests/ui/open_options.stderr @@ -1,5 +1,5 @@ error: file opened with `truncate` and `read` - --> $DIR/open_options.rs:6:5 + --> $DIR/open_options.rs:17:5 | LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,40 +8,46 @@ LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); = help: to override `-D warnings` add `#[allow(clippy::nonsensical_open_options)]` error: file opened with `append` and `truncate` - --> $DIR/open_options.rs:9:5 + --> $DIR/open_options.rs:20:5 | LL | OpenOptions::new().append(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method `read` is called more than once - --> $DIR/open_options.rs:12:5 + --> $DIR/open_options.rs:23:35 | LL | OpenOptions::new().read(true).read(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: the method `create` is called more than once - --> $DIR/open_options.rs:14:5 + --> $DIR/open_options.rs:28:10 | -LL | OpenOptions::new().create(true).create(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | .create(false) + | ^^^^^^^^^^^^^ error: the method `write` is called more than once - --> $DIR/open_options.rs:16:5 + --> $DIR/open_options.rs:31:36 | LL | OpenOptions::new().write(true).write(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: the method `append` is called more than once - --> $DIR/open_options.rs:18:5 + --> $DIR/open_options.rs:33:37 | LL | OpenOptions::new().append(true).append(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: the method `truncate` is called more than once - --> $DIR/open_options.rs:20:5 + --> $DIR/open_options.rs:35:39 | LL | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ + +error: the method `read` is called more than once + --> $DIR/open_options.rs:38:41 + | +LL | std::fs::File::options().read(true).read(false).open("foo.txt"); + | ^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/open_options_fixable.fixed b/src/tools/clippy/tests/ui/open_options_fixable.fixed new file mode 100644 index 0000000000000..90a129a9bdffd --- /dev/null +++ b/src/tools/clippy/tests/ui/open_options_fixable.fixed @@ -0,0 +1,7 @@ +use std::fs::OpenOptions; +#[allow(unused_must_use)] +#[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 +} diff --git a/src/tools/clippy/tests/ui/open_options_fixable.rs b/src/tools/clippy/tests/ui/open_options_fixable.rs new file mode 100644 index 0000000000000..3a9e522ba1507 --- /dev/null +++ b/src/tools/clippy/tests/ui/open_options_fixable.rs @@ -0,0 +1,7 @@ +use std::fs::OpenOptions; +#[allow(unused_must_use)] +#[warn(clippy::suspicious_open_options)] +fn main() { + OpenOptions::new().create(true).open("foo.txt"); + //~^ ERROR: file opened with `create`, but `truncate` behavior not defined +} diff --git a/src/tools/clippy/tests/ui/open_options_fixable.stderr b/src/tools/clippy/tests/ui/open_options_fixable.stderr new file mode 100644 index 0000000000000..e327661713bfb --- /dev/null +++ b/src/tools/clippy/tests/ui/open_options_fixable.stderr @@ -0,0 +1,14 @@ +error: file opened with `create`, but `truncate` behavior not defined + --> $DIR/open_options_fixable.rs:5:24 + | +LL | OpenOptions::new().create(true).open("foo.txt"); + | ^^^^^^^^^^^^- help: add: `.truncate(true)` + | + = help: if you intend to overwrite an existing file entirely, call `.truncate(true)` + = help: if you instead know that you may want to keep some parts of the old file, call `.truncate(false)` + = help: alternatively, use `.append(true)` to append to the file instead of overwriting it + = note: `-D clippy::suspicious-open-options` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_open_options)]` + +error: aborting due to 1 previous error + 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 9d173e409abcc..036b8c749e417 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr @@ -2,7 +2,7 @@ error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:11:13 | LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.clone().as_deref()` | = note: `-D clippy::option-as-ref-deref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_deref)]` @@ -15,103 +15,103 @@ LL | let _ = opt.clone() LL | | .as_ref().map( LL | | Deref::deref LL | | ) - | |_________^ help: try using as_deref instead: `opt.clone().as_deref()` + | |_________^ help: consider using as_deref: `opt.clone().as_deref()` error: called `.as_mut().map(DerefMut::deref_mut)` on an `Option` value --> $DIR/option_as_ref_deref.rs:20:13 | LL | let _ = opt.as_mut().map(DerefMut::deref_mut); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:22:13 | LL | let _ = opt.as_ref().map(String::as_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_ref().map(|x| x.as_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:23:13 | LL | let _ = opt.as_ref().map(|x| x.as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(String::as_mut_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:24:13 | LL | let _ = opt.as_mut().map(String::as_mut_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_mut().map(|x| x.as_mut_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:25:13 | LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(CString::as_c_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:26:13 | LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 --> $DIR/option_as_ref_deref.rs:27:13 | LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(OsString::new()).as_deref()` error: called `.as_ref().map(PathBuf::as_path)` on an `Option` value --> $DIR/option_as_ref_deref.rs:28:13 | LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(PathBuf::new()).as_deref()` error: called `.as_ref().map(Vec::as_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:29:13 | LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(Vec::<()>::new()).as_deref()` error: called `.as_mut().map(Vec::as_mut_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:30:13 | LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `Some(Vec::<()>::new()).as_deref_mut()` error: called `.as_ref().map(|x| x.deref())` on an `Option` value --> $DIR/option_as_ref_deref.rs:32:13 | LL | let _ = opt.as_ref().map(|x| x.deref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(|x| x.deref_mut())` on an `Option` value --> $DIR/option_as_ref_deref.rs:33:13 | LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.clone().as_deref_mut()` error: called `.as_ref().map(|x| &**x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:40:13 | LL | let _ = opt.as_ref().map(|x| &**x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(|x| &mut **x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:41:13 | LL | let _ = opt.as_mut().map(|x| &mut **x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(std::ops::Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:44:13 | LL | let _ = opt.as_ref().map(std::ops::Deref::deref); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:56:13 | LL | let _ = opt.as_ref().map(String::as_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: aborting due to 18 previous errors 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 index a193e3c4c49d3..381601cb6b3aa 100644 --- a/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr @@ -2,7 +2,7 @@ error: called `map_or(Err(_), Ok)` on an `Option` value --> $DIR/option_map_or_err_ok.rs:5:13 | LL | let _ = x.map_or(Err("a"), Ok); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `x.ok_or("a")` + | ^^^^^^^^^^^^^^^^^^^^^^ 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)]` 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 f2cfc3f9a2815..d58ff83c3da27 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr @@ -2,7 +2,7 @@ error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:10:26 | LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `map`: `opt.map(|x| x + 1)` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_map_or_none)]` @@ -14,13 +14,13 @@ LL | let _: Option = opt.map_or(None, |x| { | __________________________^ LL | | Some(x + 1) LL | | }); - | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` + | |_________________________^ help: consider using `map`: `opt.map(|x| x + 1)` error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:17:26 | LL | let _: Option = opt.map_or(None, bar); - | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `and_then`: `opt.and_then(bar)` error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:18:26 @@ -33,7 +33,7 @@ LL | | Some(offset + height) LL | | }); | |______^ | -help: try using `and_then` instead +help: consider using `and_then` | LL ~ let _: Option = opt.and_then(|x| { LL + let offset = 0; @@ -46,7 +46,7 @@ error: called `map_or(None, Some)` on a `Result` value --> $DIR/option_map_or_none.rs:25:26 | LL | let _: Option = r.map_or(None, Some); - | ^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `r.ok()` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `r.ok()` | = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed new file mode 100644 index 0000000000000..97c8c394c03d4 --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::ptr_eq)] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = core::ptr::eq(a, b); + let _ = core::ptr::eq(a, b); + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs new file mode 100644 index 0000000000000..a7ba9b4d81746 --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs @@ -0,0 +1,49 @@ +#![warn(clippy::ptr_eq)] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = a as *const _ as usize == b as *const _ as usize; + let _ = a as *const _ == b as *const _; + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr new file mode 100644 index 0000000000000..3e289f5be613e --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr @@ -0,0 +1,17 @@ +error: use `core::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq_no_std.rs:31:13 + | +LL | let _ = a as *const _ as usize == b as *const _ as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` + | + = note: `-D clippy::ptr-eq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` + +error: use `core::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq_no_std.rs:32:13 + | +LL | let _ = a as *const _ == b as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` + +error: aborting due to 2 previous errors + 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 76b9b98185119..fd5a88a37a66c 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs @@ -55,14 +55,6 @@ fn test() -> io::Result<()> { let mut buf = [0u8; 100]; f.read(&mut buf)?; - // should not lint - let mut empty = vec![]; - let mut data7 = vec![]; - f.read(&mut empty); - - // should not lint - f.read(&mut data7); - // should not lint let mut data8 = Vec::new(); data8.resize(100, 0); @@ -75,6 +67,27 @@ fn test() -> io::Result<()> { Ok(()) } +fn test_nested() -> io::Result<()> { + let cap = 1000; + let mut f = File::open("foo.txt").unwrap(); + + // Issue #9274 + // Should not lint + let mut v = Vec::new(); + { + v.resize(10, 0); + f.read(&mut v)?; + } + + let mut v = Vec::new(); + { + f.read(&mut v)?; + //~^ ERROR: reading zero byte data to `Vec` + } + + Ok(()) +} + async fn test_futures(r: &mut R) { // should lint let mut data = Vec::new(); 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 523ecb2948df3..e85aa051c34bc 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr @@ -2,7 +2,7 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:21:5 | LL | f.read_exact(&mut data).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)` | = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]` @@ -11,19 +11,19 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:27:5 | LL | f.read_exact(&mut data2)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)` error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:32:5 | LL | f.read_exact(&mut data3)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:37:5 + --> $DIR/read_zero_byte_vec.rs:37:13 | LL | let _ = f.read(&mut data4)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:43:9 @@ -38,28 +38,34 @@ LL | f.read(&mut data6) | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:81:5 + --> $DIR/read_zero_byte_vec.rs:84:9 + | +LL | f.read(&mut v)?; + | ^^^^^^^^^^^^^^ + +error: reading zero byte data to `Vec` + --> $DIR/read_zero_byte_vec.rs:94:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:86:5 + --> $DIR/read_zero_byte_vec.rs:99:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:93:5 + --> $DIR/read_zero_byte_vec.rs:106:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:98:5 + --> $DIR/read_zero_byte_vec.rs:111:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors 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 3d6bfef48ecab..201868f09efa6 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 @@ -2,7 +2,7 @@ error: called `map_or(None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:5:13 | LL | let _ = opt.map_or(None, Some); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` | = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` @@ -11,13 +11,13 @@ error: called `map_or_else(|_| None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:7:13 | LL | let _ = opt.map_or_else(|_| None, Some); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` error: called `map_or_else(|_| None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:10:13 | LL | let _ = opt.map_or_else(|_| { None }, Some); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr index f519be463695b..f569aab64900a 100644 --- a/src/tools/clippy/tests/ui/same_item_push.stderr +++ b/src/tools/clippy/tests/ui/same_item_push.stderr @@ -4,7 +4,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) = note: `-D clippy::same-item-push` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::same_item_push)]` @@ -14,7 +14,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:36:9 @@ -22,7 +22,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(13); | ^^^ | - = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) + = help: consider using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:42:9 @@ -30,7 +30,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(VALUE); | ^^^ | - = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) + = help: consider using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:49:9 @@ -38,7 +38,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs index 1c166a19b0ad7..26b1a299ba1cf 100644 --- a/src/tools/clippy/tests/ui/same_name_method.rs +++ b/src/tools/clippy/tests/ui/same_name_method.rs @@ -74,6 +74,7 @@ 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 } 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 3c5c4a53ad1f6..82f5ef6a9e827 100644 --- a/src/tools/clippy/tests/ui/same_name_method.stderr +++ b/src/tools/clippy/tests/ui/same_name_method.stderr @@ -56,10 +56,22 @@ LL | fn foo() {} | ^^^^^^^^^^^ | note: existing `foo` defined here - --> $DIR/same_name_method.rs:79:9 + --> $DIR/same_name_method.rs:80:9 | LL | impl T1 for S {} | ^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: method's name is the same as an existing method in a trait + --> $DIR/same_name_method.rs:75:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | +note: existing `foo` defined here + --> $DIR/same_name_method.rs:82:9 + | +LL | impl T2 for S {} + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr index a7a47447f61de..9dec8c9caf274 100644 --- a/src/tools/clippy/tests/ui/search_is_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -40,7 +40,7 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:42:20 | LL | let _ = (0..1).find(some_closure).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(some_closure)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:52:13 @@ -82,7 +82,7 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:79:13 | LL | let _ = (0..1).find(some_closure).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(some_closure)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(some_closure)` error: aborting due to 8 previous errors 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 f33b0430912a1..107f59a97d2f3 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 @@ -2,7 +2,7 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:9:13 | LL | let _ = v.iter().find(|&x| *x < 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` @@ -11,43 +11,43 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:10:13 | LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(|x| **y == x)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:11:13 | LL | let _ = (0..1).find(|x| *x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(|x| x == 0)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:12:13 | LL | let _ = v.iter().find(|x| **x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 0)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:13:13 | LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:14:13 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:15:13 | LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:16:13 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:17:13 @@ -56,91 +56,91 @@ LL | let _ = (1..3) | _____________^ LL | | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) LL | | .is_none(); - | |__________________^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` + | |__________________^ 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` --> $DIR/search_is_some_fixable_none.rs:22:13 | LL | let _ = v.iter().position(|&x| x < 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after searching an `Iterator` with `rposition` --> $DIR/search_is_some_fixable_none.rs:25:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:31:13 | LL | let _ = "hello world".find("world").is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains("world")` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:32:13 | LL | let _ = "hello world".find(&s2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains(&s2)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:33:13 | LL | let _ = "hello world".find(&s2[2..]).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:35:13 | LL | let _ = s1.find("world").is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains("world")` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:36:13 | LL | let _ = s1.find(&s2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains(&s2)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:37:13 | LL | let _ = s1.find(&s2[2..]).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:39:13 | LL | let _ = s1[2..].find("world").is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains("world")` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:40:13 | LL | let _ = s1[2..].find(&s2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains(&s2)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:41:13 | LL | let _ = s1[2..].find(&s2[2..]).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains(&s2[2..])` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:57:25 | LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!filter_hand.iter().any(|cc| c == &cc)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:73:30 | LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!filter_hand.iter().any(|cc| c == cc)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:84:17 | LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:87:17 @@ -152,7 +152,7 @@ LL | | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) LL | | .is_none(); | |______________________^ | -help: use `!_.any()` instead +help: consider using | LL ~ let _ = !vfoo LL ~ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); @@ -162,49 +162,49 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:95:17 | LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|a| a[0] == 42)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|a| a[0] == 42)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:101:17 | LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:119:17 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:120:17 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:123:17 | LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:124:17 | LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x: &u32| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:127:17 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:129:17 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x: &u32| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:149:17 @@ -216,7 +216,7 @@ LL | | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == LL | | .is_none(); | |______________________^ | -help: use `!_.any()` instead +help: consider using | LL ~ let _ = !vfoo LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); @@ -226,61 +226,61 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:165:17 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:170:17 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|x| (**x)[0] == 9)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:183:17 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:187:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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` --> $DIR/search_is_some_fixable_none.rs:188:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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` --> $DIR/search_is_some_fixable_none.rs:207:17 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| s[0].is_empty())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| s[0].is_empty())` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:208:17 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| test_string_1(&s[0]))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| test_string_1(&s[0]))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:217:17 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| fp.field.is_power_of_two())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| fp.field.is_power_of_two())` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:218:17 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_1(fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_1(fp.field))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:219:17 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` error: aborting due to 43 previous errors 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 e878e62de07f3..e706ce646923d 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 @@ -2,7 +2,7 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:9:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` @@ -11,43 +11,43 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:10:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:11:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:12:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:13:20 | LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 1 || x == 3 || x == 5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 1 || x == 3 || x == 5)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:14:20 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| [1, 2, 3].contains(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:15:20 | LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0 || [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 0 || [1, 2, 3].contains(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:16:20 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| [1, 2, 3].contains(&x) || x == 0)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:18:10 @@ -55,91 +55,91 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) | __________^ LL | | .is_some(); - | |__________________^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` + | |__________________^ 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` --> $DIR/search_is_some_fixable_some.rs:22:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with `rposition` --> $DIR/search_is_some_fixable_some.rs:25:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|&x| x < 0)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:30:27 | LL | let _ = "hello world".find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:31:27 | LL | let _ = "hello world".find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:32:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:34:16 | LL | let _ = s1.find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:35:16 | LL | let _ = s1.find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:36:16 | LL | let _ = s1.find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:38:21 | LL | let _ = s1[2..].find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:39:21 | LL | let _ = s1[2..].find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:40:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:56:44 | LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == &cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|cc| c == &cc)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:72:49 | LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|cc| c == cc)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:83:29 | LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.foo == 1 && v.bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.foo == 1 && v.bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:88:14 @@ -147,55 +147,55 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) | ______________^ LL | | .is_some(); - | |______________________^ help: use `any()` instead: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)` + | |______________________^ help: consider using: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:94:29 | LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|a| a[0] == 42)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|a| a[0] == 42)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:100:29 | LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|sub| sub[1..4].len() == 3)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:118:30 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|ppp_x: &&u32| please(ppp_x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:119:50 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s.len() == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:122:26 | LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:123:26 | LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:126:26 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:128:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:150:14 @@ -203,91 +203,91 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) | ______________^ LL | | .is_some(); - | |______________________^ help: use `any()` instead: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)` + | |______________________^ 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` --> $DIR/search_is_some_fixable_some.rs:164:29 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.inner[0].bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.inner[0].bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:169:29 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| (**x)[0] == 9)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:182:29 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.by_ref(&v.bar))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.by_ref(&v.bar))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:186:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:187:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:206:26 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s[0].is_empty())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s[0].is_empty())` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:207:26 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| test_string_1(&s[0]))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| test_string_1(&s[0]))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:216:26 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| fp.field.is_power_of_two())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| fp.field.is_power_of_two())` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:217:26 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_1(fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_1(fp.field))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:218:26 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_2(*fp.field))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:233:18 | LL | v.iter().find(|x: &&u32| func(x)).is_some() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| func(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| func(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:242:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_impl(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref_impl(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_impl(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:245:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_dyn(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref_dyn(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_dyn(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:248:26 | LL | let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` error: aborting due to 47 previous errors 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 15cc8d54faab3..8859a68320f00 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 @@ -80,6 +80,7 @@ fn main() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -104,6 +105,7 @@ fn msrv_1_54() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -124,6 +126,7 @@ fn msrv_1_55() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .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 197225ffbd5c9..7b72efb34ff82 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 @@ -80,6 +80,7 @@ fn main() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -104,6 +105,7 @@ fn msrv_1_54() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -124,6 +126,7 @@ fn msrv_1_55() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .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 05c11cf7f8c61..b6b0d2effa815 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 @@ -14,7 +14,7 @@ LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` error: used `seek` to go to the start of the stream - --> $DIR/seek_to_start_instead_of_rewind.rs:133:7 + --> $DIR/seek_to_start_instead_of_rewind.rs:136:7 | LL | f.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` 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 bbcc0de27d115..cdfa5d9cc7804 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed @@ -1,6 +1,11 @@ +//@aux-build:proc_macro_attr.rs + #![warn(clippy::semicolon_if_nothing_returned)] #![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)] +#[macro_use] +extern crate proc_macro_attr; + fn get_unit() {} // the functions below trigger the lint @@ -120,3 +125,32 @@ fn let_else_stmts() { return; }; } + +mod issue12123 { + #[rustfmt::skip] + mod this_triggers { + #[fake_main] + async fn main() { + + } + } + + mod and_this { + #[fake_main] + async fn main() { + println!("hello"); + } + } + + #[rustfmt::skip] + mod maybe_this { + /** */ #[fake_main] + async fn main() { + } + } + + mod but_this_does_not { + #[fake_main] + async fn main() {} + } +} 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 fdc9c0c33f5a3..315b7e4f38399 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs @@ -1,6 +1,11 @@ +//@aux-build:proc_macro_attr.rs + #![warn(clippy::semicolon_if_nothing_returned)] #![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)] +#[macro_use] +extern crate proc_macro_attr; + fn get_unit() {} // the functions below trigger the lint @@ -120,3 +125,32 @@ fn let_else_stmts() { return; }; } + +mod issue12123 { + #[rustfmt::skip] + mod this_triggers { + #[fake_main] + async fn main() { + + } + } + + mod and_this { + #[fake_main] + async fn main() { + println!("hello"); + } + } + + #[rustfmt::skip] + mod maybe_this { + /** */ #[fake_main] + async fn main() { + } + } + + mod but_this_does_not { + #[fake_main] + async fn main() {} + } +} 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 66373a13c5690..09c4d12f216c5 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,5 +1,5 @@ error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:8:5 + --> $DIR/semicolon_if_nothing_returned.rs:13:5 | LL | println!("Hello") | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` @@ -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 - --> $DIR/semicolon_if_nothing_returned.rs:12:5 + --> $DIR/semicolon_if_nothing_returned.rs:17:5 | LL | get_unit() | ^^^^^^^^^^ help: add a `;` here: `get_unit();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:17:5 + --> $DIR/semicolon_if_nothing_returned.rs:22:5 | LL | y = x + 1 | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:23:9 + --> $DIR/semicolon_if_nothing_returned.rs:28:9 | LL | hello() | ^^^^^^^ help: add a `;` here: `hello();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:34:9 + --> $DIR/semicolon_if_nothing_returned.rs:39: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/single_call_fn.rs b/src/tools/clippy/tests/ui/single_call_fn.rs index 3cc8061647dff..c20214fecccea 100644 --- a/src/tools/clippy/tests/ui/single_call_fn.rs +++ b/src/tools/clippy/tests/ui/single_call_fn.rs @@ -69,6 +69,17 @@ fn e() { #[test] fn k() {} +mod issue12182 { + #[allow(clippy::single_call_fn)] + fn print_foo(text: &str) { + println!("{text}"); + } + + fn use_print_foo() { + print_foo("foo"); + } +} + #[test] fn l() { k(); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index 781ab316d9de3..664d6b5a1e9b0 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -2,7 +2,7 @@ error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:7:13 | LL | x.split("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` | = note: `-D clippy::single-char-pattern` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` @@ -11,235 +11,235 @@ error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:13:13 | LL | x.split("ß"); - | ^^^ help: try using a `char` instead: `'ß'` + | ^^^ help: consider using a `char`: `'ß'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:14:13 | LL | x.split("ℝ"); - | ^^^ help: try using a `char` instead: `'ℝ'` + | ^^^ help: consider using a `char`: `'ℝ'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:15:13 | LL | x.split("💣"); - | ^^^^ help: try using a `char` instead: `'💣'` + | ^^^^ help: consider using a `char`: `'💣'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:18:23 | LL | x.split_inclusive("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:19:16 | LL | x.contains("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:20:19 | LL | x.starts_with("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:21:17 | LL | x.ends_with("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:22:12 | LL | x.find("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:23:13 | LL | x.rfind("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:24:14 | LL | x.rsplit("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:25:24 | LL | x.split_terminator("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:26:25 | LL | x.rsplit_terminator("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:27:17 | LL | x.splitn(2, "x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:28:18 | LL | x.rsplitn(2, "x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:29:18 | LL | x.split_once("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:30:19 | LL | x.rsplit_once("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:31:15 | LL | x.matches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:32:16 | LL | x.rmatches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:33:21 | LL | x.match_indices("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:34:22 | LL | x.rmatch_indices("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:35:26 | LL | x.trim_start_matches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:36:24 | LL | x.trim_end_matches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:37:20 | LL | x.strip_prefix("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:38:20 | LL | x.strip_suffix("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:39:15 | LL | x.replace("x", "y"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:40:16 | LL | x.replacen("x", "y", 3); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:42:13 | LL | x.split("\n"); - | ^^^^ help: try using a `char` instead: `'\n'` + | ^^^^ help: consider using a `char`: `'\n'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:43:13 | LL | x.split("'"); - | ^^^ help: try using a `char` instead: `'\''` + | ^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:44:13 | LL | x.split("\'"); - | ^^^^ help: try using a `char` instead: `'\''` + | ^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:46:13 | LL | x.split("\""); - | ^^^^ help: try using a `char` instead: `'"'` + | ^^^^ help: consider using a `char`: `'"'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:51:31 | LL | x.replace(';', ",").split(","); // issue #2978 - | ^^^ help: try using a `char` instead: `','` + | ^^^ help: consider using a `char`: `','` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:52:19 | LL | x.starts_with("\x03"); // issue #2996 - | ^^^^^^ help: try using a `char` instead: `'\x03'` + | ^^^^^^ help: consider using a `char`: `'\x03'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:59:13 | LL | x.split(r"a"); - | ^^^^ help: try using a `char` instead: `'a'` + | ^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:60:13 | LL | x.split(r#"a"#); - | ^^^^^^ help: try using a `char` instead: `'a'` + | ^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:61:13 | LL | x.split(r###"a"###); - | ^^^^^^^^^^ help: try using a `char` instead: `'a'` + | ^^^^^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:62:13 | LL | x.split(r###"'"###); - | ^^^^^^^^^^ help: try using a `char` instead: `'\''` + | ^^^^^^^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:63:13 | LL | x.split(r###"#"###); - | ^^^^^^^^^^ help: try using a `char` instead: `'#'` + | ^^^^^^^^^^ help: consider using a `char`: `'#'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:65:13 | LL | x.split(r#"\"#); - | ^^^^^^ help: try using a `char` instead: `'\\'` + | ^^^^^^ help: consider using a `char`: `'\\'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:66:13 | LL | x.split(r"\"); - | ^^^^ help: try using a `char` instead: `'\\'` + | ^^^^ help: consider using a `char`: `'\\'` error: aborting due to 40 previous errors 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 4fca29698e06b..7e2663d734f63 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -118,4 +118,33 @@ fn bad_trait_object(arg0: &(dyn Any + Send)) { unimplemented!(); } -fn main() {} +trait Proj { + type S; +} + +impl Proj for () { + type S = (); +} + +impl Proj for i32 { + type S = i32; +} + +trait Base { + fn is_base(&self); +} + +trait Derived: Base + Base<()> { + fn is_derived(&self); +} + +fn f(obj: &dyn Derived

) { + obj.is_derived(); + Base::::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let _x: fn(_) = f::<()>; + let _x: fn(_) = f::; +} 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 f67c8e35ed4cf..fede1671a4363 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -118,4 +118,33 @@ fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { unimplemented!(); } -fn main() {} +trait Proj { + type S; +} + +impl Proj for () { + type S = (); +} + +impl Proj for i32 { + type S = i32; +} + +trait Base { + fn is_base(&self); +} + +trait Derived: Base + Base<()> { + fn is_derived(&self); +} + +fn f(obj: &dyn Derived

) { + obj.is_derived(); + Base::::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let _x: fn(_) = f::<()>; + let _x: fn(_) = f::; +} diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index 32f6027e99111..1796ccaf28e1a 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -102,19 +102,6 @@ fn crosspointer() { } } -#[warn(clippy::transmute_int_to_char)] -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` - let _: char = unsafe { std::mem::transmute(0_i32) }; - //~^ ERROR: transmute from a `i32` to a `char` - - // These shouldn't warn - const _: char = unsafe { std::mem::transmute(0_u32) }; - const _: char = unsafe { std::mem::transmute(0_i32) }; -} - #[warn(clippy::transmute_int_to_bool)] fn int_to_bool() { let _: bool = unsafe { std::mem::transmute(0_u8) }; diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index cdc733b54a9b2..df32d478cbf40 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -88,23 +88,8 @@ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:107:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` - | - = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` - -error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:110:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` - error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:120:28 + --> $DIR/transmute.rs:107:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -113,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:128:31 + --> $DIR/transmute.rs:115:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` @@ -122,25 +107,25 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:131:31 + --> $DIR/transmute.rs:118:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> $DIR/transmute.rs:133:31 + --> $DIR/transmute.rs:120:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> $DIR/transmute.rs:135:31 + --> $DIR/transmute.rs:122:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u8` to a `[u8; 1]` - --> $DIR/transmute.rs:156:30 + --> $DIR/transmute.rs:143:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -149,85 +134,85 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> $DIR/transmute.rs:159:30 + --> $DIR/transmute.rs:146: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]` - --> $DIR/transmute.rs:161:31 + --> $DIR/transmute.rs:148: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]` - --> $DIR/transmute.rs:163:30 + --> $DIR/transmute.rs:150: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]` - --> $DIR/transmute.rs:165:30 + --> $DIR/transmute.rs:152: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]` - --> $DIR/transmute.rs:167:31 + --> $DIR/transmute.rs:154:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> $DIR/transmute.rs:169:30 + --> $DIR/transmute.rs:156: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]` - --> $DIR/transmute.rs:171:30 + --> $DIR/transmute.rs:158:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> $DIR/transmute.rs:177:30 + --> $DIR/transmute.rs:164: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]` - --> $DIR/transmute.rs:179:30 + --> $DIR/transmute.rs:166: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]` - --> $DIR/transmute.rs:181:31 + --> $DIR/transmute.rs:168: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]` - --> $DIR/transmute.rs:183:30 + --> $DIR/transmute.rs:170: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]` - --> $DIR/transmute.rs:185:30 + --> $DIR/transmute.rs:172: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]` - --> $DIR/transmute.rs:187:31 + --> $DIR/transmute.rs:174:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:198:28 + --> $DIR/transmute.rs:185:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -236,16 +221,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:201:32 + --> $DIR/transmute.rs:188: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` - --> $DIR/transmute.rs:203:30 + --> $DIR/transmute.rs:190:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 38 previous errors +error: aborting due to 36 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed new file mode 100644 index 0000000000000..1708011817541 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::transmute_int_to_char)] + +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` + let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { std::mem::transmute(0_u32) }; + const _: char = unsafe { std::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs new file mode 100644 index 0000000000000..5846a97e88abf --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs @@ -0,0 +1,15 @@ +#![warn(clippy::transmute_int_to_char)] + +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` + let _: char = unsafe { std::mem::transmute(0_i32) }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { std::mem::transmute(0_u32) }; + const _: char = unsafe { std::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr new file mode 100644 index 0000000000000..2297f5b4f8bf2 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr @@ -0,0 +1,17 @@ +error: transmute from a `u32` to a `char` + --> $DIR/transmute_int_to_char.rs:4:28 + | +LL | let _: char = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` + | + = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute_int_to_char.rs:7:28 + | +LL | let _: char = unsafe { std::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` + +error: aborting due to 2 previous errors + 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 new file mode 100644 index 0000000000000..9ae4e11fb56e7 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed @@ -0,0 +1,27 @@ +#![no_std] +#![feature(lang_items)] +#![warn(clippy::transmute_int_to_char)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +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` + let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { core::mem::transmute(0_u32) }; + const _: char = unsafe { core::mem::transmute(0_i32) }; +} + +fn main() {} 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 new file mode 100644 index 0000000000000..9a2afd5bd2fd6 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs @@ -0,0 +1,27 @@ +#![no_std] +#![feature(lang_items)] +#![warn(clippy::transmute_int_to_char)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +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` + let _: char = unsafe { core::mem::transmute(0_i32) }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { core::mem::transmute(0_u32) }; + const _: char = unsafe { core::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr new file mode 100644 index 0000000000000..aace6968696da --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr @@ -0,0 +1,17 @@ +error: transmute from a `u32` to a `char` + --> $DIR/transmute_int_to_char_no_std.rs:16:28 + | +LL | let _: char = unsafe { core::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()` + | + = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute_int_to_char_no_std.rs:19:28 + | +LL | let _: char = unsafe { core::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()` + +error: aborting due to 2 previous errors + 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 e7f35c5743684..bdc7b9f647877 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -12,7 +12,7 @@ fn main() { let b: &[u8] = unsafe { std::mem::transmute(a) }; //~^ ERROR: transmute from a reference to a reference let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; - let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; //~^ ERROR: transmute from a reference to a reference } } 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 cc6b156b18885..4238bc637ad04 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr @@ -19,8 +19,8 @@ LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; error: transmute from a reference to a reference --> $DIR/transmute_ref_to_ref.rs:15:42 | -LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` +LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` error: aborting due to 3 previous errors 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 new file mode 100644 index 0000000000000..b67386f858852 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs @@ -0,0 +1,30 @@ +//@no-rustfix + +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +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 + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { core::mem::transmute(a) }; + //~^ ERROR: transmute from a reference to a reference + 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 + } +} 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 new file mode 100644 index 0000000000000..ca7966ffa9e88 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr @@ -0,0 +1,26 @@ +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:21:39 + | +LL | let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` + | +note: the lint level is defined here + --> $DIR/transmute_ref_to_ref_no_std.rs:3:9 + | +LL | #![deny(clippy::transmute_ptr_to_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:24: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 + --> $DIR/transmute_ref_to_ref_no_std.rs:27:42 + | +LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs index e1a2d6a90b896..7b898a6e0e784 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.rs +++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs @@ -264,6 +264,28 @@ impl S13 { } } -fn main() { - // test code goes here +struct S14 { + field: String, +} + +impl PartialEq for S14 { + fn eq(&self, other: &Self) -> bool { + // Should not warn! + self.field.eq(&other.field) + } +} + +struct S15<'a> { + field: &'a S15<'a>, } + +impl PartialEq for S15<'_> { + fn eq(&self, other: &Self) -> bool { + //~^ ERROR: function cannot return without recursing + let mine = &self.field; + let theirs = &other.field; + mine.eq(theirs) + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr index 5d82e2a9f3194..094b80d4586c8 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr +++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr @@ -340,5 +340,22 @@ note: recursive call site LL | Self::default() | ^^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: function cannot return without recursing + --> $DIR/unconditional_recursion.rs:283:5 + | +LL | / fn eq(&self, other: &Self) -> bool { +LL | | +LL | | let mine = &self.field; +LL | | let theirs = &other.field; +LL | | mine.eq(theirs) +LL | | } + | |_____^ + | +note: recursive call site + --> $DIR/unconditional_recursion.rs:287:9 + | +LL | mine.eq(theirs) + | ^^^^^^^^^^^^^^^ + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_join.stderr b/src/tools/clippy/tests/ui/unnecessary_join.stderr index 8bf2ac5fdb1d9..205a714b694ae 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_join.stderr @@ -4,7 +4,7 @@ error: called `.collect::>().join("")` on an iterator LL | .collect::>() | __________^ LL | | .join(""); - | |_________________^ help: try using: `collect::()` + | |_________________^ help: consider using: `collect::()` | = note: `-D clippy::unnecessary-join` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_join)]` @@ -15,7 +15,7 @@ error: called `.collect::>().join("")` on an iterator LL | .collect::>() | __________^ LL | | .join(""); - | |_________________^ help: try using: `collect::()` + | |_________________^ help: consider using: `collect::()` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr index 9d54c8d50e31f..f4409113a45fa 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr @@ -1,4 +1,4 @@ -error: use Vec::sort here instead +error: consider using `sort` --> $DIR/unnecessary_sort_by.rs:12:5 | LL | vec.sort_by(|a, b| a.cmp(b)); @@ -7,67 +7,67 @@ LL | vec.sort_by(|a, b| a.cmp(b)); = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` -error: use Vec::sort here instead +error: consider using `sort` --> $DIR/unnecessary_sort_by.rs:13:5 | LL | vec.sort_unstable_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:14: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: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:15:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:18: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: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:19: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: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:29:5 | LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:30:5 | LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:89:9 | LL | args.sort_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:90:9 | LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:92: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: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:93:9 | LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs index 62aec6e9eafca..9974600dad5be 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.rs +++ b/src/tools/clippy/tests/ui/unused_io_amount.rs @@ -1,4 +1,5 @@ #![allow(dead_code, clippy::needless_pass_by_ref_mut)] +#![allow(clippy::redundant_pattern_matching)] #![warn(clippy::unused_io_amount)] extern crate futures; @@ -142,4 +143,90 @@ async fn undetected_bad_async_write(w: &mut W) { future.await.unwrap(); } +fn match_okay_underscore(s: &mut T) { + match s.write(b"test") { + //~^ ERROR: written amount is not handled + 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 + 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 + 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 + Ok(_) => todo!(), + //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled + Err(_) => todo!(), + } +} + +fn returned_value_should_not_lint(s: &mut T) -> Result { + s.write(b"test") +} + +fn if_okay_underscore_read_expr(s: &mut T) { + if let Ok(_) = s.read(&mut [0u8; 4]) { + //~^ ERROR: read amount is not handled + todo!() + } +} + +fn if_okay_underscore_write_expr(s: &mut T) { + if let Ok(_) = s.write(b"test") { + //~^ ERROR: written amount is not handled + todo!() + } +} + +fn if_okay_dots_write_expr(s: &mut T) { + if let Ok(..) = s.write(b"test") { + //~^ ERROR: written amount is not handled + todo!() + } +} + +fn if_okay_underscore_write_expr_true_negative(s: &mut T) { + if let Ok(bound) = s.write(b"test") { + todo!() + } +} + +fn match_okay_underscore_true_neg(s: &mut T) { + match s.write(b"test") { + Ok(bound) => todo!(), + Err(_) => todo!(), + }; +} + +fn true_negative(s: &mut T) { + let mut buf = [0u8; 4]; + let read_amount = s.read(&mut buf).unwrap(); +} + +fn on_return_should_not_raise(s: &mut T) -> io::Result { + /// this is bad code because it goes around the problem of handling the read amount + /// by returning it, which makes it impossible to know this is a resonpose from the + /// correct account. + let mut buf = [0u8; 4]; + s.read(&mut buf) +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr index f9aef596a1c98..4af56d264bfa1 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.stderr +++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr @@ -1,5 +1,5 @@ error: written amount is not handled - --> $DIR/unused_io_amount.rs:9:5 + --> $DIR/unused_io_amount.rs:10:5 | LL | s.write(b"test")?; | ^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | s.write(b"test")?; = help: to override `-D warnings` add `#[allow(clippy::unused_io_amount)]` error: read amount is not handled - --> $DIR/unused_io_amount.rs:12:5 + --> $DIR/unused_io_amount.rs:13:5 | LL | s.read(&mut buf)?; | ^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | s.read(&mut buf)?; = help: use `Read::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:18:5 + --> $DIR/unused_io_amount.rs:19:5 | LL | s.write(b"test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | s.write(b"test").unwrap(); = help: use `Write::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:21:5 + --> $DIR/unused_io_amount.rs:22:5 | LL | s.read(&mut buf).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,19 +33,19 @@ LL | s.read(&mut buf).unwrap(); = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:26:5 + --> $DIR/unused_io_amount.rs:27:5 | LL | s.read_vectored(&mut [io::IoSliceMut::new(&mut [])])?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: written amount is not handled - --> $DIR/unused_io_amount.rs:28:5 + --> $DIR/unused_io_amount.rs:29:5 | LL | s.write_vectored(&[io::IoSlice::new(&[])])?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: read amount is not handled - --> $DIR/unused_io_amount.rs:36:5 + --> $DIR/unused_io_amount.rs:37:5 | LL | reader.read(&mut result).ok()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | reader.read(&mut result).ok()?; = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:46:5 + --> $DIR/unused_io_amount.rs:47:5 | LL | reader.read(&mut result).or_else(|err| Err(err))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | reader.read(&mut result).or_else(|err| Err(err))?; = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:59:5 + --> $DIR/unused_io_amount.rs:60:5 | LL | reader.read(&mut result).or(Err(Error::Kind))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | reader.read(&mut result).or(Err(Error::Kind))?; = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:67:5 + --> $DIR/unused_io_amount.rs:68:5 | LL | / reader LL | | @@ -82,7 +82,7 @@ LL | | .expect("error"); = help: use `Read::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:77:5 + --> $DIR/unused_io_amount.rs:78:5 | LL | s.write(b"ok").is_ok(); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | s.write(b"ok").is_ok(); = help: use `Write::write_all` instead, or handle partial writes error: written amount is not handled - --> $DIR/unused_io_amount.rs:79:5 + --> $DIR/unused_io_amount.rs:80:5 | LL | s.write(b"err").is_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ LL | s.write(b"err").is_err(); = help: use `Write::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:82:5 + --> $DIR/unused_io_amount.rs:83:5 | LL | s.read(&mut buf).is_ok(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | s.read(&mut buf).is_ok(); = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:84:5 + --> $DIR/unused_io_amount.rs:85:5 | LL | s.read(&mut buf).is_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | s.read(&mut buf).is_err(); = help: use `Read::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:89:5 + --> $DIR/unused_io_amount.rs:90:5 | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,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 - --> $DIR/unused_io_amount.rs:95:5 + --> $DIR/unused_io_amount.rs:96:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,15 @@ LL | r.read(&mut buf[..]).await.unwrap(); = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:109:9 + --> $DIR/unused_io_amount.rs:104:5 + | +LL | w.write(b"hello world"); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `AsyncWriteExt::write_all` instead, or handle partial writes + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:110:9 | LL | w.write(b"hello world").await?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,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 - --> $DIR/unused_io_amount.rs:118:9 + --> $DIR/unused_io_amount.rs:119:9 | LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,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 - --> $DIR/unused_io_amount.rs:127:5 + --> $DIR/unused_io_amount.rs:128:5 | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,12 +162,103 @@ LL | w.write(b"hello world").await.unwrap(); = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:133:5 + --> $DIR/unused_io_amount.rs:134:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `AsyncReadExt::read_exact` instead, or handle partial reads -error: aborting due to 20 previous errors +error: written amount is not handled + --> $DIR/unused_io_amount.rs:147: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 + --> $DIR/unused_io_amount.rs:149:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:155:11 + | +LL | match s.read(&mut buf) { + | ^^^^^^^^^^^^^^^^ + | + = 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 + --> $DIR/unused_io_amount.rs:157:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:164: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 + --> $DIR/unused_io_amount.rs:166:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:173: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 + --> $DIR/unused_io_amount.rs:175:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:186: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 + --> $DIR/unused_io_amount.rs:186:12 + | +LL | if let Ok(_) = s.read(&mut [0u8; 4]) { + | ^^^^^ + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:193: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 + --> $DIR/unused_io_amount.rs:193:12 + | +LL | if let Ok(_) = s.write(b"test") { + | ^^^^^ + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:200: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 + --> $DIR/unused_io_amount.rs:200:12 + | +LL | if let Ok(..) = s.write(b"test") { + | ^^^^^^ + +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index 88b95095bc0f0..c98f2928e03cc 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -144,6 +144,42 @@ fn foo() { //~^ ERROR: this call to `as_ref.map(...)` does nothing } +mod issue12135 { + pub struct Struct { + field: Option, + } + + #[derive(Clone)] + pub struct Foo; + + #[derive(Clone)] + struct InnerStruct { + x: Foo, + } + + impl InnerStruct { + fn method(&self) -> &Foo { + &self.x + } + } + + pub fn f(x: &Struct) -> Option { + x.field.clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + + // 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 + + x.field.as_ref().map(|v| v.method().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 504dc1f5cbf90..f9d603f116de5 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -144,6 +144,42 @@ fn foo() { //~^ ERROR: this call to `as_ref.map(...)` does nothing } +mod issue12135 { + pub struct Struct { + field: Option, + } + + #[derive(Clone)] + pub struct Foo; + + #[derive(Clone)] + struct InnerStruct { + x: Foo, + } + + impl InnerStruct { + fn method(&self) -> &Foo { + &self.x + } + } + + pub fn f(x: &Struct) -> Option { + x.field.as_ref().map(|v| v.clone()); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.as_ref().map(Clone::clone); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.as_ref().map(|v| Clone::clone(v)); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + + // 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 + + x.field.as_ref().map(|v| v.method().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 deb5d90f2f62f..e158df2664d77 100644 --- a/src/tools/clippy/tests/ui/useless_asref.stderr +++ b/src/tools/clippy/tests/ui/useless_asref.stderr @@ -88,5 +88,29 @@ error: this call to `as_ref.map(...)` does nothing LL | let z = x.as_ref().map(|z| String::clone(z)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()` -error: aborting due to 14 previous errors +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:167:9 + | +LL | x.field.as_ref().map(|v| v.clone()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` + +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:169:9 + | +LL | x.field.as_ref().map(Clone::clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` + +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:171: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 + --> $DIR/useless_asref.rs:176:9 + | +LL | Some(1).as_ref().map(|&x| x.clone()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index a05765b398133..3eadc66f544f3 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -19,7 +19,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" -users_on_vacation = ["blyxyas"] [assign.owners] "/.github" = ["@flip1995"] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e70e01e8757e0..ff907152ca916 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1109,9 +1109,6 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { } fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { - if config.system_llvm && line.starts_with("no-system-llvm") { - return IgnoreDecision::Ignore { reason: "ignored when the system LLVM is used".into() }; - } if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 8882f1582acc7..c859e8acadebd 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -242,15 +242,6 @@ fn aux_build() { ); } -#[test] -fn no_system_llvm() { - let config: Config = cfg().system_llvm(false).build(); - assert!(!check_ignore(&config, "// no-system-llvm")); - - let config: Config = cfg().system_llvm(true).build(); - assert!(check_ignore(&config, "// no-system-llvm")); -} - #[test] fn llvm_version() { let config: Config = cfg().llvm_version("8.1.2").build(); @@ -266,6 +257,18 @@ fn llvm_version() { assert!(!check_ignore(&config, "// min-llvm-version: 9.0")); } +#[test] +fn system_llvm_version() { + let config: Config = cfg().system_llvm(true).llvm_version("17.0.0").build(); + assert!(check_ignore(&config, "// min-system-llvm-version: 18.0")); + + let config: Config = cfg().system_llvm(true).llvm_version("18.0.0").build(); + assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0")); + + let config: Config = cfg().llvm_version("17.0.0").build(); + assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0")); +} + #[test] fn ignore_target() { let config: Config = cfg().target("x86_64-unknown-linux-gnu").build(); diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index 76c2e330b2100..f4dac6e947e32 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] mdbook = { version = "0.4", default-features = false, features = ["search"] } -rustc_error_codes = { version = "0.0.0", path = "../../../compiler/rustc_error_codes" } [[bin]] name = "error_index_generator" diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 865d7172cd3e6..2de2d959a95d7 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -4,13 +4,15 @@ extern crate rustc_driver; extern crate rustc_log; extern crate rustc_session; +extern crate rustc_errors; +use rustc_errors::codes::DIAGNOSTICS; + use std::env; use std::error::Error; use std::fs::{self, File}; use std::io::Write; use std::path::Path; use std::path::PathBuf; - use std::str::FromStr; use mdbook::book::{parse_summary, BookItem, Chapter}; @@ -38,7 +40,7 @@ fn render_markdown(output_path: &Path) -> Result<(), Box> { write!(output_file, "# Rust Compiler Error Index\n")?; - for (err_code, description) in rustc_error_codes::DIAGNOSTICS.iter() { + for (err_code, description) in DIAGNOSTICS.iter() { write!(output_file, "## {}\n{}\n", err_code, description)? } @@ -85,7 +87,7 @@ This page lists all the error codes emitted by the Rust compiler. " ); - let err_codes = rustc_error_codes::DIAGNOSTICS; + let err_codes = DIAGNOSTICS; let mut chapters = Vec::with_capacity(err_codes.len()); for (err_code, explanation) in err_codes.iter() { diff --git a/src/tools/miri/.github/workflows/sysroots.yml b/src/tools/miri/.github/workflows/sysroots.yml index 509521e7478b0..96d7d4d111851 100644 --- a/src/tools/miri/.github/workflows/sysroots.yml +++ b/src/tools/miri/.github/workflows/sysroots.yml @@ -1,8 +1,8 @@ name: Tier 2 sysroots -on: push -# schedule: -# - cron: '44 4 * * *' # At 4:44 UTC every day. +on: + schedule: + - cron: '44 4 * * *' # At 4:44 UTC every day. defaults: run: diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 6cd22a9151897..8cd996d85645b 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -486,9 +486,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "measureme" -version = "10.1.2" +version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e381dcdad44c3c435f8052b08c5c4a1449c48ab56f312345eae12d7a693dbe" +checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" dependencies = [ "log", "memmap2", diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 3dee742fa0dea..6695f123c7836 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -590,6 +590,7 @@ Definite bugs found: * [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186) * [Dropping with unaligned pointers in `vec::IntoIter`](https://github.com/rust-lang/rust/pull/106084) * [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460) +* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index a7412f90c8505..79ce1f4ca3226 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -501,11 +501,10 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner // Set missing env vars. We prefer build-time env vars over run-time ones; see // for the kind of issue that fixes. for (name, val) in info.env { - // `CARGO_MAKEFLAGS` contains information about how to reach the - // jobserver, but by the time the program is being run, that jobserver - // no longer exists. Hence we shouldn't forward this. - // FIXME: Miri builds the final crate without a jobserver. - // This may be fixed with github.com/rust-lang/cargo/issues/12597. + // `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time + // the program is being run, that jobserver no longer exists (cargo only runs the jobserver + // for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this. + // Also see . if name == "CARGO_MAKEFLAGS" { continue; } diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 548e12ffdeafb..6624672775f9d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5bcd86d89b2b7b6a490f7e075dd4eb346deb5f98 +dd2559e08e1530806740931037d6bb83ef956161 diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 74ff6ed4e0abe..46f96a715f1c6 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -383,7 +383,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // will never cause UB on the pointer itself. let (_, _, kind) = this.get_alloc_info(*alloc_id); if matches!(kind, AllocKind::LiveData) { - let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap(); + let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static` let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap(); alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?; } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index eac315d04368d..7740d383ee3f2 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -830,7 +830,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' let new_prov = this.sb_reborrow(place, size, new_perm, new_tag, info)?; // Adjust place. - Ok(place.clone().map_provenance(|_| new_prov)) + // (If the closure gets called, that means the old provenance was `Some`, and hence the new + // one must also be `Some`.) + Ok(place.clone().map_provenance(|_| new_prov.unwrap())) } /// Retags an individual pointer, returning the retagged version. diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 573d13bf4a5d9..0945a5292bb92 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -351,7 +351,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' let new_prov = this.tb_reborrow(place, reborrow_size, new_perm, new_tag)?; // Adjust place. - Ok(place.clone().map_provenance(|_| new_prov)) + // (If the closure gets called, that means the old provenance was `Some`, and hence the new + // one must also be `Some`.) + Ok(place.clone().map_provenance(|_| new_prov.unwrap())) } /// Retags an individual pointer, returning the retagged version. diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index bf3284df5967a..92c58d48dc757 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -104,7 +104,7 @@ impl MachineStopType for TerminationInfo { self: Box, _: &mut dyn FnMut( std::borrow::Cow<'static, str>, - rustc_errors::DiagnosticArgValue<'static>, + rustc_errors::DiagnosticArgValue, ), ) { } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 905b2fc4d604b..d6b1e1358086c 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Helper function to get a `windows` constant as a `Scalar`. fn eval_windows(&self, module: &str, name: &str) -> Scalar { - self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal","windows", module, name]) + self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name]) } /// Helper function to get a `windows` constant as a `u32`. @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> { let this = self.eval_context_ref(); let ty = this - .resolve_path(&["std", "sys", "pal","windows", "c", name], Namespace::TypeNS) + .resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS) .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty).unwrap() } @@ -270,6 +270,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { bug!("No field named {} in type {}", name, base.layout().ty); } + /// Search if `base` (which must be a struct or union type) contains the `name` field. + fn projectable_has_field>( + &self, + base: &P, + name: &str, + ) -> bool { + let adt = base.layout().ty.ty_adt_def().unwrap(); + for field in adt.non_enum_variant().fields.iter() { + if field.name.as_str() == name { + return true; + } + } + false + } + /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so /// this method is fine for almost all integer types. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index cacd02bbfaee1..057b883a3bf9e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -8,10 +8,9 @@ #![feature(variant_count)] #![feature(yeet_expr)] #![feature(nonzero_ops)] -#![feature(round_ties_even)] #![feature(let_chains)] #![feature(lint_reasons)] -#![feature(int_roundings)] +#![cfg_attr(not(bootstrap), feature(trait_upcasting))] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -95,7 +94,6 @@ pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::TlsData; -pub use crate::shims::EvalContextExt as _; pub use crate::borrow_tracker::stacked_borrows::{ EvalContextExt as _, Item, Permission, Stack, Stacks, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 4a878f4a36e6c..40d041c8fdb16 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -2,13 +2,15 @@ //! `Machine` trait. use std::borrow::Cow; -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; +use std::collections::hash_map::Entry; use std::fmt; use std::path::Path; use std::process; use either::Either; use rand::rngs::StdRng; +use rand::Rng; use rand::SeedableRng; use rustc_ast::ast::Mutability; @@ -45,6 +47,11 @@ pub const SIGRTMIN: i32 = 34; /// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`) pub const SIGRTMAX: i32 = 42; +/// Each const has multiple addresses, but only this many. Since const allocations are never +/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would +/// produce unbounded memory usage. +const ADDRS_PER_CONST: usize = 16; + /// Extra data stored with each stack frame pub struct FrameExtra<'tcx> { /// Extra data for the Borrow Tracker. @@ -65,12 +72,19 @@ pub struct FrameExtra<'tcx> { /// optimization. /// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span` pub is_user_relevant: bool, + + /// We have a cache for the mapping from [`mir::Const`] to resulting [`AllocId`]. + /// However, we don't want all frames to always get the same result, so we insert + /// an additional bit of "salt" into the cache key. This salt is fixed per-frame + /// so that within a call, a const will have a stable address. + salt: usize, } impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _ } = self; + let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = + self; f.debug_struct("FrameData") .field("borrow_tracker", borrow_tracker) .field("catch_unwind", catch_unwind) @@ -80,7 +94,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { impl VisitProvenance for FrameExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self; + let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = + self; catch_unwind.visit_provenance(visit); borrow_tracker.visit_provenance(visit); @@ -321,20 +336,11 @@ pub struct AllocExtra<'tcx> { /// if this allocation is leakable. The backtrace is not /// pruned yet; that should be done before printing it. pub backtrace: Option>>, - /// An offset inside this allocation that was deemed aligned even for symbolic alignment checks. - /// Invariant: the promised alignment will never be less than the native alignment of this allocation. - pub symbolic_alignment: Cell>, } impl VisitProvenance for AllocExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let AllocExtra { - borrow_tracker, - data_race, - weak_memory, - backtrace: _, - symbolic_alignment: _, - } = self; + let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self; borrow_tracker.visit_provenance(visit); data_race.visit_provenance(visit); @@ -552,6 +558,19 @@ pub struct MiriMachine<'mir, 'tcx> { /// The spans we will use to report where an allocation was created and deallocated in /// diagnostics. pub(crate) allocation_spans: RefCell)>>, + + /// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`) + /// that is fixed per stack frame; this lets us have sometimes different results for the + /// same const while ensuring consistent results within a single call. + const_cache: RefCell, usize), OpTy<'tcx, Provenance>>>, + + /// For each allocation, an offset inside that allocation that was deemed aligned even for + /// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be + /// tracked for vtables and function allocations as well as regular allocations. + /// + /// Invariant: the promised alignment will never be less than the native alignment of the + /// allocation. + pub(crate) symbolic_alignment: RefCell>, } impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { @@ -677,6 +696,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { stack_size, collect_leak_backtraces: config.collect_leak_backtraces, allocation_spans: RefCell::new(FxHashMap::default()), + const_cache: RefCell::new(FxHashMap::default()), + symbolic_alignment: RefCell::new(FxHashMap::default()), } } @@ -691,7 +712,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { Ok(()) } - fn add_extern_static( + pub(crate) fn add_extern_static( this: &mut MiriInterpCx<'mir, 'tcx>, name: &str, ptr: Pointer>, @@ -701,75 +722,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } - fn alloc_extern_static( - this: &mut MiriInterpCx<'mir, 'tcx>, - name: &str, - val: ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { - let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; - this.write_immediate(*val, &place)?; - Self::add_extern_static(this, name, place.ptr()); - Ok(()) - } - - /// Sets up the "extern statics" for this machine. - fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { - // "__rust_no_alloc_shim_is_unstable" - let val = ImmTy::from_int(0, this.machine.layouts.u8); - Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?; - - match this.tcx.sess.target.os.as_ref() { - "linux" => { - // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr(), - ); - // A couple zero-initialized pointer-sized extern statics. - // Most of them are for weak symbols, which we all set to null (indicating that the - // symbol is not supported, and triggering fallback code which ends up calling a - // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] - { - let val = ImmTy::from_int(0, this.machine.layouts.usize); - Self::alloc_extern_static(this, name, val)?; - } - } - "freebsd" => { - // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr(), - ); - } - "android" => { - // "signal" -- just needs a non-zero pointer value (function does not even get called), - // but we arrange for this to be callable anyway (it will then do nothing). - let layout = this.machine.layouts.const_raw_ptr; - let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal"))); - let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); - Self::alloc_extern_static(this, "signal", val)?; - // A couple zero-initialized pointer-sized extern statics. - // Most of them are for weak symbols, which we all set to null (indicating that the - // symbol is not supported, and triggering fallback code.) - for name in &["bsd_signal"] { - let val = ImmTy::from_int(0, this.machine.layouts.usize); - Self::alloc_extern_static(this, name, val)?; - } - } - "windows" => { - // "_tls_used" - // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let val = ImmTy::from_int(0, this.machine.layouts.u8); - Self::alloc_extern_static(this, "_tls_used", val)?; - } - _ => {} // No "extern statics" supported on this target - } - Ok(()) - } - pub(crate) fn communicate(&self) -> bool { self.isolated_op == IsolatedOp::Allow } @@ -857,6 +809,8 @@ impl VisitProvenance for MiriMachine<'_, '_> { stack_size: _, collect_leak_backtraces: _, allocation_spans: _, + const_cache: _, + symbolic_alignment: _, } = self; threads.visit_provenance(visit); @@ -940,9 +894,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { return None; } // Let's see which alignment we have been promised for this allocation. - let alloc_info = ecx.get_alloc_extra(alloc_id).unwrap(); // cannot fail since the allocation is live - let (promised_offset, promised_align) = - alloc_info.symbolic_alignment.get().unwrap_or((Size::ZERO, alloc_align)); + let (promised_offset, promised_align) = ecx + .machine + .symbolic_alignment + .borrow() + .get(&alloc_id) + .copied() + .unwrap_or((Size::ZERO, alloc_align)); if promised_align < align { // Definitely not enough. Some(Misalignment { has: promised_align, required: align }) @@ -989,7 +947,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind) + // For foreign items, try to see if we can emulate them. + if ecx.tcx.is_foreign_item(instance.def_id()) { + // An external function call that does not have a MIR body. We either find MIR elsewhere + // or emulate its effect. + // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need + // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the + // foreign function + // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. + let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? + let link_name = ecx.item_link_name(instance.def_id()); + return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); + } + + // Otherwise, load the MIR. + Ok(Some((ecx.load_mir(instance.def, None)?, instance))) } #[inline(always)] @@ -1165,7 +1137,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { data_race: race_alloc, weak_memory: buffer_alloc, backtrace, - symbolic_alignment: Cell::new(None), }, |ptr| ecx.global_base_pointer(ptr), )?; @@ -1400,6 +1371,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { catch_unwind: None, timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), + salt: ecx.machine.rng.borrow_mut().gen::() % ADDRS_PER_CONST, }; Ok(frame.with_extra(extra)) @@ -1505,4 +1477,31 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None)); Ok(()) } + + fn eval_mir_constant( + ecx: &InterpCx<'mir, 'tcx, Self>, + val: mir::Const<'tcx>, + span: Option, + layout: Option>, + eval: F, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + where + F: Fn( + &InterpCx<'mir, 'tcx, Self>, + mir::Const<'tcx>, + Option, + Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + { + let frame = ecx.active_thread_stack().last().unwrap(); + let mut cache = ecx.machine.const_cache.borrow_mut(); + match cache.entry((val, frame.extra.salt)) { + Entry::Vacant(ve) => { + let op = eval(ecx, val, span, layout)?; + ve.insert(op.clone()); + Ok(op) + } + Entry::Occupied(oe) => Ok(oe.get().clone()), + } + } } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 140764446969a..6f19dead2e9bf 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { - assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for` + assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for` let size = this.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index ab178f82d9fde..347951ce37270 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -196,6 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let allocs = LiveAllocs { ecx: this, collected: allocs }; this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id)); + this.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id)); this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs); if let Some(borrow_tracker) = &this.machine.borrow_tracker { borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs); diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs new file mode 100644 index 0000000000000..0284e5b606ced --- /dev/null +++ b/src/tools/miri/src/shims/extern_static.rs @@ -0,0 +1,79 @@ +//! Provides the `extern static` that this platform expects. + +use crate::*; + +impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { + fn alloc_extern_static( + this: &mut MiriInterpCx<'mir, 'tcx>, + name: &str, + val: ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; + this.write_immediate(*val, &place)?; + Self::add_extern_static(this, name, place.ptr()); + Ok(()) + } + + /// Zero-initialized pointer-sized extern statics are pretty common. + /// Most of them are for weak symbols, which we all set to null (indicating that the + /// symbol is not supported, and triggering fallback code which ends up calling a + /// syscall that we do support). + fn null_ptr_extern_statics( + this: &mut MiriInterpCx<'mir, 'tcx>, + names: &[&str], + ) -> InterpResult<'tcx> { + for name in names { + let val = ImmTy::from_int(0, this.machine.layouts.usize); + Self::alloc_extern_static(this, name, val)?; + } + Ok(()) + } + + /// Sets up the "extern statics" for this machine. + pub fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { + // "__rust_no_alloc_shim_is_unstable" + let val = ImmTy::from_int(0, this.machine.layouts.u8); + Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?; + + match this.tcx.sess.target.os.as_ref() { + "linux" => { + Self::null_ptr_extern_statics( + this, + &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"], + )?; + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.as_ref().unwrap().ptr(), + ); + } + "freebsd" => { + Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?; + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.as_ref().unwrap().ptr(), + ); + } + "android" => { + Self::null_ptr_extern_statics(this, &["bsd_signal"])?; + // "signal" -- just needs a non-zero pointer value (function does not even get called), + // but we arrange for this to call the `signal` function anyway. + let layout = this.machine.layouts.const_raw_ptr; + let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal"))); + let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); + Self::alloc_extern_static(this, "signal", val)?; + } + "windows" => { + // "_tls_used" + // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. + let val = ImmTy::from_int(0, this.machine.layouts.u8); + Self::alloc_extern_static(this, "_tls_used", val)?; + } + _ => {} // No "extern statics" supported on this target + } + Ok(()) + } +} diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index a002f2aad057c..25654248db41a 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -585,17 +585,17 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr) { let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id); - // Not `get_alloc_extra_mut`, need to handle read-only allocations! - let alloc_extra = this.get_alloc_extra(alloc_id)?; // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align - && !alloc_extra + && !this + .machine .symbolic_alignment - .get() - .is_some_and(|(_, old_align)| align <= old_align) + .get_mut() + .get(&alloc_id) + .is_some_and(|&(_, old_align)| align <= old_align) { - alloc_extra.symbolic_alignment.set(Some((offset, align))); + this.machine.symbolic_alignment.get_mut().insert(alloc_id, (offset, align)); } } } diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index a1db7bf74f281..e34fb118f7234 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -5,6 +5,7 @@ use std::iter; use log::trace; +use rand::Rng; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{ @@ -141,6 +142,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?; } + // We want to return either `true` or `false` at random, or else something like + // ``` + // if !is_val_statically_known(0) { unreachable_unchecked(); } + // ``` + // Would not be considered UB, or the other way around (`is_val_statically_known(0)`). + "is_val_statically_known" => { + let [arg] = check_arg_count(args)?; + this.validate_operand(arg)?; + let branch: bool = this.machine.rng.get_mut().gen(); + this.write_scalar(Scalar::from_bool(branch), dest)?; + } + // Floating-point operations "fabsf32" => { let [f] = check_arg_count(args)?; diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 1e9d927e1a957..ea6120f757947 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -10,48 +10,8 @@ pub mod windows; mod x86; pub mod env; +pub mod extern_static; pub mod os_str; pub mod panic; pub mod time; pub mod tls; - -// End module management, begin local code - -use log::trace; - -use rustc_middle::{mir, ty}; -use rustc_target::spec::abi::Abi; - -use crate::*; - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn find_mir_or_eval_fn( - &mut self, - instance: ty::Instance<'tcx>, - abi: Abi, - args: &[FnArg<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, dest); - - // For foreign items, try to see if we can emulate them. - if this.tcx.is_foreign_item(instance.def_id()) { - // An external function call that does not have a MIR body. We either find MIR elsewhere - // or emulate its effect. - // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need - // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the - // foreign function - // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? - let link_name = this.item_link_name(instance.def_id()); - return this.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); - } - - // Otherwise, load the MIR. - Ok(Some((this.load_mir(instance.def, None)?, instance))) - } -} diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 23342c8045e80..35036ce078d37 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -155,6 +155,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_i64()?; + let whence = this.read_scalar(whence)?.to_i32()?; + let result = this.lseek64(fd, offset.into(), whence)?; + this.write_scalar(result, dest)?; + } + "lseek" => { + let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let whence = this.read_scalar(whence)?.to_i32()?; let result = this.lseek64(fd, offset, whence)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 7c843e106eacf..64094ac307d2a 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateForeignItemResult; +use shims::unix::fs::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(_name: &str) -> bool { @@ -63,6 +64,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_target_usize(len, this), dest)?; } + // File related shims + // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases + // since freebsd 12 the former form can be expected. + "stat" | "stat@FBSD_1.0" => { + let [path, buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_stat(path, buf)?; + this.write_scalar(result, dest)?; + } + "lstat" | "lstat@FBSD_1.0" => { + let [path, buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_lstat(path, buf)?; + this.write_scalar(result, dest)?; + } + "fstat" | "fstat@FBSD_1.0" => { + let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_fstat(fd, buf)?; + this.write_scalar(result, dest)?; + } + "readdir_r" | "readdir_r@FBSD_1.0" => { + let [dirp, entry, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; + this.write_scalar(result, dest)?; + } + // errno "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 99d8a3a2c91f4..53f975baa89a5 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -813,24 +813,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn lseek64( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - offset_op: &OpTy<'tcx, Provenance>, - whence_op: &OpTy<'tcx, Provenance>, + fd: i32, + offset: i128, + whence: i32, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. - let fd = this.read_scalar(fd_op)?.to_i32()?; - let offset = this.read_scalar(offset_op)?.to_i64()?; - let whence = this.read_scalar(whence_op)?.to_i32()?; - let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { SeekFrom::Start(u64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_CUR") { - SeekFrom::Current(offset) + SeekFrom::Current(i64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_END") { - SeekFrom::End(offset) + SeekFrom::End(i64::try_from(offset).unwrap()) } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -897,13 +893,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.try_unwrap_io_result(result) } - fn macos_stat( + fn macos_fbsd_stat( &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "stat"); + + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os); + } let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); @@ -926,13 +925,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // `lstat` is used to get symlink metadata. - fn macos_lstat( + fn macos_fbsd_lstat( &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "lstat"); + + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os); + } let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); @@ -953,14 +955,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } - fn macos_fstat( + fn macos_fbsd_fstat( &mut self, fd_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "fstat"); + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_fstat` should not be called on {}", this.tcx.sess.target.os); + } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1199,7 +1203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.os == "macos" { + let mode = if matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { u32::from(this.read_scalar(mode_op)?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? @@ -1371,7 +1375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_maybe_pointer(entry, this)) } - fn macos_readdir_r( + fn macos_fbsd_readdir_r( &mut self, dirp_op: &OpTy<'tcx, Provenance>, entry_op: &OpTy<'tcx, Provenance>, @@ -1379,7 +1383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "readdir_r"); + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_readdir_r` should not be called on {}", this.tcx.sess.target.os); + } let dirp = this.read_target_usize(dirp_op)?; @@ -1410,7 +1416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // } let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?; - let name_place = this.project_field(&entry_place, 5)?; + let name_place = this.project_field_named(&entry_place, "d_name")?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str( @@ -1434,16 +1440,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields_named( - &[ - ("d_ino", ino.into()), - ("d_seekoff", 0), - ("d_reclen", 0), - ("d_namlen", file_name_len.into()), - ("d_type", file_type.into()), - ], - &entry_place, - )?; + // macOS offset field is d_seekoff + if this.projectable_has_field(&entry_place, "d_seekoff") { + this.write_int_fields_named( + &[ + ("d_ino", ino.into()), + ("d_seekoff", 0), + ("d_reclen", 0), + ("d_namlen", file_name_len.into()), + ("d_type", file_type.into()), + ], + &entry_place, + )?; + } else if this.projectable_has_field(&entry_place, "d_off") { + // freebsd 12 and onwards had added the d_off field + this.write_int_fields_named( + &[ + ("d_fileno", ino.into()), + ("d_off", 0), + ("d_reclen", 0), + ("d_type", file_type.into()), + ("d_namlen", file_name_len.into()), + ], + &entry_place, + )?; + } else { + this.write_int_fields_named( + &[ + ("d_fileno", ino.into()), + ("d_reclen", 0), + ("d_type", file_type.into()), + ("d_namlen", file_name_len.into()), + ], + &entry_place, + )?; + } let result_place = this.deref_pointer(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 07e19cadd6e32..ecc07e28a2988 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -40,18 +40,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_stat(path, buf)?; + let result = this.macos_fbsd_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_lstat(path, buf)?; + let result = this.macos_fbsd_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_fstat(fd, buf)?; + let result = this.macos_fbsd_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { @@ -62,14 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "readdir_r" | "readdir_r$INODE64" => { let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_readdir_r(dirp, entry, result)?; - this.write_scalar(result, dest)?; - } - "lseek" => { - let [fd, offset, whence] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - // macOS is 64bit-only, so this is lseek64 - let result = this.lseek64(fd, offset, whence)?; + let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs index 0e7c3dbcc040f..13f913454dcdf 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs @@ -1,4 +1,5 @@ trait T1 { + #[allow(dead_code)] fn method1(self: Box); } trait T2 { diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 7d46ecd8f6ea8..982f33b0a3102 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -1,28 +1,37 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + #[allow(dead_code)] fn a(&self) -> i32 { 10 } + #[allow(dead_code)] fn z(&self) -> i32 { 11 } + #[allow(dead_code)] fn y(&self) -> i32 { 12 } } trait Bar: Foo { + #[allow(dead_code)] fn b(&self) -> i32 { 20 } + #[allow(dead_code)] fn w(&self) -> i32 { 21 } } trait Baz: Bar { + #[allow(dead_code)] fn c(&self) -> i32 { 30 } diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs new file mode 100644 index 0000000000000..446040749822e --- /dev/null +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs @@ -0,0 +1,12 @@ +//@compile-flags: -Zmiri-symbolic-alignment-check + +extern "C" { + static _dispatch_queue_attr_concurrent: [u8; 0]; +} + +static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] = + unsafe { &_dispatch_queue_attr_concurrent }; + +fn main() { + let _val = *DISPATCH_QUEUE_CONCURRENT; //~ERROR: is not supported +} diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr new file mode 100644 index 0000000000000..a4249d2e8816d --- /dev/null +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri + --> $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC + | +LL | let _val = *DISPATCH_QUEUE_CONCURRENT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs index adfece586611d..5185db0b0e29f 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: no libc on Windows -//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0` //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs index 4df364bac7ad9..e96f11b1efa72 100644 --- a/src/tools/miri/tests/pass/align_offset_symbolic.rs +++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs @@ -1,6 +1,8 @@ //@compile-flags: -Zmiri-symbolic-alignment-check #![feature(strict_provenance)] +use std::mem; + fn test_align_to() { const N: usize = 4; let d = Box::new([0u32; N]); @@ -68,7 +70,7 @@ fn test_u64_array() { #[repr(align(8))] struct AlignToU64(T); - const BYTE_LEN: usize = std::mem::size_of::<[u64; 4]>(); + const BYTE_LEN: usize = mem::size_of::<[u64; 4]>(); type Data = AlignToU64<[u8; BYTE_LEN]>; fn example(data: &Data) { @@ -101,10 +103,29 @@ fn huge_align() { let _ = std::ptr::invalid::(SIZE).align_offset(SIZE); } +// This shows that we cannot store the promised alignment info in `AllocExtra`, +// since vtables do not have an `AllocExtra`. +fn vtable() { + #[cfg(target_pointer_width = "64")] + type TWOPTR = u128; + #[cfg(target_pointer_width = "32")] + type TWOPTR = u64; + + let ptr: &dyn Send = &0; + let parts: (*const (), *const u8) = unsafe { mem::transmute(ptr) }; + let vtable = parts.1 ; + let offset = vtable.align_offset(mem::align_of::()); + let _vtable_aligned = vtable.wrapping_add(offset) as *const [TWOPTR; 0]; + // FIXME: we can't actually do the access since vtable pointers act like zero-sized allocations. + // Enable the next line once https://github.com/rust-lang/rust/issues/117945 is implemented. + //let _place = unsafe { &*vtable_aligned }; +} + fn main() { test_align_to(); test_from_utf8(); test_u64_array(); test_cstr(); huge_align(); + vtable(); } diff --git a/src/tools/miri/tests/pass/async-fn.rs b/src/tools/miri/tests/pass/async-fn.rs index 6c92735df0af8..13400c88c7112 100644 --- a/src/tools/miri/tests/pass/async-fn.rs +++ b/src/tools/miri/tests/pass/async-fn.rs @@ -76,8 +76,7 @@ async fn uninhabited_variant() { fn run_fut(fut: impl Future) -> T { use std::task::{Context, Poll, Waker}; - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); let mut pinned = Box::pin(fut); loop { diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs index 75b512f6f729a..8d6da0733fe17 100644 --- a/src/tools/miri/tests/pass/box-custom-alloc.rs +++ b/src/tools/miri/tests/pass/box-custom-alloc.rs @@ -1,6 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(allocator_api)] +#![allow(incomplete_features)] // for trait upcasting +#![feature(allocator_api, trait_upcasting)] use std::alloc::Layout; use std::alloc::{AllocError, Allocator}; diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs index ccf96b9967202..2491bda0917d3 100644 --- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -9,6 +9,7 @@ trait Foo { } } +#[allow(dead_code)] trait Bar { fn bar(&self) { println!("Bar!"); diff --git a/src/tools/miri/tests/pass/const-addrs.rs b/src/tools/miri/tests/pass/const-addrs.rs new file mode 100644 index 0000000000000..6c14f0b679ce8 --- /dev/null +++ b/src/tools/miri/tests/pass/const-addrs.rs @@ -0,0 +1,38 @@ +// The const fn interpreter creates a new AllocId every time it evaluates any const. +// If we do that in Miri, repeatedly evaluating a const causes unbounded memory use +// we need to keep track of the base address for that AllocId, and the allocation is never +// deallocated. +// In Miri we explicitly store previously-assigned AllocIds for each const and ensure +// that we only hand out a finite number of AllocIds per const. +// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same +// stack frame, breaking this test. +//@compile-flags: -Zinline-mir=no +#![feature(strict_provenance)] + +const EVALS: usize = 256; + +use std::collections::HashSet; +fn main() { + let mut addrs = HashSet::new(); + for _ in 0..EVALS { + addrs.insert(const_addr()); + } + // Check that the const allocation has multiple base addresses + assert!(addrs.len() > 1); + // But also that we get a limited number of unique base addresses + assert!(addrs.len() < EVALS); + + // Check that within a call we always produce the same address + let mut prev = 0; + for iter in 0..EVALS { + let addr = "test".as_bytes().as_ptr().addr(); + if iter > 0 { + assert_eq!(prev, addr); + } + prev = addr; + } +} + +fn const_addr() -> usize { + "test".as_bytes().as_ptr().addr() +} diff --git a/src/tools/miri/tests/pass/dyn-star.rs b/src/tools/miri/tests/pass/dyn-star.rs index 8e26c4850fa8e..dab589b465181 100644 --- a/src/tools/miri/tests/pass/dyn-star.rs +++ b/src/tools/miri/tests/pass/dyn-star.rs @@ -93,8 +93,7 @@ fn dispatch_on_pin_mut() { let mut fut = async_main(); // Poll loop, just to test the future... - let waker = Waker::noop(); - let ctx = &mut Context::from_waker(&waker); + let ctx = &mut Context::from_waker(Waker::noop()); loop { match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } { diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index ddaefeca3a3be..529b9c471d426 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -1,3 +1,6 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + fn main() { basic(); diamond(); @@ -380,14 +383,17 @@ fn struct_() { fn replace_vptr() { trait A { + #[allow(dead_code)] fn foo_a(&self); } trait B { + #[allow(dead_code)] fn foo_b(&self); } trait C: A + B { + #[allow(dead_code)] fn foo_c(&self); } diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 5f2d4489f4ac1..1bb44d56bf6b5 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,5 +1,4 @@ #![feature(stmt_expr_attributes)] -#![feature(round_ties_even)] #![feature(float_gamma)] #![allow(arithmetic_overflow)] diff --git a/src/tools/miri/tests/pass/future-self-referential.rs b/src/tools/miri/tests/pass/future-self-referential.rs index 38cb700fd584f..8aeb26a7a957b 100644 --- a/src/tools/miri/tests/pass/future-self-referential.rs +++ b/src/tools/miri/tests/pass/future-self-referential.rs @@ -77,8 +77,7 @@ impl Future for DoStuff { } fn run_fut(fut: impl Future) -> T { - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); let mut pinned = pin!(fut); loop { @@ -90,8 +89,7 @@ fn run_fut(fut: impl Future) -> T { } fn self_referential_box() { - let waker = Waker::noop(); - let cx = &mut Context::from_waker(&waker); + let cx = &mut Context::from_waker(Waker::noop()); async fn my_fut() -> i32 { let val = 10; diff --git a/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs index 55d1bacdf4578..7363c75361779 100644 --- a/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs @@ -9,7 +9,7 @@ //@ignore-target-wasm32 //@compile-flags: -C target-feature=+aes,+vaes,+avx512f -#![feature(avx512_target_feature, stdsimd)] +#![feature(avx512_target_feature, stdarch_x86_avx512)] use core::mem::transmute; #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs index 394412a235432..66bfcb20f1c99 100644 --- a/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs @@ -10,7 +10,7 @@ //@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq #![feature(avx512_target_feature)] -#![feature(stdsimd)] +#![feature(stdarch_x86_avx512)] #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics.rs index 8c6eeab22195c..8e46bd7ad48fb 100644 --- a/src/tools/miri/tests/pass/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics.rs @@ -33,6 +33,21 @@ fn main() { assert_eq!(intrinsics::likely(false), false); assert_eq!(intrinsics::unlikely(true), true); + let mut saw_true = false; + let mut saw_false = false; + + for _ in 0..50 { + if unsafe { intrinsics::is_val_statically_known(0) } { + saw_true = true; + } else { + saw_false = true; + } + } + assert!( + saw_true && saw_false, + "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" + ); + intrinsics::forget(Bomb); let _v = intrinsics::discriminant_value(&Some(())); diff --git a/src/tools/miri/tests/pass/issues/issue-120337-irrefutable-let-ice.rs b/src/tools/miri/tests/pass/issues/issue-120337-irrefutable-let-ice.rs new file mode 100644 index 0000000000000..5af0d0e4bbd95 --- /dev/null +++ b/src/tools/miri/tests/pass/issues/issue-120337-irrefutable-let-ice.rs @@ -0,0 +1,16 @@ +// Validation stops the test before the ICE we used to hit +//@compile-flags: -Zmiri-disable-validation + +#![feature(never_type)] +#[derive(Copy, Clone)] +pub enum E { + A(!), +} +pub union U { + u: (), + e: E, +} + +fn main() { + let E::A(ref _a) = unsafe { &(&U { u: () }).e }; +} diff --git a/src/tools/miri/tests/pass/issues/issue-miri-2068.rs b/src/tools/miri/tests/pass/issues/issue-miri-2068.rs index f18c4a3a0655f..ccee2221e2958 100644 --- a/src/tools/miri/tests/pass/issues/issue-miri-2068.rs +++ b/src/tools/miri/tests/pass/issues/issue-miri-2068.rs @@ -6,8 +6,7 @@ use std::task::{Context, Poll, Waker}; pub fn fuzzing_block_on>(fut: F) -> O { let mut fut = std::pin::pin!(fut); - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); loop { match fut.as_mut().poll(&mut context) { Poll::Ready(v) => return v, diff --git a/src/tools/miri/tests/pass/issues/issue-miri-3282-struct-tail-normalize.rs b/src/tools/miri/tests/pass/issues/issue-miri-3282-struct-tail-normalize.rs new file mode 100644 index 0000000000000..2a31df83843e6 --- /dev/null +++ b/src/tools/miri/tests/pass/issues/issue-miri-3282-struct-tail-normalize.rs @@ -0,0 +1,20 @@ +// regression test for an ICE: https://github.com/rust-lang/miri/issues/3282 + +trait Id { + type Assoc: ?Sized; +} + +impl Id for T { + type Assoc = T; +} + +#[repr(transparent)] +struct Foo { + field: ::Assoc, +} + +fn main() { + let x = unsafe { std::mem::transmute::)>(|_| ()) }; + let foo: &Foo = unsafe { &*("uwu" as *const str as *const Foo) }; + x(foo); +} diff --git a/src/tools/miri/tests/pass/move-data-across-await-point.rs b/src/tools/miri/tests/pass/move-data-across-await-point.rs index 9bea6ea574209..1a93a6bf66497 100644 --- a/src/tools/miri/tests/pass/move-data-across-await-point.rs +++ b/src/tools/miri/tests/pass/move-data-across-await-point.rs @@ -56,8 +56,7 @@ fn data_moved() { fn run_fut(fut: impl Future) -> T { use std::task::{Context, Poll, Waker}; - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); let mut pinned = Box::pin(fut); loop { diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 4c3be6b3559ae..e10ccc277f6f1 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -11,6 +11,7 @@ use std::sync::atomic::Ordering::*; use std::sync::atomic::{fence, AtomicUsize}; use std::thread::spawn; +#[allow(dead_code)] #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index bcda930d093c5..590c735596ed9 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -300,7 +300,7 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { // Ok now it's time to read all the output. We're receiving "frames" // representing stdout/stderr, so we decode all that here. - let mut header = [0; 5]; + let mut header = [0; 9]; let mut stderr_done = false; let mut stdout_done = false; let mut client = t!(client.into_inner()); @@ -308,10 +308,8 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { let mut stderr = io::stderr(); while !stdout_done || !stderr_done { t!(client.read_exact(&mut header)); - let amt = ((header[1] as u64) << 24) - | ((header[2] as u64) << 16) - | ((header[3] as u64) << 8) - | ((header[4] as u64) << 0); + let amt = u64::from_be_bytes(header[1..9].try_into().unwrap()); + if header[0] == 0 { if amt == 0 { stdout_done = true; @@ -349,7 +347,8 @@ fn send(path: &Path, dst: &mut dyn Write) { t!(dst.write_all(&[0])); let mut file = t!(File::open(&path)); let amt = t!(file.metadata()).len(); - t!(dst.write_all(&[(amt >> 24) as u8, (amt >> 16) as u8, (amt >> 8) as u8, (amt >> 0) as u8,])); + + t!(dst.write_all(&amt.to_be_bytes())); t!(io::copy(&mut file, dst)); } diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index 3d61a0675590c..68d7aa56c438b 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -347,7 +347,7 @@ fn recv(dir: &Path, io: &mut B) -> PathBuf { // the filesystem limits. let len = cmp::min(filename.len() - 1, 50); let dst = dir.join(t!(str::from_utf8(&filename[..len]))); - let amt = read_u32(io) as u64; + let amt = read_u64(io); t!(io::copy(&mut io.take(amt), &mut t!(File::create(&dst)))); set_permissions(&dst); dst @@ -365,7 +365,7 @@ fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex) { loop { let n = t!(src.read(&mut b)); let mut dst = dst.lock().unwrap(); - t!(dst.write_all(&create_header(which, n as u32))); + t!(dst.write_all(&create_header(which, n as u64))); if n > 0 { t!(dst.write_all(&b[..n])); } else { @@ -377,7 +377,7 @@ fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex) { fn batch_copy(buf: &[u8], which: u8, dst: &Mutex) { let n = buf.len(); let mut dst = dst.lock().unwrap(); - t!(dst.write_all(&create_header(which, n as u32))); + t!(dst.write_all(&create_header(which, n as u64))); if n > 0 { t!(dst.write_all(buf)); // Marking buf finished @@ -385,13 +385,13 @@ fn batch_copy(buf: &[u8], which: u8, dst: &Mutex) { } } -const fn create_header(which: u8, n: u32) -> [u8; 5] { +const fn create_header(which: u8, n: u64) -> [u8; 9] { let bytes = n.to_be_bytes(); - [which, bytes[0], bytes[1], bytes[2], bytes[3]] + [which, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]] } -fn read_u32(r: &mut dyn Read) -> u32 { - let mut len = [0; 4]; +fn read_u64(r: &mut dyn Read) -> u64 { + let mut len = [0; 8]; t!(r.read_exact(&mut len)); - u32::from_be_bytes(len) + u64::from_be_bytes(len) } diff --git a/src/tools/rust-analyzer/.editorconfig b/src/tools/rust-analyzer/.editorconfig index f00ade5fd8266..e337066f7eaca 100644 --- a/src/tools/rust-analyzer/.editorconfig +++ b/src/tools/rust-analyzer/.editorconfig @@ -8,6 +8,7 @@ end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 +max_line_length = 100 [*.md] indent_size = 2 diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index be830415f9cb7..07fa85a61cbd0 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -90,7 +90,7 @@ jobs: - name: Switch to stable toolchain run: | rustup update --no-self-update stable - rustup component add --toolchain stable rust-src + rustup component add --toolchain stable rust-src clippy rustup default stable - name: Run analysis-stats on rust-analyzer @@ -103,6 +103,10 @@ jobs: RUSTC_BOOTSTRAP: 1 run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std + - name: clippy + if: matrix.os == 'ubuntu-latest' + run: cargo clippy --all-targets + # Weird targets to catch non-portable code rust-cross: if: github.repository == 'rust-lang/rust-analyzer' @@ -203,11 +207,25 @@ jobs: working-directory: ./editors/code if: needs.changes.outputs.typescript == 'true' + typo-check: + name: Typo Check + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + FORCE_COLOR: 1 + TYPOS_VERSION: v1.18.0 + steps: + - name: download typos + run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin + + - name: check for typos + run: typos + end-success: name: bors build finished if: github.event.pusher.name == 'bors' && success() runs-on: ubuntu-latest - needs: [rust, rust-cross, typescript] + needs: [rust, rust-cross, typescript, typo-check] steps: - name: Mark the job as successful run: exit 0 @@ -216,7 +234,7 @@ jobs: name: bors build finished if: github.event.pusher.name == 'bors' && !success() runs-on: ubuntu-latest - needs: [rust, rust-cross, typescript] + needs: [rust, rust-cross, typescript, typo-check] steps: - name: Mark the job as a failure run: exit 1 diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index 6a3cdfe3a3c7f..9077a9ac21eb6 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -43,10 +43,10 @@ jobs: - os: ubuntu-20.04 target: arm-unknown-linux-gnueabihf code-target: linux-armhf - - os: macos-11 + - os: macos-12 target: x86_64-apple-darwin code-target: darwin-x64 - - os: macos-11 + - os: macos-12 target: aarch64-apple-darwin code-target: darwin-arm64 diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml new file mode 100644 index 0000000000000..e638a3e648d68 --- /dev/null +++ b/src/tools/rust-analyzer/.typos.toml @@ -0,0 +1,31 @@ +[default.extend-identifiers] +AnserStyle = "AnserStyle" +datas = "datas" +impl_froms = "impl_froms" +selfs = "selfs" + +[default.extend-words] +anser = "anser" +ba = "ba" +fo = "fo" +ket = "ket" +makro = "makro" +raison = "raison" +trivias = "trivias" +TOOD = "TOOD" + +[default] +extend-ignore-re = [ + # ignore string which contains $x (x is a num), which use widely in test + ".*\\$\\d.*", + # ignore generated content like `boxed....nner()`, `Defaul...efault` + "\\w*\\.{3,4}\\w*", +] + +[files] +extend-exclude = [ + "*.json", + "*.rast", + "crates/parser/test_data/lexer/err/*", + "bench_data/*", +] diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 15d06222eb42d..e9492ce0202b2 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -19,11 +19,11 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "always-assert" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127" +checksum = "a1078fa1ce1e34b1872d8611ad921196d76bdd7027e949fbe31231abde201892" dependencies = [ - "log", + "tracing", ] [[package]] @@ -78,6 +78,7 @@ dependencies = [ "span", "stdx", "syntax", + "tracing", "triomphe", "vfs", ] @@ -160,21 +161,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.95.0" +version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329427f28cd2bddaacd47c4dcd3d7082d315c61fb164394c690fe98c1b6ee9d3" +checksum = "5676cea088c32290fe65c82895be9d06dd21e0fa49bb97ca840529e9417ab71a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", "synstructure", ] [[package]] name = "chalk-ir" -version = "0.95.0" +version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1e1659238bd598d0f7dbc5034cf1ff46010a3d6827704c9ed443c8359cb484" +checksum = "ff550c2cdd63ff74394214dce03d06386928a641c0f08837535f04af573a966d" dependencies = [ "bitflags 2.4.1", "chalk-derive", @@ -183,9 +184,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.95.0" +version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e0bff0ba1bed11407384fcec0353aeb6888901e63cb47d04505ec47adad847" +checksum = "4c4559e5c9b200240453b07d893f9c3c74413b53b0d33cbe272c68b0b77aa1c3" dependencies = [ "chalk-derive", "chalk-ir", @@ -196,9 +197,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.95.0" +version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9c46d501cf83732a91056c0c846ae7a16d6b3c67a6a6bb5e9cc0a2e91563b6" +checksum = "0882e68ce9eb5a0a2413806538494d19df6ee520ab17d1faf489e952f32e98b8" dependencies = [ "chalk-derive", "chalk-ir", @@ -312,6 +313,17 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -320,7 +332,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -483,8 +495,10 @@ dependencies = [ "profile", "rustc-hash", "smallvec", + "span", "stdx", "syntax", + "tracing", "triomphe", "tt", ] @@ -581,7 +595,8 @@ dependencies = [ "profile", "project-model", "ra-ap-rustc_abi", - "ra-ap-rustc_index", + "ra-ap-rustc_index 0.35.0", + "ra-ap-rustc_pattern_analysis", "rustc-hash", "scoped-tls", "smallvec", @@ -658,6 +673,7 @@ dependencies = [ "test-fixture", "test-utils", "text-edit", + "tracing", ] [[package]] @@ -678,6 +694,7 @@ dependencies = [ "test-fixture", "test-utils", "text-edit", + "tracing", ] [[package]] @@ -735,6 +752,7 @@ dependencies = [ "test-fixture", "test-utils", "text-edit", + "tracing", ] [[package]] @@ -1001,9 +1019,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memmap2" @@ -1330,6 +1348,7 @@ dependencies = [ "once_cell", "perf-event", "tikv-jemalloc-ctl", + "tracing", "winapi", ] @@ -1407,43 +1426,66 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.21.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7816f980fab89e878ff2e916e2077d484e3aa1c619a3cc982c8a417c3dfe45fa" +checksum = "3c0baa423a2c2bfd6e4bd40e7215f7ddebd12a649ce0b65078a38b91068895aa" dependencies = [ - "bitflags 1.3.2", - "ra-ap-rustc_index", + "bitflags 2.4.1", + "ra-ap-rustc_index 0.35.0", "tracing", ] [[package]] name = "ra-ap-rustc_index" -version = "0.21.0" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5313d7f243b63ef9e58d94355b11aa8499f1328055f1f58adf0a5ea7d2faca" +dependencies = [ + "arrayvec", + "ra-ap-rustc_index_macros 0.33.0", + "smallvec", +] + +[[package]] +name = "ra-ap-rustc_index" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8352918d61aa4afab9f2ed7314cf638976b20949b3d61d2f468c975b0d251f24" +checksum = "322b751895cc4a0a2ee0c6ab36ec80bc8abf5f8d76254c482f96f03c27c92ebe" dependencies = [ "arrayvec", - "ra-ap-rustc_index_macros", + "ra-ap-rustc_index_macros 0.35.0", "smallvec", ] [[package]] name = "ra-ap-rustc_index_macros" -version = "0.21.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a9424018828155a3e3596515598f90e68427d8f35eff6df7f0856c73fc58a8" +checksum = "a83108ebf3e73dde205b9c25706209bcd7736480820f90ded28eabaf8b469f25" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", + "synstructure", +] + +[[package]] +name = "ra-ap-rustc_index_macros" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054e25eac52f0506c1309ca4317c11ad4925d7b99eb897f71aa7c3cbafb46c2b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", "synstructure", ] [[package]] name = "ra-ap-rustc_lexer" -version = "0.21.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc741c7a78103efab416b562e35bd73c8d4967478575010c86c6062f8d3cbf29" +checksum = "c8da0fa51a1a97ba4296a1c78fa454815a153b472e2546b6338a0902ad59e015" dependencies = [ "unicode-properties", "unicode-xid", @@ -1451,14 +1493,28 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.21.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d557201d71792487bd2bab637ab5be9aa6fff59b88e25e12de180b0f9d2df60f" +checksum = "3851f930a54adcb76889983dcd5c00a0c4e206e190e1384dbc00d49b82dfb45e" dependencies = [ - "ra-ap-rustc_index", + "ra-ap-rustc_index 0.35.0", "ra-ap-rustc_lexer", ] +[[package]] +name = "ra-ap-rustc_pattern_analysis" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c4085e0c771fd4b883930b599ef42966b855762bbe4052c17673b3253421a6d" +dependencies = [ + "derivative", + "ra-ap-rustc_index 0.33.0", + "rustc-hash", + "rustc_apfloat", + "smallvec", + "tracing", +] + [[package]] name = "rayon" version = "1.8.0" @@ -1532,6 +1588,7 @@ dependencies = [ "lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", "mbe", + "memchr", "mimalloc", "nohash-hasher", "num_cpus", @@ -1554,7 +1611,6 @@ dependencies = [ "tikv-jemallocator", "toolchain", "tracing", - "tracing-log", "tracing-subscriber", "tracing-tree", "triomphe", @@ -1568,31 +1624,31 @@ dependencies = [ [[package]] name = "rust-analyzer-salsa" -version = "0.17.0-pre.5" +version = "0.17.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9d387a9801f4fb9b366789ad1bfc08448cafc49cf148d907cfcd88ab665d7f" +checksum = "719825638c59fd26a55412a24561c7c5bcf54364c88b9a7a04ba08a6eafaba8d" dependencies = [ "indexmap", "lock_api", - "log", "oorandom", "parking_lot", "rust-analyzer-salsa-macros", "rustc-hash", "smallvec", + "tracing", "triomphe", ] [[package]] name = "rust-analyzer-salsa-macros" -version = "0.17.0-pre.5" +version = "0.17.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2035f385d7fae31e9b086f40b272ee1d79c484472f31c9a10348a406e841eaf" +checksum = "4d96498e9684848c6676c399032ebc37c52da95ecbefa83d71ccc53b9f8a4a8e" dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1607,6 +1663,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_apfloat" +version = "0.2.0+llvm-462a31f5a5ab" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465187772033a5ee566f69fe008df03628fce549a0899aae76f0a0c2e34696be" +dependencies = [ + "bitflags 1.3.2", + "smallvec", +] + [[package]] name = "ryu" version = "1.0.13" @@ -1624,9 +1690,9 @@ dependencies = [ [[package]] name = "scip" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e84d21062a3ba08d58870c8c36b0c005b2b2261c6ad1bf7042585427c781883" +checksum = "e5dc1bd66649133af84ab62436ddd2856c2605182b02dec2cd197f684dfe15ef" dependencies = [ "protobuf", ] @@ -1669,7 +1735,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1692,7 +1758,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1706,15 +1772,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" [[package]] name = "smol_str" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" dependencies = [ "serde", ] @@ -1769,6 +1835,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.39" @@ -1788,7 +1865,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", "unicode-xid", ] @@ -1815,6 +1892,7 @@ dependencies = [ "stdx", "test-utils", "text-edit", + "tracing", "triomphe", "ungrammar", ] @@ -1842,6 +1920,7 @@ dependencies = [ "rustc-hash", "stdx", "text-size", + "tracing", ] [[package]] @@ -1875,7 +1954,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1976,7 +2055,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 35bef151196f0..3fb5d9aa7a869 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -79,10 +79,11 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.21.0", default-features = false } -ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false } -ra-ap-rustc_index = { version = "0.21.0", default-features = false } -ra-ap-rustc_abi = { version = "0.21.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.35.0", default-features = false } +ra-ap-rustc_parse_format = { version = "0.35.0", default-features = false } +ra-ap-rustc_index = { version = "0.35.0", default-features = false } +ra-ap-rustc_abi = { version = "0.35.0", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.33.0", default-features = false } # local crates that aren't published to crates.io. These should not have versions. sourcegen = { path = "./crates/sourcegen" } @@ -105,31 +106,31 @@ dissimilar = "1.0.7" either = "1.9.0" expect-test = "1.4.0" hashbrown = { version = "0.14", features = [ - "inline-more", + "inline-more", ], default-features = false } indexmap = "2.1.0" itertools = "0.12.0" libc = "0.2.150" nohash-hasher = "0.2.0" rayon = "1.8.0" -rust-analyzer-salsa = "0.17.0-pre.5" +rust-analyzer-salsa = "0.17.0-pre.6" rustc-hash = "1.1.0" semver = "1.0.14" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" smallvec = { version = "1.10.0", features = [ - "const_new", - "union", - "const_generics", + "const_new", + "union", + "const_generics", ] } -smol_str = "0.2.0" +smol_str = "0.2.1" text-size = "1.1.1" tracing = "0.1.40" tracing-tree = "0.3.0" tracing-subscriber = { version = "0.3.18", default-features = false, features = [ - "registry", - "fmt", - "tracing-log", + "registry", + "fmt", + "tracing-log", ] } triomphe = { version = "0.1.10", default-features = false, features = ["std"] } xshell = "0.2.5" @@ -138,8 +139,48 @@ xshell = "0.2.5" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.5.3", features = ["raw-api"] } +[workspace.lints.rust] +rust_2018_idioms = "warn" +unused_lifetimes = "warn" +semicolon_in_expressions_from_macros = "warn" + [workspace.lints.clippy] -collapsible_if = "allow" -needless_pass_by_value = "allow" -nonminimal_bool = "allow" -redundant_pattern_matching = "allow" +# FIXME Remove the tidy test once the lint table is stable + +## lint groups +complexity = { level = "warn", priority = -1 } +correctness = { level = "deny", priority = -1 } +perf = { level = "deny", priority = -1 } +restriction = { level = "allow", priority = -1 } +style = { level = "warn", priority = -1 } +suspicious = { level = "warn", priority = -1 } + +## allow following lints +# () makes a fine error in most cases +result_unit_err = "allow" +# We don't expose public APIs that matter like this +len_without_is_empty = "allow" +# We have macros that rely on this currently +enum_variant_names = "allow" +# Builder pattern disagrees +new_ret_no_self = "allow" + +## Following lints should be tackled at some point +borrowed_box = "allow" +derived_hash_with_manual_eq = "allow" +forget_non_drop = "allow" +needless_doctest_main = "allow" +non_canonical_clone_impl = "allow" +non_canonical_partial_ord_impl = "allow" +self_named_constructors = "allow" +too_many_arguments = "allow" +type_complexity = "allow" +wrong_self_convention = "allow" + +## warn at following lints +dbg_macro = "warn" +todo = "warn" +unimplemented = "allow" +rc_buffer = "warn" +# FIXME enable this, we use this pattern a lot so its annoying work ... +# str_to_string = "warn" diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 1aa43175f90b2..485ba78846a85 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -17,6 +17,7 @@ rust-analyzer-salsa.workspace = true rustc-hash.workspace = true triomphe.workspace = true semver.workspace = true +tracing.workspace = true # local deps cfg.workspace = true @@ -27,4 +28,4 @@ vfs.workspace = true span.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs index 4332e572e2092..003ffb24d9d0d 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs @@ -51,7 +51,7 @@ impl FileChange { } pub fn apply(self, db: &mut dyn SourceDatabaseExt) { - let _p = profile::span("RootDatabase::apply_change"); + let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered(); if let Some(roots) = self.roots { for (idx, root) in roots.into_iter().enumerate() { let root_id = SourceRootId(idx as u32); diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index e45a81238ac9b..51e6fdb9510a8 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -9,7 +9,7 @@ use std::{fmt, mem, ops, str::FromStr}; use cfg::CfgOptions; -use la_arena::{Arena, Idx}; +use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use syntax::SmolStr; @@ -157,6 +157,10 @@ impl CrateOrigin { pub fn is_lib(&self) -> bool { matches!(self, CrateOrigin::Library { .. }) } + + pub fn is_lang(&self) -> bool { + matches!(self, CrateOrigin::Lang { .. }) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -174,7 +178,7 @@ impl From<&str> for LangCrateOrigin { match s { "alloc" => LangCrateOrigin::Alloc, "core" => LangCrateOrigin::Core, - "proc-macro" => LangCrateOrigin::ProcMacro, + "proc-macro" | "proc_macro" => LangCrateOrigin::ProcMacro, "std" => LangCrateOrigin::Std, "test" => LangCrateOrigin::Test, _ => LangCrateOrigin::Other, @@ -257,6 +261,7 @@ impl ReleaseChannel { } } + #[allow(clippy::should_implement_trait)] pub fn from_str(str: &str) -> Option { Some(match str { "" | "stable" => ReleaseChannel::Stable, @@ -326,7 +331,7 @@ impl CrateData { return false; } - if let Some(_) = opts.next() { + if opts.next().is_some() { return false; } } @@ -489,7 +494,7 @@ impl CrateGraph { from: CrateId, dep: Dependency, ) -> Result<(), CyclicDependenciesError> { - let _p = profile::span("add_dep"); + let _p = tracing::span!(tracing::Level::INFO, "add_dep").entered(); self.check_cycle_after_dependency(from, dep.crate_id)?; @@ -522,7 +527,7 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } - // FIXME: used for `handle_hack_cargo_workspace`, should be removed later + // FIXME: used for fixing up the toolchain sysroot, should be removed and done differently #[doc(hidden)] pub fn iter_mut(&mut self) -> impl Iterator + '_ { self.arena.iter_mut() @@ -619,7 +624,12 @@ impl CrateGraph { /// This will deduplicate the crates of the graph where possible. /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted. - pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { + pub fn extend( + &mut self, + mut other: CrateGraph, + proc_macros: &mut ProcMacroPaths, + on_finished: impl FnOnce(&FxHashMap), + ) { let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap = FxHashMap::default(); for topo in topo { @@ -630,7 +640,7 @@ impl CrateGraph { let res = self.arena.iter().find_map(|(id, data)| { match (&data.origin, &crate_data.origin) { (a, b) if a == b => { - if data.eq_ignoring_origin_and_deps(&crate_data, false) { + if data.eq_ignoring_origin_and_deps(crate_data, false) { return Some((id, false)); } } @@ -642,8 +652,8 @@ impl CrateGraph { // version and discard the library one as the local version may have // dev-dependencies that we want to keep resolving. See #15656 for more // information. - if data.eq_ignoring_origin_and_deps(&crate_data, true) { - return Some((id, if a.is_local() { false } else { true })); + if data.eq_ignoring_origin_and_deps(crate_data, true) { + return Some((id, !a.is_local())); } } (_, _) => return None, @@ -670,6 +680,8 @@ impl CrateGraph { *proc_macros = mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect(); + + on_finished(&id_map); } fn find_path( @@ -721,6 +733,29 @@ impl CrateGraph { fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator + 'a { self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name)) } + + /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies. + /// Returns a mapping from old crate ids to new crate ids. + pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec> { + let mut id_map = vec![None; self.arena.len()]; + self.arena = std::mem::take(&mut self.arena) + .into_iter() + .filter_map(|(id, data)| if to_keep.contains(&id) { Some((id, data)) } else { None }) + .enumerate() + .map(|(new_id, (id, data))| { + id_map[id.into_raw().into_u32() as usize] = + Some(CrateId::from_raw(RawIdx::from_u32(new_id as u32))); + data + }) + .collect(); + for (_, data) in self.arena.iter_mut() { + data.dependencies.iter_mut().for_each(|dep| { + dep.crate_id = + id_map[dep.crate_id.into_raw().into_u32() as usize].expect("crate was filtered") + }); + } + id_map + } } impl ops::Index for CrateGraph { diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 92d2b9c3f57c9..d7fc9d4c95cd6 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -2,8 +2,8 @@ #![warn(rust_2018_idioms, unused_lifetimes)] -mod input; mod change; +mod input; use std::panic; @@ -65,7 +65,7 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { } fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse { - let _p = profile::span("parse_query").detail(|| format!("{file_id:?}")); + let _p = tracing::span!(tracing::Level::INFO, "parse_query", ?file_id).entered(); let text = db.file_text(file_id); SourceFile::parse(&text) } @@ -116,7 +116,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { } fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { - let _p = profile::span("relevant_crates"); + let _p = tracing::span!(tracing::Level::INFO, "relevant_crates").entered(); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) } diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs index fb7505ba2dd5b..4be6ae7481d8e 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs @@ -18,28 +18,6 @@ pub enum CfgAtom { KeyValue { key: SmolStr, value: SmolStr }, } -impl CfgAtom { - /// Returns `true` when the atom comes from the target specification. - /// - /// If this returns `true`, then changing this atom requires changing the compilation target. If - /// it returns `false`, the atom might come from a build script or the build system. - pub fn is_target_defined(&self) -> bool { - match self { - CfgAtom::Flag(flag) => matches!(&**flag, "unix" | "windows"), - CfgAtom::KeyValue { key, value: _ } => matches!( - &**key, - "target_arch" - | "target_os" - | "target_env" - | "target_family" - | "target_endian" - | "target_pointer_width" - | "target_vendor" // NOTE: `target_feature` is left out since it can be configured via `-Ctarget-feature` - ), - } - } -} - impl fmt::Display for CfgAtom { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 6b178e7b04a76..454d6fc5384ba 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -131,11 +131,9 @@ impl CfgDiff { /// of both. pub fn new(enable: Vec, disable: Vec) -> Option { let mut occupied = FxHashSet::default(); - for item in enable.iter().chain(disable.iter()) { - if !occupied.insert(item) { - // was present - return None; - } + if enable.iter().chain(disable.iter()).any(|item| !occupied.insert(item)) { + // was present + return None; } Some(CfgDiff { enable, disable }) diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index 68faca51e8263..22603842a1b6b 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -493,7 +493,9 @@ impl CargoActor { // Skip certain kinds of messages to only spend time on what's useful JsonMessage::Cargo(message) => match message { cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => { - self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap(); + self.sender + .send(CargoMessage::CompilerArtifact(Box::new(artifact))) + .unwrap(); } cargo_metadata::Message::CompilerMessage(msg) => { self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap(); @@ -538,7 +540,7 @@ impl CargoActor { } enum CargoMessage { - CompilerArtifact(cargo_metadata::Artifact), + CompilerArtifact(Box), Diagnostic(Diagnostic), } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 30452e34aac36..bee6f0083b1e4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -24,14 +24,15 @@ use triomphe::Arc; use crate::{ db::DefDatabase, - item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, + item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeModItemNode}, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, - AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId, - LocalFieldId, Lookup, MacroId, VariantId, + AdtId, AssocItemLoc, AttrDefId, GenericParamId, ItemLoc, LocalFieldId, Lookup, MacroId, + VariantId, }; +/// Desugared attributes of an item post `cfg_attr` expansion. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Attrs(RawAttrs); @@ -70,67 +71,22 @@ impl ops::Deref for AttrsWithOwner { impl Attrs { pub const EMPTY: Self = Self(RawAttrs::EMPTY); - pub(crate) fn variants_attrs_query( - db: &dyn DefDatabase, - e: EnumId, - ) -> Arc> { - let _p = profile::span("variants_attrs_query"); - // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids - let mut res = ArenaMap::default(); - - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let enum_ = &item_tree[loc.id.value]; - let crate_graph = db.crate_graph(); - let cfg_options = &crate_graph[krate].cfg_options; - - let mut idx = 0; - for variant in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); - idx += 1; - } - } - - Arc::new(res) - } - pub(crate) fn fields_attrs_query( db: &dyn DefDatabase, v: VariantId, ) -> Arc> { - let _p = profile::span("fields_attrs_query"); + let _p = tracing::span!(tracing::Level::INFO, "fields_attrs_query").entered(); // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); let crate_graph = db.crate_graph(); let (fields, item_tree, krate) = match v { VariantId::EnumVariantId(it) => { - let e = it.parent; - let loc = e.lookup(db); - let krate = loc.container.krate; + let loc = it.lookup(db); + let krate = loc.parent.lookup(db).container.krate; let item_tree = loc.id.item_tree(db); - let enum_ = &item_tree[loc.id.value]; - - let cfg_options = &crate_graph[krate].cfg_options; - - let Some(variant) = enum_ - .variants - .clone() - .filter(|variant| { - let attrs = item_tree.attrs(db, krate, (*variant).into()); - attrs.is_cfg_enabled(cfg_options) - }) - .zip(0u32..) - .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx))) - .map(|(variant, _idx)| variant) - else { - return Arc::new(res); - }; - - (item_tree[variant].fields.clone(), item_tree, krate) + let variant = &item_tree[loc.id.value]; + (variant.fields.clone(), item_tree, krate) } VariantId::StructId(it) => { let loc = it.lookup(db); @@ -273,7 +229,6 @@ pub enum DocAtom { KeyValue { key: SmolStr, value: SmolStr }, } -// Adapted from `CfgExpr` parsing code #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum DocExpr { Invalid, @@ -367,7 +322,7 @@ impl AttrsWithOwner { } pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { - let _p = profile::span("attrs_query"); + let _p = tracing::span!(tracing::Level::INFO, "attrs_query").entered(); // FIXME: this should use `Trace` to avoid duplication in `source_map` below let raw_attrs = match def { AttrDefId::ModuleId(module) => { @@ -401,10 +356,12 @@ impl AttrsWithOwner { AttrDefId::FieldId(it) => { return db.fields_attrs(it.parent)[it.local_id].clone(); } + // FIXME: DRY this up AttrDefId::EnumVariantId(it) => { - return db.variants_attrs(it.parent)[it.local_id].clone(); + let id = it.lookup(db).id; + let tree = id.item_tree(db); + tree.raw_attrs(id.value.into()).clone() } - // FIXME: DRY this up AttrDefId::AdtId(it) => match it { AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), @@ -491,10 +448,7 @@ impl AttrsWithOwner { let map = db.fields_attrs_source_map(id.parent); let file_id = id.parent.file_id(db); let root = db.parse_or_expand(file_id); - let owner = match &map[id.local_id] { - Either::Left(it) => ast::AnyHasAttrs::new(it.to_node(&root)), - Either::Right(it) => ast::AnyHasAttrs::new(it.to_node(&root)), - }; + let owner = ast::AnyHasAttrs::new(map[id.local_id].to_node(&root)); InFile::new(file_id, owner) } AttrDefId::AdtId(adt) => match adt { @@ -503,12 +457,7 @@ impl AttrsWithOwner { AdtId::EnumId(id) => any_has_attrs(db, id), }, AttrDefId::FunctionId(id) => any_has_attrs(db, id), - AttrDefId::EnumVariantId(id) => { - let map = db.variants_attrs_source_map(id.parent); - let file_id = id.parent.lookup(db).id.file_id(); - let root = db.parse_or_expand(file_id); - InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root))) - } + AttrDefId::EnumVariantId(id) => any_has_attrs(db, id), AttrDefId::StaticId(id) => any_has_attrs(db, id), AttrDefId::ConstId(id) => any_has_attrs(db, id), AttrDefId::TraitId(id) => any_has_attrs(db, id), @@ -654,13 +603,16 @@ fn any_has_attrs<'db>( id.lookup(db).source(db).map(ast::AnyHasAttrs::new) } -fn attrs_from_item_tree(db: &dyn DefDatabase, id: ItemTreeId) -> RawAttrs { +fn attrs_from_item_tree( + db: &dyn DefDatabase, + id: ItemTreeId, +) -> RawAttrs { let tree = id.item_tree(db); let mod_item = N::id_to_mod_item(id.value); tree.raw_attrs(mod_item.into()).clone() } -fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( +fn attrs_from_item_tree_loc<'db, N: ItemTreeModItemNode>( db: &(dyn DefDatabase + 'db), lookup: impl Lookup = dyn DefDatabase + 'db, Data = ItemLoc>, ) -> RawAttrs { @@ -668,7 +620,7 @@ fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( attrs_from_item_tree(db, id) } -fn attrs_from_item_tree_assoc<'db, N: ItemTreeNode>( +fn attrs_from_item_tree_assoc<'db, N: ItemTreeModItemNode>( db: &(dyn DefDatabase + 'db), lookup: impl Lookup = dyn DefDatabase + 'db, Data = AssocItemLoc>, ) -> RawAttrs { @@ -676,24 +628,10 @@ fn attrs_from_item_tree_assoc<'db, N: ItemTreeNode>( attrs_from_item_tree(db, id) } -pub(crate) fn variants_attrs_source_map( - db: &dyn DefDatabase, - def: EnumId, -) -> Arc>> { - let mut res = ArenaMap::default(); - let child_source = def.child_source(db); - - for (idx, variant) in child_source.value.iter() { - res.insert(idx, AstPtr::new(variant)); - } - - Arc::new(res) -} - pub(crate) fn fields_attrs_source_map( db: &dyn DefDatabase, def: VariantId, -) -> Arc, AstPtr>>> { +) -> Arc>>> { let mut res = ArenaMap::default(); let child_source = def.child_source(db); @@ -702,7 +640,7 @@ pub(crate) fn fields_attrs_source_map( idx, variant .as_ref() - .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))), + .either(|l| AstPtr::new(l).wrap_left(), |r| AstPtr::new(r).wrap_right()), ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index db28c6731ece1..ce8a9eab14a9d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -1,10 +1,10 @@ //! Defines `Body`: a lowered representation of bodies of functions, statics and //! consts. mod lower; +mod pretty; +pub mod scope; #[cfg(test)] mod tests; -pub mod scope; -mod pretty; use std::ops::Index; @@ -26,7 +26,7 @@ use crate::{ }, nameres::DefMap, path::{ModPath, Path}, - src::{HasChildSource, HasSource}, + src::HasSource, BlockId, DefWithBodyId, HasModule, Lookup, }; @@ -37,7 +37,7 @@ pub struct Body { pub pats: Arena, pub bindings: Arena, pub labels: Arena

{ @@ -752,11 +759,11 @@ impl Evaluator<'_> { Variants::Multiple { variants, .. } => { &variants[match f.parent { hir_def::VariantId::EnumVariantId(it) => { - RustcEnumVariantIdx(it.local_id) + RustcEnumVariantIdx(it.lookup(self.db.upcast()).index as usize) } _ => { - return Err(MirEvalError::TypeError( - "Multivariant layout only happens for enums", + return Err(MirEvalError::InternalError( + "mismatched layout".into(), )) } }] @@ -816,8 +823,8 @@ impl Evaluator<'_> { }) } - fn interpret_mir<'slf>( - &'slf mut self, + fn interpret_mir( + &mut self, body: Arc, args: impl Iterator, ) -> Result { @@ -837,7 +844,7 @@ impl Evaluator<'_> { not_supported!("missing stack frame"); }; let e = (|| { - let mut locals = &mut my_stack_frame.locals; + let locals = &mut my_stack_frame.locals; let body = locals.body.clone(); loop { let current_block = &body.basic_blocks[current_block_idx]; @@ -849,12 +856,10 @@ impl Evaluator<'_> { for statement in ¤t_block.statements { match &statement.kind { StatementKind::Assign(l, r) => { - let addr = self.place_addr(l, &locals)?; - let result = self.eval_rvalue(r, &mut locals)?; + let addr = self.place_addr(l, locals)?; + let result = self.eval_rvalue(r, locals)?; self.copy_from_interval_or_owned(addr, result)?; - locals - .drop_flags - .add_place(l.clone(), &locals.body.projection_store); + locals.drop_flags.add_place(*l, &locals.body.projection_store); } StatementKind::Deinit(_) => not_supported!("de-init statement"), StatementKind::StorageLive(_) @@ -878,20 +883,20 @@ impl Evaluator<'_> { cleanup: _, from_hir_call: _, } => { - let destination_interval = self.place_interval(destination, &locals)?; - let fn_ty = self.operand_ty(func, &locals)?; + let destination_interval = self.place_interval(destination, locals)?; + let fn_ty = self.operand_ty(func, locals)?; let args = args .iter() - .map(|it| self.operand_ty_and_eval(it, &mut locals)) + .map(|it| self.operand_ty_and_eval(it, locals)) .collect::>>()?; let stack_frame = match &fn_ty.kind(Interner) { TyKind::Function(_) => { - let bytes = self.eval_operand(func, &mut locals)?; + let bytes = self.eval_operand(func, locals)?; self.exec_fn_pointer( bytes, destination_interval, &args, - &locals, + locals, *target, terminator.span, )? @@ -901,7 +906,7 @@ impl Evaluator<'_> { generic_args, destination_interval, &args, - &locals, + locals, *target, terminator.span, )?, @@ -909,7 +914,7 @@ impl Evaluator<'_> { }; locals .drop_flags - .add_place(destination.clone(), &locals.body.projection_store); + .add_place(*destination, &locals.body.projection_store); if let Some(stack_frame) = stack_frame { self.code_stack.push(my_stack_frame); current_block_idx = stack_frame.locals.body.start_block; @@ -924,7 +929,7 @@ impl Evaluator<'_> { } TerminatorKind::SwitchInt { discr, targets } => { let val = u128::from_le_bytes(pad16( - self.eval_operand(discr, &mut locals)?.get(&self)?, + self.eval_operand(discr, locals)?.get(self)?, false, )); current_block_idx = targets.target_for_value(val); @@ -938,7 +943,7 @@ impl Evaluator<'_> { )); } TerminatorKind::Drop { place, target, unwind: _ } => { - self.drop_place(place, &mut locals, terminator.span)?; + self.drop_place(place, locals, terminator.span)?; current_block_idx = *target; } _ => not_supported!("unknown terminator"), @@ -996,12 +1001,12 @@ impl Evaluator<'_> { IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?, } if remain_args == 0 { - return Err(MirEvalError::TypeError("more arguments provided")); + return Err(MirEvalError::InternalError("too many arguments".into())); } remain_args -= 1; } if remain_args > 0 { - return Err(MirEvalError::TypeError("not enough arguments provided")); + return Err(MirEvalError::InternalError("too few arguments".into())); } Ok(()) } @@ -1074,14 +1079,14 @@ impl Evaluator<'_> { match metadata { Some(m) => m, None => { - return Err(MirEvalError::TypeError( - "type without metadata is used for Rvalue::Len", + return Err(MirEvalError::InternalError( + "type without metadata is used for Rvalue::Len".into(), )); } } } Rvalue::UnaryOp(op, val) => { - let mut c = self.eval_operand(val, locals)?.get(&self)?; + let mut c = self.eval_operand(val, locals)?.get(self)?; let mut ty = self.operand_ty(val, locals)?; while let TyKind::Ref(_, _, z) = ty.kind(Interner) { ty = z.clone(); @@ -1124,8 +1129,8 @@ impl Evaluator<'_> { Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: { let lc = self.eval_operand(lhs, locals)?; let rc = self.eval_operand(rhs, locals)?; - let mut lc = lc.get(&self)?; - let mut rc = rc.get(&self)?; + let mut lc = lc.get(self)?; + let mut rc = rc.get(self)?; let mut ty = self.operand_ty(lhs, locals)?; while let TyKind::Ref(_, _, z) = ty.kind(Interner) { ty = z.clone(); @@ -1277,12 +1282,12 @@ impl Evaluator<'_> { } Rvalue::Discriminant(p) => { let ty = self.place_ty(p, locals)?; - let bytes = self.eval_place(p, locals)?.get(&self)?; + let bytes = self.eval_place(p, locals)?.get(self)?; let result = self.compute_discriminant(ty, bytes)?; Owned(result.to_le_bytes().to_vec()) } Rvalue::Repeat(it, len) => { - let len = match try_const_usize(self.db, &len) { + let len = match try_const_usize(self.db, len) { Some(it) => it as usize, None => not_supported!("non evaluatable array len in repeat Rvalue"), }; @@ -1308,14 +1313,14 @@ impl Evaluator<'_> { AggregateKind::Array(_) => { let mut r = vec![]; for it in values { - let value = it.get(&self)?; + let value = it.get(self)?; r.extend(value); } Owned(r) } AggregateKind::Tuple(ty) => { - let layout = self.layout(&ty)?; - Owned(self.make_by_layout( + let layout = self.layout(ty)?; + Owned(self.construct_with_layout( layout.size.bytes_usize(), &layout, None, @@ -1329,7 +1334,7 @@ impl Evaluator<'_> { .fields .offset(u32::from(f.local_id.into_raw()) as usize) .bytes_usize(); - let op = values[0].get(&self)?; + let op = values[0].get(self)?; let mut result = vec![0; layout.size.bytes_usize()]; result[offset..offset + op.len()].copy_from_slice(op); Owned(result) @@ -1337,7 +1342,7 @@ impl Evaluator<'_> { AggregateKind::Adt(it, subst) => { let (size, variant_layout, tag) = self.layout_of_variant(*it, subst.clone(), locals)?; - Owned(self.make_by_layout( + Owned(self.construct_with_layout( size, &variant_layout, tag, @@ -1345,8 +1350,8 @@ impl Evaluator<'_> { )?) } AggregateKind::Closure(ty) => { - let layout = self.layout(&ty)?; - Owned(self.make_by_layout( + let layout = self.layout(ty)?; + Owned(self.construct_with_layout( layout.size.bytes_usize(), &layout, None, @@ -1390,14 +1395,11 @@ impl Evaluator<'_> { | CastKind::PointerExposeAddress | CastKind::PointerFromExposedAddress => { let current_ty = self.operand_ty(operand, locals)?; - let is_signed = match current_ty.kind(Interner) { - TyKind::Scalar(s) => match s { - chalk_ir::Scalar::Int(_) => true, - _ => false, - }, - _ => false, - }; - let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, is_signed); + let is_signed = matches!( + current_ty.kind(Interner), + TyKind::Scalar(chalk_ir::Scalar::Int(_)) + ); + let current = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed); let dest_size = self.size_of_sized(target_ty, locals, "destination of int to int cast")?; Owned(current[0..dest_size].to_vec()) @@ -1412,29 +1414,16 @@ impl Evaluator<'_> { fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result { let layout = self.layout(&ty)?; - let enum_id = 'b: { - match ty.kind(Interner) { - TyKind::Adt(e, _) => match e.0 { - AdtId::EnumId(e) => break 'b e, - _ => (), - }, - _ => (), - } + let &TyKind::Adt(chalk_ir::AdtId(AdtId::EnumId(e)), _) = ty.kind(Interner) else { return Ok(0); }; match &layout.variants { Variants::Single { index } => { - let r = self.const_eval_discriminant(EnumVariantId { - parent: enum_id, - local_id: index.0, - })?; + let r = self.const_eval_discriminant(self.db.enum_data(e).variants[index.0].0)?; Ok(r) } Variants::Multiple { tag, tag_encoding, variants, .. } => { - let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else { - not_supported!("missing target data layout"); - }; - let size = tag.size(&*target_data_layout).bytes_usize(); + let size = tag.size(&*self.target_data_layout).bytes_usize(); let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field match tag_encoding { TagEncoding::Direct => { @@ -1446,17 +1435,15 @@ impl Evaluator<'_> { let candidate_tag = i128::from_le_bytes(pad16(tag, false)) .wrapping_sub(*niche_start as i128) as usize; - let variant = variants + let idx = variants .iter_enumerated() .map(|(it, _)| it) .filter(|it| it != untagged_variant) .nth(candidate_tag) .unwrap_or(*untagged_variant) .0; - let result = self.const_eval_discriminant(EnumVariantId { - parent: enum_id, - local_id: variant, - })?; + let result = + self.const_eval_discriminant(self.db.enum_data(e).variants[idx].0)?; Ok(result) } } @@ -1476,9 +1463,8 @@ impl Evaluator<'_> { if let TyKind::Adt(id, subst) = kind { if let AdtId::StructId(struct_id) = id.0 { let field_types = self.db.field_types(struct_id.into()); - let mut field_types = field_types.iter(); if let Some(ty) = - field_types.next().map(|it| it.1.clone().substitute(Interner, subst)) + field_types.iter().last().map(|it| it.1.clone().substitute(Interner, subst)) { return self.coerce_unsized_look_through_fields(&ty, goal); } @@ -1525,7 +1511,7 @@ impl Evaluator<'_> { let mut r = Vec::with_capacity(16); let addr = addr.get(self)?; r.extend(addr.iter().copied()); - r.extend(len.to_le_bytes().into_iter()); + r.extend(len.to_le_bytes()); Owned(r) } t => { @@ -1537,7 +1523,7 @@ impl Evaluator<'_> { let mut r = Vec::with_capacity(16); let addr = addr.get(self)?; r.extend(addr.iter().copied()); - r.extend(vtable.to_le_bytes().into_iter()); + r.extend(vtable.to_le_bytes()); Owned(r) } TyKind::Adt(id, target_subst) => match ¤t_ty.kind(Interner) { @@ -1551,7 +1537,7 @@ impl Evaluator<'_> { AdtId::EnumId(_) => not_supported!("unsizing enums"), }; let Some((last_field, _)) = - self.db.struct_data(id).variant_data.fields().iter().rev().next() + self.db.struct_data(id).variant_data.fields().iter().next_back() else { not_supported!("unsizing struct without field"); }; @@ -1579,14 +1565,16 @@ impl Evaluator<'_> { subst: Substitution, locals: &Locals, ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { - let adt = it.adt_id(); + let adt = it.adt_id(self.db.upcast()); if let DefWithBodyId::VariantId(f) = locals.body.owner { if let VariantId::EnumVariantId(it) = it { - if AdtId::from(f.parent) == adt { - // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and - // infinite sized type errors) we use a dummy layout - let i = self.const_eval_discriminant(it)?; - return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); + if let AdtId::EnumId(e) = adt { + if f.lookup(self.db.upcast()).parent == e { + // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and + // infinite sized type errors) we use a dummy layout + let i = self.const_eval_discriminant(it)?; + return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); + } } } } @@ -1594,16 +1582,13 @@ impl Evaluator<'_> { Ok(match &layout.variants { Variants::Single { .. } => (layout.size.bytes_usize(), layout, None), Variants::Multiple { variants, tag, tag_encoding, .. } => { - let cx = self - .db - .target_data_layout(self.crate_id) - .ok_or(MirEvalError::TargetDataLayoutNotAvailable)?; let enum_variant_id = match it { VariantId::EnumVariantId(it) => it, _ => not_supported!("multi variant layout for non-enums"), }; - let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.local_id); let mut discriminant = self.const_eval_discriminant(enum_variant_id)?; + let lookup = enum_variant_id.lookup(self.db.upcast()); + let rustc_enum_variant_idx = RustcEnumVariantIdx(lookup.index as usize); let variant_layout = variants[rustc_enum_variant_idx].clone(); let have_tag = match tag_encoding { TagEncoding::Direct => true, @@ -1627,7 +1612,7 @@ impl Evaluator<'_> { if have_tag { Some(( layout.fields.offset(0).bytes_usize(), - tag.size(&*cx).bytes_usize(), + tag.size(&*self.target_data_layout).bytes_usize(), discriminant, )) } else { @@ -1638,7 +1623,7 @@ impl Evaluator<'_> { }) } - fn make_by_layout( + fn construct_with_layout( &mut self, size: usize, // Not necessarily equal to variant_layout.size variant_layout: &Layout, @@ -1649,15 +1634,26 @@ impl Evaluator<'_> { if let Some((offset, size, value)) = tag { match result.get_mut(offset..offset + size) { Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]), - None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))), + None => { + return Err(MirEvalError::InternalError( + format!( + "encoded tag ({offset}, {size}, {value}) is out of bounds 0..{size}" + ) + .into(), + )) + } } } for (i, op) in values.enumerate() { let offset = variant_layout.fields.offset(i).bytes_usize(); - let op = op.get(&self)?; + let op = op.get(self)?; match result.get_mut(offset..offset + op.len()) { Some(it) => it.copy_from_slice(op), - None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))), + None => { + return Err(MirEvalError::InternalError( + format!("field offset ({offset}) is out of bounds 0..{size}").into(), + )) + } } } Ok(result) @@ -1677,6 +1673,7 @@ impl Evaluator<'_> { }) } + #[allow(clippy::double_parens)] fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result { let ty = &konst.data(Interner).ty; let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else { @@ -1695,7 +1692,7 @@ impl Evaluator<'_> { } result_owner = self .db - .const_eval(const_id.into(), subst, Some(self.trait_env.clone())) + .const_eval(const_id, subst, Some(self.trait_env.clone())) .map_err(|e| { let name = const_id.name(self.db.upcast()); MirEvalError::ConstEvalError(name, Box::new(e)) @@ -1709,28 +1706,29 @@ impl Evaluator<'_> { } ConstScalar::Unknown => not_supported!("evaluating unknown const"), }; - let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); let patch_map = memory_map.transform_addresses(|b, align| { let addr = self.heap_allocate(b.len(), align)?; self.write_memory(addr, b)?; Ok(addr.to_usize()) })?; let (size, align) = self.size_align_of(ty, locals)?.unwrap_or((v.len(), 1)); - if size != v.len() { + let v: Cow<'_, [u8]> = if size != v.len() { // Handle self enum if size == 16 && v.len() < 16 { - v = Cow::Owned(pad16(&v, false).to_vec()); + Cow::Owned(pad16(v, false).to_vec()) } else if size < 16 && v.len() == 16 { - v = Cow::Owned(v[0..size].to_vec()); + Cow::Borrowed(&v[0..size]) } else { return Err(MirEvalError::InvalidConst(konst.clone())); } - } + } else { + Cow::Borrowed(v) + }; let addr = self.heap_allocate(size, align)?; self.write_memory(addr, &v)?; self.patch_addresses( &patch_map, - |bytes| match &memory_map { + |bytes| match memory_map { MemoryMap::Empty | MemoryMap::Simple(_) => { Err(MirEvalError::InvalidVTableId(from_bytes!(usize, bytes))) } @@ -1778,9 +1776,8 @@ impl Evaluator<'_> { ))); } }; - Ok(mem.get_mut(pos..pos + size).ok_or_else(|| { - MirEvalError::UndefinedBehavior("out of bound memory write".to_string()) - })?) + mem.get_mut(pos..pos + size) + .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory write".to_string())) } fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> { @@ -1847,8 +1844,8 @@ impl Evaluator<'_> { .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); } if let DefWithBodyId::VariantId(f) = locals.body.owner { - if let Some((adt, _)) = ty.as_adt() { - if AdtId::from(f.parent) == adt { + if let Some((AdtId::EnumId(e), _)) = ty.as_adt() { + if f.lookup(self.db.upcast()).parent == e { // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and // infinite sized type errors) we use a dummy size return Ok(Some((16, 16))); @@ -1856,10 +1853,10 @@ impl Evaluator<'_> { } } let layout = self.layout(ty); - if self.assert_placeholder_ty_is_unused { - if matches!(layout, Err(MirEvalError::LayoutError(LayoutError::HasPlaceholder, _))) { - return Ok(Some((0, 1))); - } + if self.assert_placeholder_ty_is_unused + && matches!(layout, Err(MirEvalError::LayoutError(LayoutError::HasPlaceholder, _))) + { + return Ok(Some((0, 1))); } let layout = layout?; Ok(layout @@ -1969,14 +1966,14 @@ impl Evaluator<'_> { if let Some(ty) = check_inner { for i in 0..count { let offset = element_size * i; - rec(this, &b[offset..offset + element_size], &ty, locals, mm)?; + rec(this, &b[offset..offset + element_size], ty, locals, mm)?; } } } } } chalk_ir::TyKind::Array(inner, len) => { - let len = match try_const_usize(this.db, &len) { + let len = match try_const_usize(this.db, len) { Some(it) => it as usize, None => not_supported!("non evaluatable array len in patching addresses"), }; @@ -2015,14 +2012,12 @@ impl Evaluator<'_> { if let Some((v, l)) = detect_variant_from_bytes( &layout, this.db, - this.trait_env.clone(), + &this.target_data_layout, bytes, e, ) { - let data = &this.db.enum_data(e).variants[v].variant_data; - let field_types = this - .db - .field_types(EnumVariantId { parent: e, local_id: v }.into()); + let data = &this.db.enum_variant_data(v).variant_data; + let field_types = this.db.field_types(v.into()); for (f, _) in data.fields().iter() { let offset = l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize(); @@ -2039,7 +2034,7 @@ impl Evaluator<'_> { Ok(()) } let mut mm = ComplexMemoryMap::default(); - rec(&self, bytes, ty, locals, &mut mm)?; + rec(self, bytes, ty, locals, &mut mm)?; Ok(mm) } @@ -2093,14 +2088,13 @@ impl Evaluator<'_> { } AdtId::UnionId(_) => (), AdtId::EnumId(e) => { - if let Some((variant, layout)) = detect_variant_from_bytes( + if let Some((ev, layout)) = detect_variant_from_bytes( &layout, self.db, - self.trait_env.clone(), + &self.target_data_layout, self.read_memory(addr, layout.size.bytes_usize())?, e, ) { - let ev = EnumVariantId { parent: e, local_id: variant }; for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); let ty = ty.clone().substitute(Interner, subst); @@ -2123,7 +2117,7 @@ impl Evaluator<'_> { } } TyKind::Array(inner, len) => { - let len = match try_const_usize(self.db, &len) { + let len = match try_const_usize(self.db, len) { Some(it) => it as usize, None => not_supported!("non evaluatable array len in patching addresses"), }; @@ -2147,8 +2141,8 @@ impl Evaluator<'_> { | TyKind::Str | TyKind::Never | TyKind::Closure(_, _) - | TyKind::Generator(_, _) - | TyKind::GeneratorWitness(_, _) + | TyKind::Coroutine(_, _) + | TyKind::CoroutineWitness(_, _) | TyKind::Foreign(_) | TyKind::Error | TyKind::Placeholder(_) @@ -2171,14 +2165,14 @@ impl Evaluator<'_> { ) -> Result> { let id = from_bytes!(usize, bytes.get(self)?); let next_ty = self.vtable_map.ty(id)?.clone(); - match &next_ty.kind(Interner) { + match next_ty.kind(Interner) { TyKind::FnDef(def, generic_args) => { - self.exec_fn_def(*def, generic_args, destination, args, &locals, target_bb, span) + self.exec_fn_def(*def, generic_args, destination, args, locals, target_bb, span) } TyKind::Closure(id, subst) => { self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span) } - _ => Err(MirEvalError::TypeError("function pointer to non function")), + _ => Err(MirEvalError::InternalError("function pointer to non function".into())), } } @@ -2207,7 +2201,7 @@ impl Evaluator<'_> { closure_data.get(self)?.to_owned() }; let arg_bytes = iter::once(Ok(closure_data)) - .chain(args.iter().map(|it| Ok(it.get(&self)?.to_owned()))) + .chain(args.iter().map(|it| Ok(it.get(self)?.to_owned()))) .collect::>>()?; let interval = self .interpret_mir(mir_body, arg_bytes.into_iter().map(IntervalOrOwned::Owned)) @@ -2235,7 +2229,7 @@ impl Evaluator<'_> { let generic_args = generic_args.clone(); match def { CallableDefId::FunctionId(def) => { - if let Some(_) = self.detect_fn_trait(def) { + if self.detect_fn_trait(def).is_some() { return self.exec_fn_trait( def, args, @@ -2258,8 +2252,8 @@ impl Evaluator<'_> { } CallableDefId::StructId(id) => { let (size, variant_layout, tag) = - self.layout_of_variant(id.into(), generic_args, &locals)?; - let result = self.make_by_layout( + self.layout_of_variant(id.into(), generic_args, locals)?; + let result = self.construct_with_layout( size, &variant_layout, tag, @@ -2270,8 +2264,8 @@ impl Evaluator<'_> { } CallableDefId::EnumVariantId(id) => { let (size, variant_layout, tag) = - self.layout_of_variant(id.into(), generic_args, &locals)?; - let result = self.make_by_layout( + self.layout_of_variant(id.into(), generic_args, locals)?; + let result = self.construct_with_layout( size, &variant_layout, tag, @@ -2365,7 +2359,7 @@ impl Evaluator<'_> { } }), ); - return self.exec_fn_with_args( + self.exec_fn_with_args( def, &args_for_target, generics_for_target, @@ -2373,7 +2367,7 @@ impl Evaluator<'_> { destination, target_bb, span, - ); + ) } MirOrDynIndex::Mir(body) => self.exec_looked_up_function( body, @@ -2425,7 +2419,9 @@ impl Evaluator<'_> { target_bb: Option, span: MirSpan, ) -> Result> { - let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?; + let func = args + .first() + .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?; let mut func_ty = func.ty.clone(); let mut func_data = func.interval; while let TyKind::Ref(_, _, z) = func_ty.kind(Interner) { @@ -2441,25 +2437,10 @@ impl Evaluator<'_> { } match &func_ty.kind(Interner) { TyKind::FnDef(def, subst) => { - return self.exec_fn_def( - *def, - subst, - destination, - &args[1..], - locals, - target_bb, - span, - ); + self.exec_fn_def(*def, subst, destination, &args[1..], locals, target_bb, span) } TyKind::Function(_) => { - return self.exec_fn_pointer( - func_data, - destination, - &args[1..], - locals, - target_bb, - span, - ); + self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span) } TyKind::Closure(closure, subst) => { return self.exec_closure( @@ -2483,7 +2464,7 @@ impl Evaluator<'_> { ) .intern(Interner); let layout = self.layout(&ty)?; - let result = self.make_by_layout( + let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, None, @@ -2495,7 +2476,7 @@ impl Evaluator<'_> { self.write_memory(addr, &result)?; IntervalAndTy { interval: Interval { addr, size }, ty } }; - return self.exec_fn_with_args( + self.exec_fn_with_args( def, &[arg0.clone(), arg1], generic_args, @@ -2503,7 +2484,7 @@ impl Evaluator<'_> { destination, target_bb, span, - ); + ) } } } @@ -2523,7 +2504,7 @@ impl Evaluator<'_> { self.allocate_const_in_heap(locals, &konst)? } else { let ty = &self.db.infer(st.into())[self.db.body(st.into()).body_expr]; - let Some((size, align)) = self.size_align_of(&ty, locals)? else { + let Some((size, align)) = self.size_align_of(ty, locals)? else { not_supported!("unsized extern static"); }; let addr = self.heap_allocate(size, align)?; @@ -2540,11 +2521,13 @@ impl Evaluator<'_> { match r { Ok(r) => Ok(r), Err(e) => { - let data = self.db.enum_data(variant.parent); + let db = self.db.upcast(); + let loc = variant.lookup(db); + let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - data.name.display(self.db.upcast()), - data.variants[variant.local_id].name.display(self.db.upcast()) + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), ); Err(MirEvalError::ConstEvalError(name, Box::new(e))) } @@ -2635,8 +2618,8 @@ impl Evaluator<'_> { | TyKind::Str | TyKind::Never | TyKind::Closure(_, _) - | TyKind::Generator(_, _) - | TyKind::GeneratorWitness(_, _) + | TyKind::Coroutine(_, _) + | TyKind::CoroutineWitness(_, _) | TyKind::Foreign(_) | TyKind::Error | TyKind::Placeholder(_) @@ -2665,7 +2648,7 @@ pub fn render_const_using_debug_impl( owner: ConstId, c: &Const, ) -> Result { - let mut evaluator = Evaluator::new(db, owner.into(), false, None); + let mut evaluator = Evaluator::new(db, owner.into(), false, None)?; let locals = &Locals { ptr: ArenaMap::new(), body: db @@ -2679,7 +2662,7 @@ pub fn render_const_using_debug_impl( db.upcast(), &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( hir_expand::mod_path::PathKind::Abs, - [name![core], name![fmt], name![Debug]].into_iter(), + [name![core], name![fmt], name![Debug]], )), ) else { not_supported!("core::fmt::Debug not found"); @@ -2711,7 +2694,7 @@ pub fn render_const_using_debug_impl( db.upcast(), &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( hir_expand::mod_path::PathKind::Abs, - [name![std], name![fmt], name![format]].into_iter(), + [name![std], name![fmt], name![format]], )), ) else { not_supported!("std::fmt::format not found"); @@ -2730,12 +2713,7 @@ pub fn render_const_using_debug_impl( pub fn pad16(it: &[u8], is_signed: bool) -> [u8; 16] { let is_negative = is_signed && it.last().unwrap_or(&0) > &127; - let fill_with = if is_negative { 255 } else { 0 }; - it.iter() - .copied() - .chain(iter::repeat(fill_with)) - .take(16) - .collect::>() - .try_into() - .expect("iterator take is not working") + let mut res = [if is_negative { 255 } else { 0 }; 16]; + res[..it.len()].copy_from_slice(it); + res } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index ff26a3d0be173..b4fb99acae778 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -18,7 +18,7 @@ macro_rules! from_bytes { ($ty:tt, $value:expr) => { ($ty::from_le_bytes(match ($value).try_into() { Ok(it) => it, - Err(_) => return Err(MirEvalError::TypeError("mismatched size")), + Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())), })) }; } @@ -60,7 +60,7 @@ impl Evaluator<'_> { args, generic_args, destination, - &locals, + locals, span, )?; return Ok(true); @@ -82,7 +82,7 @@ impl Evaluator<'_> { args, generic_args, destination, - &locals, + locals, span, )?; return Ok(true); @@ -100,7 +100,7 @@ impl Evaluator<'_> { args, generic_args, destination, - &locals, + locals, span, )?; return Ok(true); @@ -125,7 +125,7 @@ impl Evaluator<'_> { } if let Some(it) = self.detect_lang_function(def) { let arg_bytes = - args.iter().map(|it| Ok(it.get(&self)?.to_owned())).collect::>>()?; + args.iter().map(|it| Ok(it.get(self)?.to_owned())).collect::>>()?; let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?; destination.write_from_bytes(self, &result)?; return Ok(true); @@ -249,7 +249,9 @@ impl Evaluator<'_> { match alloc_fn { "rustc_allocator_zeroed" | "rustc_allocator" => { let [size, align] = args else { - return Err(MirEvalError::TypeError("rustc_allocator args are not provided")); + return Err(MirEvalError::InternalError( + "rustc_allocator args are not provided".into(), + )); }; let size = from_bytes!(usize, size.get(self)?); let align = from_bytes!(usize, align.get(self)?); @@ -259,7 +261,9 @@ impl Evaluator<'_> { "rustc_deallocator" => { /* no-op for now */ } "rustc_reallocator" => { let [ptr, old_size, align, new_size] = args else { - return Err(MirEvalError::TypeError("rustc_allocator args are not provided")); + return Err(MirEvalError::InternalError( + "rustc_allocator args are not provided".into(), + )); }; let old_size = from_bytes!(usize, old_size.get(self)?); let new_size = from_bytes!(usize, new_size.get(self)?); @@ -313,7 +317,7 @@ impl Evaluator<'_> { &hir_def::path::Path::from_known_path_with_no_generic( ModPath::from_segments( hir_expand::mod_path::PathKind::Abs, - [name![std], name![fmt], name![format]].into_iter(), + [name![std], name![fmt], name![format]], ), ), ) else { @@ -339,22 +343,22 @@ impl Evaluator<'_> { Err(MirEvalError::Panic(message)) } SliceLen => { - let arg = args - .next() - .ok_or(MirEvalError::TypeError("argument of <[T]>::len() is not provided"))?; + let arg = args.next().ok_or(MirEvalError::InternalError( + "argument of <[T]>::len() is not provided".into(), + ))?; let ptr_size = arg.len() / 2; Ok(arg[ptr_size..].into()) } DropInPlace => { let ty = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)).ok_or( - MirEvalError::TypeError( - "generic argument of drop_in_place is not provided", + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)).ok_or( + MirEvalError::InternalError( + "generic argument of drop_in_place is not provided".into(), ), )?; - let arg = args - .next() - .ok_or(MirEvalError::TypeError("argument of drop_in_place is not provided"))?; + let arg = args.next().ok_or(MirEvalError::InternalError( + "argument of drop_in_place is not provided".into(), + ))?; self.run_drop_glue_deep( ty.clone(), locals, @@ -380,7 +384,9 @@ impl Evaluator<'_> { 318 => { // SYS_getrandom let [buf, len, _flags] = args else { - return Err(MirEvalError::TypeError("SYS_getrandom args are not provided")); + return Err(MirEvalError::InternalError( + "SYS_getrandom args are not provided".into(), + )); }; let addr = Address::from_bytes(buf.get(self)?)?; let size = from_bytes!(usize, len.get(self)?); @@ -408,7 +414,7 @@ impl Evaluator<'_> { match as_str { "memcmp" => { let [ptr1, ptr2, size] = args else { - return Err(MirEvalError::TypeError("memcmp args are not provided")); + return Err(MirEvalError::InternalError("memcmp args are not provided".into())); }; let addr1 = Address::from_bytes(ptr1.get(self)?)?; let addr2 = Address::from_bytes(ptr2.get(self)?)?; @@ -424,7 +430,9 @@ impl Evaluator<'_> { } "write" => { let [fd, ptr, len] = args else { - return Err(MirEvalError::TypeError("libc::write args are not provided")); + return Err(MirEvalError::InternalError( + "libc::write args are not provided".into(), + )); }; let fd = u128::from_le_bytes(pad16(fd.get(self)?, false)); let interval = Interval { @@ -445,15 +453,17 @@ impl Evaluator<'_> { } "pthread_key_create" => { let key = self.thread_local_storage.create_key(); - let Some(arg0) = args.get(0) else { - return Err(MirEvalError::TypeError("pthread_key_create arg0 is not provided")); + let Some(arg0) = args.first() else { + return Err(MirEvalError::InternalError( + "pthread_key_create arg0 is not provided".into(), + )); }; let arg0_addr = Address::from_bytes(arg0.get(self)?)?; let key_ty = if let Some((ty, ..)) = arg0.ty.as_reference_or_ptr() { ty } else { - return Err(MirEvalError::TypeError( - "pthread_key_create arg0 is not a pointer", + return Err(MirEvalError::InternalError( + "pthread_key_create arg0 is not a pointer".into(), )); }; let arg0_interval = Interval::new( @@ -466,9 +476,9 @@ impl Evaluator<'_> { Ok(()) } "pthread_getspecific" => { - let Some(arg0) = args.get(0) else { - return Err(MirEvalError::TypeError( - "pthread_getspecific arg0 is not provided", + let Some(arg0) = args.first() else { + return Err(MirEvalError::InternalError( + "pthread_getspecific arg0 is not provided".into(), )); }; let key = from_bytes!(usize, &pad16(arg0.get(self)?, false)[0..8]); @@ -477,15 +487,15 @@ impl Evaluator<'_> { Ok(()) } "pthread_setspecific" => { - let Some(arg0) = args.get(0) else { - return Err(MirEvalError::TypeError( - "pthread_setspecific arg0 is not provided", + let Some(arg0) = args.first() else { + return Err(MirEvalError::InternalError( + "pthread_setspecific arg0 is not provided".into(), )); }; let key = from_bytes!(usize, &pad16(arg0.get(self)?, false)[0..8]); let Some(arg1) = args.get(1) else { - return Err(MirEvalError::TypeError( - "pthread_setspecific arg1 is not provided", + return Err(MirEvalError::InternalError( + "pthread_setspecific arg1 is not provided".into(), )); }; let value = from_bytes!(u128, pad16(arg1.get(self)?, false)); @@ -502,14 +512,16 @@ impl Evaluator<'_> { } "syscall" => { let Some((id, rest)) = args.split_first() else { - return Err(MirEvalError::TypeError("syscall arg1 is not provided")); + return Err(MirEvalError::InternalError("syscall arg1 is not provided".into())); }; let id = from_bytes!(i64, id.get(self)?); self.exec_syscall(id, rest, destination, locals, span) } "sched_getaffinity" => { let [_pid, _set_size, set] = args else { - return Err(MirEvalError::TypeError("libc::write args are not provided")); + return Err(MirEvalError::InternalError( + "libc::write args are not provided".into(), + )); }; let set = Address::from_bytes(set.get(self)?)?; // Only enable core 0 (we are single threaded anyway), which is bitset 0x0000001 @@ -520,7 +532,9 @@ impl Evaluator<'_> { } "getenv" => { let [name] = args else { - return Err(MirEvalError::TypeError("libc::write args are not provided")); + return Err(MirEvalError::InternalError( + "libc::write args are not provided".into(), + )); }; let mut name_buf = vec![]; let name = { @@ -586,8 +600,8 @@ impl Evaluator<'_> { "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => { let [arg] = args else { - return Err(MirEvalError::TypeError( - "f64 intrinsic signature doesn't match fn (f64) -> f64", + return Err(MirEvalError::InternalError( + "f64 intrinsic signature doesn't match fn (f64) -> f64".into(), )); }; let arg = from_bytes!(f64, arg.get(self)?); @@ -614,8 +628,8 @@ impl Evaluator<'_> { } "pow" | "minnum" | "maxnum" | "copysign" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError( - "f64 intrinsic signature doesn't match fn (f64, f64) -> f64", + return Err(MirEvalError::InternalError( + "f64 intrinsic signature doesn't match fn (f64, f64) -> f64".into(), )); }; let arg1 = from_bytes!(f64, arg1.get(self)?); @@ -630,8 +644,8 @@ impl Evaluator<'_> { } "powi" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError( - "powif64 signature doesn't match fn (f64, i32) -> f64", + return Err(MirEvalError::InternalError( + "powif64 signature doesn't match fn (f64, i32) -> f64".into(), )); }; let arg1 = from_bytes!(f64, arg1.get(self)?); @@ -640,8 +654,8 @@ impl Evaluator<'_> { } "fma" => { let [arg1, arg2, arg3] = args else { - return Err(MirEvalError::TypeError( - "fmaf64 signature doesn't match fn (f64, f64, f64) -> f64", + return Err(MirEvalError::InternalError( + "fmaf64 signature doesn't match fn (f64, f64, f64) -> f64".into(), )); }; let arg1 = from_bytes!(f64, arg1.get(self)?); @@ -658,8 +672,8 @@ impl Evaluator<'_> { "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => { let [arg] = args else { - return Err(MirEvalError::TypeError( - "f32 intrinsic signature doesn't match fn (f32) -> f32", + return Err(MirEvalError::InternalError( + "f32 intrinsic signature doesn't match fn (f32) -> f32".into(), )); }; let arg = from_bytes!(f32, arg.get(self)?); @@ -686,8 +700,8 @@ impl Evaluator<'_> { } "pow" | "minnum" | "maxnum" | "copysign" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError( - "f32 intrinsic signature doesn't match fn (f32, f32) -> f32", + return Err(MirEvalError::InternalError( + "f32 intrinsic signature doesn't match fn (f32, f32) -> f32".into(), )); }; let arg1 = from_bytes!(f32, arg1.get(self)?); @@ -702,8 +716,8 @@ impl Evaluator<'_> { } "powi" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError( - "powif32 signature doesn't match fn (f32, i32) -> f32", + return Err(MirEvalError::InternalError( + "powif32 signature doesn't match fn (f32, i32) -> f32".into(), )); }; let arg1 = from_bytes!(f32, arg1.get(self)?); @@ -712,8 +726,8 @@ impl Evaluator<'_> { } "fma" => { let [arg1, arg2, arg3] = args else { - return Err(MirEvalError::TypeError( - "fmaf32 signature doesn't match fn (f32, f32, f32) -> f32", + return Err(MirEvalError::InternalError( + "fmaf32 signature doesn't match fn (f32, f32, f32) -> f32".into(), )); }; let arg1 = from_bytes!(f32, arg1.get(self)?); @@ -728,30 +742,38 @@ impl Evaluator<'_> { match name { "size_of" => { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("size_of generic arg is not provided")); + return Err(MirEvalError::InternalError( + "size_of generic arg is not provided".into(), + )); }; let size = self.size_of_sized(ty, locals, "size_of arg")?; destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } "min_align_of" | "pref_align_of" => { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("align_of generic arg is not provided")); + return Err(MirEvalError::InternalError( + "align_of generic arg is not provided".into(), + )); }; let align = self.layout(ty)?.align.abi.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "size_of_val" => { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("size_of_val generic arg is not provided")); + return Err(MirEvalError::InternalError( + "size_of_val generic arg is not provided".into(), + )); }; let [arg] = args else { - return Err(MirEvalError::TypeError("size_of_val args are not provided")); + return Err(MirEvalError::InternalError( + "size_of_val args are not provided".into(), + )); }; if let Some((size, _)) = self.size_align_of(ty, locals)? { destination.write_from_bytes(self, &size.to_le_bytes()) @@ -763,14 +785,16 @@ impl Evaluator<'_> { } "min_align_of_val" => { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError( - "min_align_of_val generic arg is not provided", + return Err(MirEvalError::InternalError( + "min_align_of_val generic arg is not provided".into(), )); }; let [arg] = args else { - return Err(MirEvalError::TypeError("min_align_of_val args are not provided")); + return Err(MirEvalError::InternalError( + "min_align_of_val args are not provided".into(), + )); }; if let Some((_, align)) = self.size_align_of(ty, locals)? { destination.write_from_bytes(self, &align.to_le_bytes()) @@ -782,9 +806,11 @@ impl Evaluator<'_> { } "type_name" => { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("type_name generic arg is not provided")); + return Err(MirEvalError::InternalError( + "type_name generic arg is not provided".into(), + )); }; let ty_name = match ty.display_source_code( self.db, @@ -806,9 +832,11 @@ impl Evaluator<'_> { } "needs_drop" => { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("size_of generic arg is not provided")); + return Err(MirEvalError::InternalError( + "size_of generic arg is not provided".into(), + )); }; let result = !ty.clone().is_copy(self.db, locals.body.owner); destination.write_from_bytes(self, &[u8::from(result)]) @@ -817,14 +845,18 @@ impl Evaluator<'_> { // FIXME: this is wrong for const eval, it should return 2 in some // cases. let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("wrapping_add args are not provided")); + return Err(MirEvalError::InternalError( + "wrapping_add args are not provided".into(), + )); }; let ans = lhs.get(self)? == rhs.get(self)?; destination.write_from_bytes(self, &[u8::from(ans)]) } "saturating_add" | "saturating_sub" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("saturating_add args are not provided")); + return Err(MirEvalError::InternalError( + "saturating_add args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -844,7 +876,9 @@ impl Evaluator<'_> { } "wrapping_add" | "unchecked_add" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("wrapping_add args are not provided")); + return Err(MirEvalError::InternalError( + "wrapping_add args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -853,16 +887,18 @@ impl Evaluator<'_> { } "ptr_offset_from_unsigned" | "ptr_offset_from" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("wrapping_sub args are not provided")); + return Err(MirEvalError::InternalError( + "wrapping_sub args are not provided".into(), + )); }; let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false)); let ans = lhs.wrapping_sub(rhs); let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError( - "ptr_offset_from generic arg is not provided", + return Err(MirEvalError::InternalError( + "ptr_offset_from generic arg is not provided".into(), )); }; let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128; @@ -871,7 +907,9 @@ impl Evaluator<'_> { } "wrapping_sub" | "unchecked_sub" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("wrapping_sub args are not provided")); + return Err(MirEvalError::InternalError( + "wrapping_sub args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -880,7 +918,9 @@ impl Evaluator<'_> { } "wrapping_mul" | "unchecked_mul" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("wrapping_mul args are not provided")); + return Err(MirEvalError::InternalError( + "wrapping_mul args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -890,7 +930,9 @@ impl Evaluator<'_> { "wrapping_shl" | "unchecked_shl" => { // FIXME: signed let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("unchecked_shl args are not provided")); + return Err(MirEvalError::InternalError( + "unchecked_shl args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -900,7 +942,9 @@ impl Evaluator<'_> { "wrapping_shr" | "unchecked_shr" => { // FIXME: signed let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("unchecked_shr args are not provided")); + return Err(MirEvalError::InternalError( + "unchecked_shr args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -910,7 +954,9 @@ impl Evaluator<'_> { "unchecked_rem" => { // FIXME: signed let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("unchecked_rem args are not provided")); + return Err(MirEvalError::InternalError( + "unchecked_rem args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -922,7 +968,9 @@ impl Evaluator<'_> { "unchecked_div" | "exact_div" => { // FIXME: signed let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("unchecked_div args are not provided")); + return Err(MirEvalError::InternalError( + "unchecked_div args are not provided".into(), + )); }; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); @@ -933,7 +981,9 @@ impl Evaluator<'_> { } "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("const_eval_select args are not provided")); + return Err(MirEvalError::InternalError( + "const_eval_select args are not provided".into(), + )); }; let result_ty = TyKind::Tuple( 2, @@ -954,7 +1004,7 @@ impl Evaluator<'_> { || ans.to_le_bytes()[op_size..].iter().any(|&it| it != 0 && it != 255); let is_overflow = vec![u8::from(is_overflow)]; let layout = self.layout(&result_ty)?; - let result = self.make_by_layout( + let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, None, @@ -966,15 +1016,15 @@ impl Evaluator<'_> { } "copy" | "copy_nonoverlapping" => { let [src, dst, offset] = args else { - return Err(MirEvalError::TypeError( - "copy_nonoverlapping args are not provided", + return Err(MirEvalError::InternalError( + "copy_nonoverlapping args are not provided".into(), )); }; let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError( - "copy_nonoverlapping generic arg is not provided", + return Err(MirEvalError::InternalError( + "copy_nonoverlapping generic arg is not provided".into(), )); }; let src = Address::from_bytes(src.get(self)?)?; @@ -988,18 +1038,22 @@ impl Evaluator<'_> { } "offset" | "arith_offset" => { let [ptr, offset] = args else { - return Err(MirEvalError::TypeError("offset args are not provided")); + return Err(MirEvalError::InternalError("offset args are not provided".into())); }; let ty = if name == "offset" { let Some(ty0) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("offset generic arg is not provided")); + return Err(MirEvalError::InternalError( + "offset generic arg is not provided".into(), + )); }; let Some(ty1) = generic_args.as_slice(Interner).get(1).and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("offset generic arg is not provided")); + return Err(MirEvalError::InternalError( + "offset generic arg is not provided".into(), + )); }; if !matches!( ty1.as_builtin(), @@ -1008,24 +1062,24 @@ impl Evaluator<'_> { | BuiltinType::Uint(BuiltinUint::Usize) ) ) { - return Err(MirEvalError::TypeError( - "offset generic arg is not usize or isize", + return Err(MirEvalError::InternalError( + "offset generic arg is not usize or isize".into(), )); } match ty0.as_raw_ptr() { Some((ty, _)) => ty, None => { - return Err(MirEvalError::TypeError( - "offset generic arg is not a raw pointer", + return Err(MirEvalError::InternalError( + "offset generic arg is not a raw pointer".into(), )); } } } else { let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError( - "arith_offset generic arg is not provided", + return Err(MirEvalError::InternalError( + "arith_offset generic arg is not provided".into(), )); }; ty @@ -1046,19 +1100,21 @@ impl Evaluator<'_> { } "transmute" => { let [arg] = args else { - return Err(MirEvalError::TypeError("transmute arg is not provided")); + return Err(MirEvalError::InternalError( + "transmute arg is not provided".into(), + )); }; destination.write_from_interval(self, arg.interval) } "likely" | "unlikely" => { let [arg] = args else { - return Err(MirEvalError::TypeError("likely arg is not provided")); + return Err(MirEvalError::InternalError("likely arg is not provided".into())); }; destination.write_from_interval(self, arg.interval) } "ctpop" => { let [arg] = args else { - return Err(MirEvalError::TypeError("ctpop arg is not provided")); + return Err(MirEvalError::InternalError("ctpop arg is not provided".into())); }; let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).count_ones(); destination @@ -1066,7 +1122,7 @@ impl Evaluator<'_> { } "ctlz" | "ctlz_nonzero" => { let [arg] = args else { - return Err(MirEvalError::TypeError("ctlz arg is not provided")); + return Err(MirEvalError::InternalError("ctlz arg is not provided".into())); }; let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).leading_zeros() as usize; @@ -1076,7 +1132,7 @@ impl Evaluator<'_> { } "cttz" | "cttz_nonzero" => { let [arg] = args else { - return Err(MirEvalError::TypeError("cttz arg is not provided")); + return Err(MirEvalError::InternalError("cttz arg is not provided".into())); }; let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros(); destination @@ -1084,7 +1140,9 @@ impl Evaluator<'_> { } "rotate_left" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("rotate_left args are not provided")); + return Err(MirEvalError::InternalError( + "rotate_left args are not provided".into(), + )); }; let lhs = &lhs.get(self)?[0..destination.size]; let rhs = rhs.get(self)?[0] as u32; @@ -1114,7 +1172,9 @@ impl Evaluator<'_> { } "rotate_right" => { let [lhs, rhs] = args else { - return Err(MirEvalError::TypeError("rotate_right args are not provided")); + return Err(MirEvalError::InternalError( + "rotate_right args are not provided".into(), + )); }; let lhs = &lhs.get(self)?[0..destination.size]; let rhs = rhs.get(self)?[0] as u32; @@ -1144,13 +1204,15 @@ impl Evaluator<'_> { } "discriminant_value" => { let [arg] = args else { - return Err(MirEvalError::TypeError("discriminant_value arg is not provided")); + return Err(MirEvalError::InternalError( + "discriminant_value arg is not provided".into(), + )); }; let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError( - "discriminant_value generic arg is not provided", + return Err(MirEvalError::InternalError( + "discriminant_value generic arg is not provided".into(), )); }; let addr = Address::from_bytes(arg.get(self)?)?; @@ -1161,11 +1223,15 @@ impl Evaluator<'_> { } "const_eval_select" => { let [tuple, const_fn, _] = args else { - return Err(MirEvalError::TypeError("const_eval_select args are not provided")); + return Err(MirEvalError::InternalError( + "const_eval_select args are not provided".into(), + )); }; let mut args = vec![const_fn.clone()]; let TyKind::Tuple(_, fields) = tuple.ty.kind(Interner) else { - return Err(MirEvalError::TypeError("const_eval_select arg[0] is not a tuple")); + return Err(MirEvalError::InternalError( + "const_eval_select arg[0] is not a tuple".into(), + )); }; let layout = self.layout(&tuple.ty)?; for (i, field) in fields.iter(Interner).enumerate() { @@ -1196,21 +1262,25 @@ impl Evaluator<'_> { } "read_via_copy" | "volatile_load" => { let [arg] = args else { - return Err(MirEvalError::TypeError("read_via_copy args are not provided")); + return Err(MirEvalError::InternalError( + "read_via_copy args are not provided".into(), + )); }; let addr = Address::from_bytes(arg.interval.get(self)?)?; destination.write_from_interval(self, Interval { addr, size: destination.size }) } "write_via_move" => { let [ptr, val] = args else { - return Err(MirEvalError::TypeError("write_via_move args are not provided")); + return Err(MirEvalError::InternalError( + "write_via_move args are not provided".into(), + )); }; let dst = Address::from_bytes(ptr.get(self)?)?; let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError( - "write_via_copy generic arg is not provided", + return Err(MirEvalError::InternalError( + "write_via_copy generic arg is not provided".into(), )); }; let size = self.size_of_sized(ty, locals, "write_via_move ptr type")?; @@ -1219,14 +1289,18 @@ impl Evaluator<'_> { } "write_bytes" => { let [dst, val, count] = args else { - return Err(MirEvalError::TypeError("write_bytes args are not provided")); + return Err(MirEvalError::InternalError( + "write_bytes args are not provided".into(), + )); }; let count = from_bytes!(usize, count.get(self)?); let val = from_bytes!(u8, val.get(self)?); let Some(ty) = - generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("write_bytes generic arg is not provided")); + return Err(MirEvalError::InternalError( + "write_bytes generic arg is not provided".into(), + )); }; let dst = Address::from_bytes(dst.get(self)?)?; let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?; @@ -1265,7 +1339,7 @@ impl Evaluator<'_> { }; let field_types = &self.db.field_types(id.into()); let last_field_ty = - field_types.iter().rev().next().unwrap().1.clone().substitute(Interner, subst); + field_types.iter().next_back().unwrap().1.clone().substitute(Interner, subst); let sized_part_size = layout.fields.offset(field_types.iter().count() - 1).bytes_usize(); let sized_part_align = layout.align.abi.bytes() as usize; @@ -1308,11 +1382,16 @@ impl Evaluator<'_> { // The rest of atomic intrinsics have exactly one generic arg - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided")); + let Some(ty) = generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) + else { + return Err(MirEvalError::InternalError( + "atomic intrinsic generic arg is not provided".into(), + )); }; - let Some(arg0) = args.get(0) else { - return Err(MirEvalError::TypeError("atomic intrinsic arg0 is not provided")); + let Some(arg0) = args.first() else { + return Err(MirEvalError::InternalError( + "atomic intrinsic arg0 is not provided".into(), + )); }; let arg0_addr = Address::from_bytes(arg0.get(self)?)?; let arg0_interval = @@ -1321,7 +1400,9 @@ impl Evaluator<'_> { return destination.write_from_interval(self, arg0_interval); } let Some(arg1) = args.get(1) else { - return Err(MirEvalError::TypeError("atomic intrinsic arg1 is not provided")); + return Err(MirEvalError::InternalError( + "atomic intrinsic arg1 is not provided".into(), + )); }; if name.starts_with("store_") { return arg0_interval.write_from_interval(self, arg1.interval); @@ -1373,7 +1454,9 @@ impl Evaluator<'_> { return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); } let Some(arg2) = args.get(2) else { - return Err(MirEvalError::TypeError("atomic intrinsic arg2 is not provided")); + return Err(MirEvalError::InternalError( + "atomic intrinsic arg2 is not provided".into(), + )); }; if name.starts_with("cxchg_") || name.starts_with("cxchgweak_") { let dest = if arg1.get(self)? == arg0_interval.get(self)? { @@ -1388,7 +1471,7 @@ impl Evaluator<'_> { ) .intern(Interner); let layout = self.layout(&result_ty)?; - let result = self.make_by_layout( + let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index 5190066242660..eddfd0acfb98c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -10,7 +10,7 @@ macro_rules! from_bytes { ($ty:tt, $value:expr) => { ($ty::from_le_bytes(match ($value).try_into() { Ok(it) => it, - Err(_) => return Err(MirEvalError::TypeError("mismatched size")), + Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())), })) }; } @@ -40,22 +40,28 @@ impl Evaluator<'_> { .substitute(Interner, subst); return Ok((fields.len(), field_ty)); } - return Err(MirEvalError::TypeError("simd type with no len param")); + return Err(MirEvalError::InternalError( + "simd type with no len param".into(), + )); } }; match try_const_usize(self.db, len) { Some(len) => { let Some(ty) = - subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + subst.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { - return Err(MirEvalError::TypeError("simd type with no ty param")); + return Err(MirEvalError::InternalError( + "simd type with no ty param".into(), + )); }; Ok((len as usize, ty.clone())) } - None => Err(MirEvalError::TypeError("simd type with unevaluatable len param")), + None => Err(MirEvalError::InternalError( + "simd type with unevaluatable len param".into(), + )), } } - _ => Err(MirEvalError::TypeError("simd type which is not a struct")), + _ => Err(MirEvalError::InternalError("simd type which is not a struct".into())), } } @@ -71,7 +77,9 @@ impl Evaluator<'_> { match name { "and" | "or" | "xor" => { let [left, right] = args else { - return Err(MirEvalError::TypeError("simd bit op args are not provided")); + return Err(MirEvalError::InternalError( + "simd bit op args are not provided".into(), + )); }; let result = left .get(self)? @@ -88,7 +96,7 @@ impl Evaluator<'_> { } "eq" | "ne" | "lt" | "le" | "gt" | "ge" => { let [left, right] = args else { - return Err(MirEvalError::TypeError("simd args are not provided")); + return Err(MirEvalError::InternalError("simd args are not provided".into())); }; let (len, ty) = self.detect_simd_ty(&left.ty)?; let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); @@ -106,7 +114,7 @@ impl Evaluator<'_> { } } if is_signed { - if let Some((&l, &r)) = l.iter().zip(r).rev().next() { + if let Some((&l, &r)) = l.iter().zip(r).next_back() { if l != r { result = (l as i8).cmp(&(r as i8)); } @@ -125,7 +133,9 @@ impl Evaluator<'_> { } "bitmask" => { let [op] = args else { - return Err(MirEvalError::TypeError("simd_bitmask args are not provided")); + return Err(MirEvalError::InternalError( + "simd_bitmask args are not provided".into(), + )); }; let (op_len, _) = self.detect_simd_ty(&op.ty)?; let op_count = op.interval.size / op_len; @@ -139,18 +149,20 @@ impl Evaluator<'_> { } "shuffle" => { let [left, right, index] = args else { - return Err(MirEvalError::TypeError("simd_shuffle args are not provided")); + return Err(MirEvalError::InternalError( + "simd_shuffle args are not provided".into(), + )); }; let TyKind::Array(_, index_len) = index.ty.kind(Interner) else { - return Err(MirEvalError::TypeError( - "simd_shuffle index argument has non-array type", + return Err(MirEvalError::InternalError( + "simd_shuffle index argument has non-array type".into(), )); }; let index_len = match try_const_usize(self.db, index_len) { Some(it) => it as usize, None => { - return Err(MirEvalError::TypeError( - "simd type with unevaluatable len param", + return Err(MirEvalError::InternalError( + "simd type with unevaluatable len param".into(), )) } }; @@ -164,8 +176,8 @@ impl Evaluator<'_> { let val = match vector.clone().nth(index) { Some(it) => it, None => { - return Err(MirEvalError::TypeError( - "out of bound access in simd shuffle", + return Err(MirEvalError::InternalError( + "out of bound access in simd shuffle".into(), )) } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 6552bf493377b..381522c9abe62 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr Substitution::empty(Interner), db.trait_environment(func_id.into()), ) - .map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?; + .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; let (result, output) = interpret_mir(db, body, false, None); result?; Ok((output.stdout().into_owned(), output.stderr().into_owned())) @@ -49,8 +49,8 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr let mut err = String::new(); let line_index = |size: TextSize| { let mut size = u32::from(size) as usize; - let mut lines = ra_fixture.lines().enumerate(); - while let Some((i, l)) = lines.next() { + let lines = ra_fixture.lines().enumerate(); + for (i, l) in lines { if let Some(x) = size.checked_sub(l.len()) { size = x; } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index c02c5ef8767f9..28d26c6c8ae6e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -69,6 +69,7 @@ struct MirLowerCtx<'a> { drop_scopes: Vec, } +// FIXME: Make this smaller, its stored in database queries #[derive(Debug, Clone, PartialEq, Eq)] pub enum MirLowerError { ConstEvalError(Box, Box), @@ -96,7 +97,7 @@ pub enum MirLowerError { MutatingRvalue, UnresolvedLabel, UnresolvedUpvar(Place), - UnaccessableLocal, + InaccessibleLocal, // monomorphization errors: GenericArgNotProvided(TypeOrConstParamId, Substitution), @@ -115,7 +116,7 @@ impl DropScopeToken { ctx.pop_drop_scope_internal(current, span) } - /// It is useful when we want a drop scope is syntaxically closed, but we don't want to execute any drop + /// It is useful when we want a drop scope is syntactically closed, but we don't want to execute any drop /// code. Either when the control flow is diverging (so drop code doesn't reached) or when drop is handled /// for us (for example a block that ended with a return statement. Return will drop everything, so the block shouldn't /// do anything) @@ -185,7 +186,7 @@ impl MirLowerError { | MirLowerError::UnsizedTemporary(_) | MirLowerError::IncompleteExpr | MirLowerError::IncompletePattern - | MirLowerError::UnaccessableLocal + | MirLowerError::InaccessibleLocal | MirLowerError::TraitFunctionDefinition(_, _) | MirLowerError::UnresolvedName(_) | MirLowerError::RecordLiteralWithoutPath @@ -258,7 +259,8 @@ impl<'ctx> MirLowerCtx<'ctx> { owner, closures: vec![], }; - let ctx = MirLowerCtx { + + MirLowerCtx { result: mir, db, infer, @@ -268,8 +270,7 @@ impl<'ctx> MirLowerCtx<'ctx> { labeled_loop_blocks: Default::default(), discr_temp: None, drop_scopes: vec![DropScope::default()], - }; - ctx + } } fn temp(&mut self, ty: Ty, current: BasicBlockId, span: MirSpan) -> Result { @@ -287,12 +288,9 @@ impl<'ctx> MirLowerCtx<'ctx> { current: BasicBlockId, ) -> Result> { if !self.has_adjustments(expr_id) { - match &self.body.exprs[expr_id] { - Expr::Literal(l) => { - let ty = self.expr_ty_without_adjust(expr_id); - return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); - } - _ => (), + if let Expr::Literal(l) = &self.body.exprs[expr_id] { + let ty = self.expr_ty_without_adjust(expr_id); + return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); } } let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else { @@ -344,8 +342,8 @@ impl<'ctx> MirLowerCtx<'ctx> { current, place, Rvalue::Cast( - CastKind::Pointer(cast.clone()), - Operand::Copy(p).into(), + CastKind::Pointer(*cast), + Operand::Copy(p), last.target.clone(), ), expr_id.into(), @@ -456,9 +454,8 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { - let variant_data = - &self.db.enum_data(variant_id.parent).variants[variant_id.local_id]; - if variant_data.variant_data.kind() == StructKind::Unit { + let variant_data = &self.db.enum_variant_data(variant_id).variant_data; + if variant_data.kind() == StructKind::Unit { let ty = self.infer.type_of_expr[expr_id].clone(); current = self.lower_enum_variant( variant_id, @@ -511,8 +508,7 @@ impl<'ctx> MirLowerCtx<'ctx> { return Ok(None); }; let start_of_then = self.new_basic_block(); - let end_of_then = - self.lower_expr_to_place(*then_branch, place.clone(), start_of_then)?; + let end_of_then = self.lower_expr_to_place(*then_branch, place, start_of_then)?; let start_of_else = self.new_basic_block(); let end_of_else = if let Some(else_branch) = else_branch { self.lower_expr_to_place(*else_branch, place, start_of_else)? @@ -539,7 +535,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.pattern_match(current, None, cond_place, *pat)?; self.write_bytes_to_place( then_target, - place.clone(), + place, Box::new([1]), TyBuilder::bool(), MirSpan::Unknown, @@ -560,25 +556,19 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Block { id: _, statements, tail, label } => { if let Some(label) = label { - self.lower_loop( - current, - place.clone(), - Some(*label), - expr_id.into(), - |this, begin| { - if let Some(current) = this.lower_block_to_place( - statements, - begin, - *tail, - place, - expr_id.into(), - )? { - let end = this.current_loop_end()?; - this.set_goto(current, end, expr_id.into()); - } - Ok(()) - }, - ) + self.lower_loop(current, place, Some(*label), expr_id.into(), |this, begin| { + if let Some(current) = this.lower_block_to_place( + statements, + begin, + *tail, + place, + expr_id.into(), + )? { + let end = this.current_loop_end()?; + this.set_goto(current, end, expr_id.into()); + } + Ok(()) + }) } else { self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) } @@ -646,9 +636,9 @@ impl<'ctx> MirLowerCtx<'ctx> { ); } TyKind::Error => { - return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)) + Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)) } - _ => return Err(MirLowerError::TypeError("function call on bad type")), + _ => Err(MirLowerError::TypeError("function call on bad type")), } } Expr::MethodCall { receiver, args, method_name, .. } => { @@ -678,7 +668,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let mut end = None; for MatchArm { pat, guard, expr } in arms.iter() { let (then, mut otherwise) = - self.pattern_match(current, None, cond_place.clone(), *pat)?; + self.pattern_match(current, None, cond_place, *pat)?; let then = if let &Some(guard) = guard { let next = self.new_basic_block(); let o = otherwise.get_or_insert_with(|| self.new_basic_block()); @@ -696,7 +686,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } else { then }; - if let Some(block) = self.lower_expr_to_place(*expr, place.clone(), then)? { + if let Some(block) = self.lower_expr_to_place(*expr, place, then)? { let r = end.get_or_insert_with(|| self.new_basic_block()); self.set_goto(block, *r, expr_id.into()); } @@ -742,9 +732,7 @@ impl<'ctx> MirLowerCtx<'ctx> { .as_ref() .ok_or(MirLowerError::BreakWithoutLoop)?, }; - let Some(c) = - self.lower_expr_to_place(expr, loop_data.place.clone(), current)? - else { + let Some(c) = self.lower_expr_to_place(expr, loop_data.place, current)? else { return Ok(None); }; current = c; @@ -906,7 +894,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let ty = self.expr_ty_after_adjustments(*expr); self.push_assignment( current, - place.clone(), + place, Rvalue::ShallowInitBoxWithAlloc(ty), expr_id.into(), ); @@ -951,16 +939,17 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } Expr::BinaryOp { lhs, rhs, op } => { - let op = op.ok_or(MirLowerError::IncompleteExpr)?; + let op: BinaryOp = op.ok_or(MirLowerError::IncompleteExpr)?; let is_builtin = 'b: { // Without adjust here is a hack. We assume that we know every possible adjustment // for binary operator, and use without adjust to simplify our conditions. let lhs_ty = self.expr_ty_without_adjust(*lhs); let rhs_ty = self.expr_ty_without_adjust(*rhs); - if matches!(op, BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. })) { - if lhs_ty.as_raw_ptr().is_some() && rhs_ty.as_raw_ptr().is_some() { - break 'b true; - } + if matches!(op, BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. })) + && lhs_ty.as_raw_ptr().is_some() + && rhs_ty.as_raw_ptr().is_some() + { + break 'b true; } let builtin_inequal_impls = matches!( op, @@ -1006,11 +995,8 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - let r_value = Rvalue::CheckedBinaryOp( - op.into(), - Operand::Copy(lhs_place.clone()), - rhs_op, - ); + let r_value = + Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op); self.push_assignment(current, lhs_place, r_value, expr_id.into()); return Ok(Some(current)); } else { @@ -1029,7 +1015,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let start_of_then = self.new_basic_block(); self.push_assignment( start_of_then, - place.clone(), + place, lhs_op.clone().into(), expr_id.into(), ); @@ -1168,12 +1154,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let tmp_ty = capture.ty.clone().substitute(Interner, &placeholder_subst); let tmp: Place = self.temp(tmp_ty, current, capture.span)?.into(); - self.push_assignment( - current, - tmp.clone(), - Rvalue::Ref(bk.clone(), p), - capture.span, - ); + self.push_assignment(current, tmp, Rvalue::Ref(*bk, p), capture.span); operands.push(Operand::Move(tmp)); } CaptureKind::ByValue => operands.push(Operand::Move(p)), @@ -1322,7 +1303,7 @@ impl<'ctx> MirLowerCtx<'ctx> { ) { let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?; let temp = Place::from(temp); - self.push_assignment(current, temp.clone(), rhs_op.into(), span); + self.push_assignment(current, temp, rhs_op.into(), span); return self.lower_destructing_assignment(current, lhs, temp, span); } let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else { @@ -1333,11 +1314,10 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn placeholder_subst(&mut self) -> Substitution { - let placeholder_subst = match self.owner.as_generic_def_id() { + match self.owner.as_generic_def_id() { Some(it) => TyBuilder::placeholder_subst(self.db, it), None => Substitution::empty(Interner), - }; - placeholder_subst + } } fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> { @@ -1470,7 +1450,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } else { let name = const_id.name(self.db.upcast()); self.db - .const_eval(const_id.into(), subst, None) + .const_eval(const_id, subst, None) .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))? }; Ok(Operand::Constant(c)) @@ -1612,13 +1592,13 @@ impl<'ctx> MirLowerCtx<'ctx> { fn discr_temp_place(&mut self, current: BasicBlockId) -> Place { match &self.discr_temp { - Some(it) => it.clone(), + Some(it) => *it, None => { let tmp: Place = self .temp(TyBuilder::discr_ty(), current, MirSpan::Unknown) .expect("discr_ty is never unsized") .into(); - self.discr_temp = Some(tmp.clone()); + self.discr_temp = Some(tmp); tmp } } @@ -1863,8 +1843,8 @@ impl<'ctx> MirLowerCtx<'ctx> { None => { // FIXME: It should never happens, but currently it will happen in `const_dependent_on_local` test, which // is a hir lowering problem IMO. - // never!("Using unaccessable local for binding is always a bug"); - Err(MirLowerError::UnaccessableLocal) + // never!("Using inaccessible local for binding is always a bug"); + Err(MirLowerError::InaccessibleLocal) } } } @@ -1874,11 +1854,13 @@ impl<'ctx> MirLowerCtx<'ctx> { match r { Ok(r) => Ok(r), Err(e) => { - let data = self.db.enum_data(variant.parent); + let db = self.db.upcast(); + let loc = variant.lookup(db); + let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - data.name.display(self.db.upcast()), - data.variants[variant.local_id].name.display(self.db.upcast()) + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), ); Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) } @@ -2039,19 +2021,16 @@ pub fn mir_body_for_closure_query( ctx.result.walk_places(|p, store| { if let Some(it) = upvar_map.get(&p.local) { let r = it.iter().find(|it| { - if p.projection.lookup(&store).len() < it.0.place.projections.len() { + if p.projection.lookup(store).len() < it.0.place.projections.len() { return false; } - for (it, y) in p.projection.lookup(&store).iter().zip(it.0.place.projections.iter()) + for (it, y) in p.projection.lookup(store).iter().zip(it.0.place.projections.iter()) { match (it, y) { (ProjectionElem::Deref, ProjectionElem::Deref) => (), (ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (), (ProjectionElem::ClosureField(it), ProjectionElem::ClosureField(y)) - if it == y => - { - () - } + if it == y => {} _ => return false, } } @@ -2067,15 +2046,11 @@ pub fn mir_body_for_closure_query( next_projs.push(ProjectionElem::Deref); } next_projs.extend( - prev_projs - .lookup(&store) - .iter() - .skip(it.0.place.projections.len()) - .cloned(), + prev_projs.lookup(store).iter().skip(it.0.place.projections.len()).cloned(), ); p.projection = store.intern(next_projs.into()); } - None => err = Some(p.clone()), + None => err = Some(*p), } } }); @@ -2093,7 +2068,7 @@ pub fn mir_body_for_closure_query( } pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result> { - let _p = profile::span("mir_body_query").detail(|| match def { + let detail = match def { DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(), DefWithBodyId::StaticId(it) => db.static_data(it).name.display(db.upcast()).to_string(), DefWithBodyId::ConstId(it) => db @@ -2104,10 +2079,11 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result { - db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() + db.enum_variant_data(it).name.display(db.upcast()).to_string() } DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), - }); + }; + let _p = tracing::span!(tracing::Level::INFO, "mir_body_query", ?detail).entered(); let body = db.body(def); let infer = db.infer(def); let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index cb5588a5c13d8..8d157944020d8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -148,7 +148,7 @@ impl MirLowerCtx<'_> { let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); self.push_assignment( current, - temp.clone(), + temp, Operand::Static(s).into(), expr_id.into(), ); @@ -160,57 +160,53 @@ impl MirLowerCtx<'_> { _ => try_rvalue(self), } } - Expr::UnaryOp { expr, op } => match op { - hir_def::hir::UnaryOp::Deref => { - let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) { - TyKind::Ref(..) | TyKind::Raw(..) => true, - TyKind::Adt(id, _) => { - if let Some(lang_item) = self.db.lang_attr(id.0.into()) { - lang_item == LangItem::OwnedBox - } else { - false - } + Expr::UnaryOp { expr, op: hir_def::hir::UnaryOp::Deref } => { + let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) { + TyKind::Ref(..) | TyKind::Raw(..) => true, + TyKind::Adt(id, _) => { + if let Some(lang_item) = self.db.lang_attr(id.0.into()) { + lang_item == LangItem::OwnedBox + } else { + false } - _ => false, + } + _ => false, + }; + if !is_builtin { + let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else { + return Ok(None); }; - if !is_builtin { - let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? - else { - return Ok(None); - }; - return self.lower_overloaded_deref( - current, - p, - self.expr_ty_after_adjustments(*expr), - self.expr_ty_without_adjust(expr_id), - expr_id.into(), - 'b: { - if let Some((f, _)) = self.infer.method_resolution(expr_id) { - if let Some(deref_trait) = - self.resolve_lang_item(LangItem::DerefMut)?.as_trait() + return self.lower_overloaded_deref( + current, + p, + self.expr_ty_after_adjustments(*expr), + self.expr_ty_without_adjust(expr_id), + expr_id.into(), + 'b: { + if let Some((f, _)) = self.infer.method_resolution(expr_id) { + if let Some(deref_trait) = + self.resolve_lang_item(LangItem::DerefMut)?.as_trait() + { + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&name![deref_mut]) { - if let Some(deref_fn) = self - .db - .trait_data(deref_trait) - .method_by_name(&name![deref_mut]) - { - break 'b deref_fn == f; - } + break 'b deref_fn == f; } } - false - }, - ); - } - let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? - else { - return Ok(None); - }; - r = r.project(ProjectionElem::Deref, &mut self.result.projection_store); - Ok(Some((r, current))) + } + false + }, + ); } - _ => try_rvalue(self), - }, + let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { + return Ok(None); + }; + r = r.project(ProjectionElem::Deref, &mut self.result.projection_store); + Ok(Some((r, current))) + } + Expr::UnaryOp { .. } => try_rvalue(self), Expr::Field { expr, .. } => { let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); @@ -304,7 +300,7 @@ impl MirLowerCtx<'_> { let Some(current) = self.lower_call( index_fn_op, Box::new([Operand::Copy(place), index_operand]), - result.clone(), + result, current, false, span, @@ -338,7 +334,7 @@ impl MirLowerCtx<'_> { let ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), source_ty.clone()).intern(Interner); let target_ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), target_ty).intern(Interner); let ref_place: Place = self.temp(ty_ref, current, span)?.into(); - self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span); + self.push_assignment(current, ref_place, Rvalue::Ref(borrow_kind, place), span); let deref_trait = self .resolve_lang_item(trait_lang_item)? .as_trait() @@ -359,7 +355,7 @@ impl MirLowerCtx<'_> { let Some(current) = self.lower_call( deref_fn_op, Box::new([Operand::Copy(ref_place)]), - result.clone(), + result, current, false, span, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 98c2e7c63bc17..8202bac532f7a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -58,7 +58,7 @@ impl MirLowerCtx<'_> { let (current, current_else) = self.pattern_match_inner( current, current_else, - cond_place.clone(), + cond_place, pattern, MatchingMode::Check, )?; @@ -114,7 +114,7 @@ impl MirLowerCtx<'_> { index: i as u32, })) }), - &(&mut cond_place), + &cond_place, mode, )? } @@ -125,7 +125,7 @@ impl MirLowerCtx<'_> { let (mut next, next_else) = self.pattern_match_inner( current, None, - (&mut cond_place).clone(), + cond_place, *pat, MatchingMode::Check, )?; @@ -133,7 +133,7 @@ impl MirLowerCtx<'_> { (next, _) = self.pattern_match_inner( next, None, - (&mut cond_place).clone(), + cond_place, *pat, MatchingMode::Bind, )?; @@ -169,7 +169,7 @@ impl MirLowerCtx<'_> { current, pattern.into(), current_else, - AdtPatternShape::Record { args: &*args }, + AdtPatternShape::Record { args }, mode, )? } @@ -183,12 +183,8 @@ impl MirLowerCtx<'_> { self.temp(TyBuilder::bool(), current, pattern.into())?.into(); self.push_assignment( current, - discr.clone(), - Rvalue::CheckedBinaryOp( - binop, - lv, - Operand::Copy((&mut cond_place).clone()), - ), + discr, + Rvalue::CheckedBinaryOp(binop, lv, Operand::Copy(cond_place)), pattern.into(), ); let discr = Operand::Copy(discr); @@ -222,8 +218,8 @@ impl MirLowerCtx<'_> { self.temp(TyBuilder::usize(), current, pattern.into())?.into(); self.push_assignment( current, - place_len.clone(), - Rvalue::Len((&mut cond_place).clone()), + place_len, + Rvalue::Len(cond_place), pattern.into(), ); let else_target = @@ -252,7 +248,7 @@ impl MirLowerCtx<'_> { self.temp(TyBuilder::bool(), current, pattern.into())?.into(); self.push_assignment( current, - discr.clone(), + discr, Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)), pattern.into(), ); @@ -270,7 +266,7 @@ impl MirLowerCtx<'_> { } } for (i, &pat) in prefix.iter().enumerate() { - let next_place = (&mut cond_place).project( + let next_place = cond_place.project( ProjectionElem::ConstantIndex { offset: i as u64, from_end: false }, &mut self.result.projection_store, ); @@ -280,7 +276,7 @@ impl MirLowerCtx<'_> { if let Some(slice) = slice { if mode == MatchingMode::Bind { if let Pat::Bind { id, subpat: _ } = self.body[*slice] { - let next_place = (&mut cond_place).project( + let next_place = cond_place.project( ProjectionElem::Subslice { from: prefix.len() as u64, to: suffix.len() as u64, @@ -299,7 +295,7 @@ impl MirLowerCtx<'_> { } } for (i, &pat) in suffix.iter().enumerate() { - let next_place = (&mut cond_place).project( + let next_place = cond_place.project( ProjectionElem::ConstantIndex { offset: i as u64, from_end: true }, &mut self.result.projection_store, ); @@ -335,10 +331,8 @@ impl MirLowerCtx<'_> { break 'b (c, x.1); } } - if let ResolveValueResult::ValueNs(v, _) = pr { - if let ValueNs::ConstId(c) = v { - break 'b (c, Substitution::empty(Interner)); - } + if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr { + break 'b (c, Substitution::empty(Interner)); } not_supported!("path in pattern position that is not const or variant") }; @@ -348,7 +342,7 @@ impl MirLowerCtx<'_> { self.lower_const( c.into(), current, - tmp.clone(), + tmp, subst, span, self.infer[pattern].clone(), @@ -356,7 +350,7 @@ impl MirLowerCtx<'_> { let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); self.push_assignment( current, - tmp2.clone(), + tmp2, Rvalue::CheckedBinaryOp( BinOp::Eq, Operand::Copy(tmp), @@ -390,13 +384,8 @@ impl MirLowerCtx<'_> { }, Pat::Bind { id, subpat } => { if let Some(subpat) = subpat { - (current, current_else) = self.pattern_match_inner( - current, - current_else, - (&mut cond_place).clone(), - *subpat, - mode, - )? + (current, current_else) = + self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)? } if mode == MatchingMode::Bind { self.pattern_match_binding( @@ -475,7 +464,7 @@ impl MirLowerCtx<'_> { let discr: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); self.push_assignment( current, - discr.clone(), + discr, Rvalue::CheckedBinaryOp(BinOp::Eq, c, Operand::Copy(cond_place)), pattern.into(), ); @@ -506,12 +495,7 @@ impl MirLowerCtx<'_> { if mode == MatchingMode::Check { let e = self.const_eval_discriminant(v)? as u128; let tmp = self.discr_temp_place(current); - self.push_assignment( - current, - tmp.clone(), - Rvalue::Discriminant(cond_place.clone()), - span, - ); + self.push_assignment(current, tmp, Rvalue::Discriminant(cond_place), span); let next = self.new_basic_block(); let else_target = current_else.get_or_insert_with(|| self.new_basic_block()); self.set_terminator( @@ -524,22 +508,9 @@ impl MirLowerCtx<'_> { ); current = next; } - let enum_data = self.db.enum_data(v.parent); - self.pattern_matching_variant_fields( - shape, - &enum_data.variants[v.local_id].variant_data, - variant, - current, - current_else, - &cond_place, - mode, - )? - } - VariantId::StructId(s) => { - let struct_data = self.db.struct_data(s); self.pattern_matching_variant_fields( shape, - &struct_data.variant_data, + &self.db.enum_variant_data(v).variant_data, variant, current, current_else, @@ -547,6 +518,15 @@ impl MirLowerCtx<'_> { mode, )? } + VariantId::StructId(s) => self.pattern_matching_variant_fields( + shape, + &self.db.struct_data(s).variant_data, + variant, + current, + current_else, + &cond_place, + mode, + )?, VariantId::UnionId(_) => { return Err(MirLowerError::TypeError("pattern matching on union")) } @@ -572,7 +552,7 @@ impl MirLowerCtx<'_> { variant_data.field(&x.name).ok_or(MirLowerError::UnresolvedField)?; Ok(( PlaceElem::Field(Either::Left(FieldId { - parent: v.into(), + parent: v, local_id: field_id, })), x.pat, @@ -583,7 +563,7 @@ impl MirLowerCtx<'_> { } AdtPatternShape::Tuple { args, ellipsis } => { let fields = variant_data.fields().iter().map(|(x, _)| { - PlaceElem::Field(Either::Left(FieldId { parent: v.into(), local_id: x })) + PlaceElem::Field(Either::Left(FieldId { parent: v, local_id: x })) }); self.pattern_match_tuple_like( current, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index 8da03eef2e0c6..46dec257e89a8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -275,7 +275,7 @@ impl Filler<'_> { | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Assert { .. } | TerminatorKind::Yield { .. } - | TerminatorKind::GeneratorDrop + | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => (), } @@ -306,7 +306,7 @@ pub fn monomorphized_mir_body_recover( _: &Substitution, _: &Arc, ) -> Result, MirLowerError> { - return Err(MirLowerError::Loop); + Err(MirLowerError::Loop) } pub fn monomorphized_mir_body_for_closure_query( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 366c2f662b54b..23fc271355420 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -7,7 +7,7 @@ use std::{ use either::Either; use hir_def::{body::Body, hir::BindingId}; -use hir_expand::name::Name; +use hir_expand::{name::Name, Lookup}; use la_arena::ArenaMap; use crate::{ @@ -58,8 +58,14 @@ impl MirBody { ); } hir_def::DefWithBodyId::VariantId(id) => { - let data = db.enum_data(id.parent); - w!(this, "enum {} = ", data.name.display(db.upcast())); + let loc = id.lookup(db.upcast()); + let enum_loc = loc.parent.lookup(db.upcast()); + w!( + this, + "enum {}::{} = ", + enum_loc.id.item_tree(db.upcast())[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db.upcast())[loc.id.value].name.display(db.upcast()), + ) } hir_def::DefWithBodyId::InTypeConstId(id) => { w!(this, "in type const {id:?} = "); @@ -306,8 +312,7 @@ impl<'a> MirPrettyCtx<'a> { hir_def::VariantId::EnumVariantId(e) => { w!(this, "("); f(this, local, head); - let variant_name = - &this.db.enum_data(e.parent).variants[e.local_id].name; + let variant_name = &this.db.enum_variant_data(e).name; w!( this, " as {}).{}", @@ -339,7 +344,7 @@ impl<'a> MirPrettyCtx<'a> { } } } - f(self, p.local, &p.projection.lookup(&self.body.projection_store)); + f(self, p.local, p.projection.lookup(&self.body.projection_store)); } fn operand(&mut self, r: &Operand) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index d0a1fb1d57691..460aabd733656 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -43,13 +43,13 @@ impl fmt::Debug for TestDB { impl Upcast for TestDB { fn upcast(&self) -> &(dyn ExpandDatabase + 'static) { - &*self + self } } impl Upcast for TestDB { fn upcast(&self) -> &(dyn DefDatabase + 'static) { - &*self + self } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index c8cc61cc21b48..9804910c878d4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -1,14 +1,14 @@ -mod never_type; mod coercion; +mod diagnostics; +mod display_source_code; +mod incremental; +mod macros; +mod method_resolution; +mod never_type; +mod patterns; mod regression; mod simple; -mod patterns; mod traits; -mod method_resolution; -mod macros; -mod display_source_code; -mod incremental; -mod diagnostics; use std::{collections::HashMap, env}; @@ -16,7 +16,7 @@ use base_db::{FileRange, SourceDatabaseExt}; use expect_test::Expect; use hir_def::{ body::{Body, BodySourceMap, SyntheticSyntax}, - db::{DefDatabase, InternDatabase}, + db::DefDatabase, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, @@ -145,7 +145,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::VariantId(it) => { - let loc = db.lookup_intern_enum(it.parent); + let loc = it.lookup(&db); loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), @@ -383,7 +383,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::VariantId(it) => { - let loc = db.lookup_intern_enum(it.parent); + let loc = it.lookup(&db); loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), @@ -453,16 +453,12 @@ fn visit_module( visit_body(db, &body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { - db.enum_data(it) - .variants - .iter() - .map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id }) - .for_each(|it| { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - }); + db.enum_data(it).variants.iter().for_each(|&(it, _)| { + let def = it.into(); + cb(def); + let body = db.body(def); + visit_body(db, &body, cb); + }); } ModuleDefId::TraitId(it) => { let trait_data = db.trait_data(it); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index 16e5ef85d09d5..d56b15b9b741e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -328,7 +328,7 @@ fn foo() { } #[test] -fn generator_yield_return_coerce() { +fn coroutine_yield_return_coerce() { check_no_mismatches( r#" fn test() { @@ -574,6 +574,7 @@ fn two_closures_lub() { r#" fn foo(c: i32) { let add = |a: i32, b: i32| a + b; + //^^^^^^^^^^^^^^^^^^^^^^ impl Fn(i32, i32) -> i32 let sub = |a, b| a - b; //^^^^^^^^^^^^ impl Fn(i32, i32) -> i32 if c > 42 { add } else { sub }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 622b4f56d4ffa..b0a9361f1c51d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -64,7 +64,7 @@ fn infer_macros_expanded() { "#, expect![[r#" !0..17 '{Foo(v...,2,])}': Foo - !1..4 'Foo': Foo({unknown}) -> Foo + !1..4 'Foo': extern "rust-call" Foo({unknown}) -> Foo !1..16 'Foo(vec![1,2,])': Foo !5..15 'vec![1,2,]': {unknown} 155..181 '{ ...,2); }': () @@ -97,7 +97,7 @@ fn infer_legacy_textual_scoped_macros_expanded() { "#, expect![[r#" !0..17 '{Foo(v...,2,])}': Foo - !1..4 'Foo': Foo({unknown}) -> Foo + !1..4 'Foo': extern "rust-call" Foo({unknown}) -> Foo !1..16 'Foo(vec![1,2,])': Foo !5..15 'vec![1,2,]': {unknown} 194..250 '{ ...,2); }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 548f782f4f2eb..0690073082254 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -210,13 +210,13 @@ fn infer_pattern_match_ergonomics() { 37..41 'A(n)': A 39..40 'n': &i32 44..49 '&A(1)': &A - 45..46 'A': A(i32) -> A + 45..46 'A': extern "rust-call" A(i32) -> A 45..49 'A(1)': A 47..48 '1': i32 59..63 'A(n)': A 61..62 'n': &mut i32 66..75 '&mut A(1)': &mut A - 71..72 'A': A(i32) -> A + 71..72 'A': extern "rust-call" A(i32) -> A 71..75 'A(1)': A 73..74 '1': i32 "#]], @@ -531,18 +531,18 @@ impl Foo { 56..64 'Self(s,)': Foo 61..62 's': &usize 67..75 '&Foo(0,)': &Foo - 68..71 'Foo': Foo(usize) -> Foo + 68..71 'Foo': extern "rust-call" Foo(usize) -> Foo 68..75 'Foo(0,)': Foo 72..73 '0': usize 89..97 'Self(s,)': Foo 94..95 's': &mut usize 100..112 '&mut Foo(0,)': &mut Foo - 105..108 'Foo': Foo(usize) -> Foo + 105..108 'Foo': extern "rust-call" Foo(usize) -> Foo 105..112 'Foo(0,)': Foo 109..110 '0': usize 126..134 'Self(s,)': Foo 131..132 's': usize - 137..140 'Foo': Foo(usize) -> Foo + 137..140 'Foo': extern "rust-call" Foo(usize) -> Foo 137..144 'Foo(0,)': Foo 141..142 '0': usize "#]], @@ -916,7 +916,7 @@ fn foo(foo: Foo) { 48..51 'foo': Foo 62..84 'const ... 32) }': Foo 68..84 '{ Foo(... 32) }': Foo - 70..73 'Foo': Foo(usize) -> Foo + 70..73 'Foo': extern "rust-call" Foo(usize) -> Foo 70..82 'Foo(15 + 32)': Foo 74..76 '15': usize 74..81 '15 + 32': usize diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 35079e70946d5..2ad9a7fe525fd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -644,7 +644,7 @@ fn issue_4953() { "#, expect![[r#" 58..72 '{ Self(0i64) }': Foo - 60..64 'Self': Foo(i64) -> Foo + 60..64 'Self': extern "rust-call" Foo(i64) -> Foo 60..70 'Self(0i64)': Foo 65..69 '0i64': i64 "#]], @@ -658,7 +658,7 @@ fn issue_4953() { "#, expect![[r#" 64..78 '{ Self(0i64) }': Foo - 66..70 'Self': Foo(i64) -> Foo + 66..70 'Self': extern "rust-call" Foo(i64) -> Foo 66..76 'Self(0i64)': Foo 71..75 '0i64': i64 "#]], @@ -858,7 +858,7 @@ fn main() { 94..96 '{}': () 109..160 '{ ...10); }': () 119..120 's': S - 123..124 'S': S() -> S + 123..124 'S': extern "rust-call" S() -> S 123..126 'S()': S 132..133 's': S 132..144 's.g(|_x| {})': () @@ -1689,18 +1689,18 @@ fn main() { } "#, expect![[r#" - 27..85 '{ ...1,); }': () - 37..48 'S(.., a, b)': S - 43..44 'a': usize - 46..47 'b': {unknown} - 51..52 'S': S(usize) -> S - 51..55 'S(1)': S - 53..54 '1': usize - 65..75 '(.., a, b)': (i32, {unknown}) - 70..71 'a': i32 - 73..74 'b': {unknown} - 78..82 '(1,)': (i32,) - 79..80 '1': i32 + 27..85 '{ ...1,); }': () + 37..48 'S(.., a, b)': S + 43..44 'a': usize + 46..47 'b': {unknown} + 51..52 'S': extern "rust-call" S(usize) -> S + 51..55 'S(1)': S + 53..54 '1': usize + 65..75 '(.., a, b)': (i32, {unknown}) + 70..71 'a': i32 + 73..74 'b': {unknown} + 78..82 '(1,)': (i32,) + 79..80 '1': i32 "#]], ); } @@ -2012,3 +2012,31 @@ fn rustc_test_issue_52437() { "#, ); } + +#[test] +fn incorrect_variant_form_through_alias_caught() { + check_types( + r#" +enum Enum { Braced {}, Unit, Tuple() } +type Alias = Enum; + +fn main() { + Alias::Braced; + //^^^^^^^^^^^^^ {unknown} + let Alias::Braced = loop {}; + //^^^^^^^^^^^^^ ! + let Alias::Braced(..) = loop {}; + //^^^^^^^^^^^^^^^^^ Enum + + Alias::Unit(); + //^^^^^^^^^^^^^ {unknown} + Alias::Unit{}; + //^^^^^^^^^^^^^ Enum + let Alias::Unit() = loop {}; + //^^^^^^^^^^^^^ Enum + let Alias::Unit{} = loop {}; + //^^^^^^^^^^^^^ Enum +} +"#, + ) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 8140c4107b8dd..8474782282606 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -236,14 +236,14 @@ fn test() { expect![[r#" 71..153 '{ ...a.c; }': () 81..82 'c': C - 85..86 'C': C(usize) -> C + 85..86 'C': extern "rust-call" C(usize) -> C 85..89 'C(1)': C 87..88 '1': usize 95..96 'B': B 106..107 'a': A 113..132 'A { b:...C(1) }': A 120..121 'B': B - 126..127 'C': C(usize) -> C + 126..127 'C': extern "rust-call" C(usize) -> C 126..130 'C(1)': C 128..129 '1': usize 138..139 'a': A @@ -303,14 +303,14 @@ unsafe fn baz(u: MyUnion) { 71..89 'MyUnio...o: 0 }': MyUnion 86..87 '0': u32 95..113 'unsafe...(u); }': () - 104..107 'baz': fn baz(MyUnion) + 104..107 'baz': unsafe fn baz(MyUnion) 104..110 'baz(u)': () 108..109 'u': MyUnion 122..123 'u': MyUnion 126..146 'MyUnio... 0.0 }': MyUnion 141..144 '0.0': f32 152..170 'unsafe...(u); }': () - 161..164 'baz': fn baz(MyUnion) + 161..164 'baz': unsafe fn baz(MyUnion) 161..167 'baz(u)': () 165..166 'u': MyUnion 188..189 'u': MyUnion @@ -625,12 +625,12 @@ impl E { 86..107 '{ ... }': () 96..100 'Self': S1 134..158 '{ ... }': () - 144..148 'Self': S2(isize) -> S2 + 144..148 'Self': extern "rust-call" S2(isize) -> S2 144..151 'Self(1)': S2 149..150 '1': isize 184..230 '{ ... }': () 194..202 'Self::V1': E - 212..220 'Self::V2': V2(u32) -> E + 212..220 'Self::V2': extern "rust-call" V2(u32) -> E 212..223 'Self::V2(1)': E 221..222 '1': u32 "#]], @@ -856,11 +856,11 @@ fn test() { 256..277 'A::foo...42))))': &i32 263..276 '&&B(B(A(42)))': &&B>> 264..276 '&B(B(A(42)))': &B>> - 265..266 'B': B>>(B>) -> B>> + 265..266 'B': extern "rust-call" B>>(B>) -> B>> 265..276 'B(B(A(42)))': B>> - 267..268 'B': B>(A) -> B> + 267..268 'B': extern "rust-call" B>(A) -> B> 267..275 'B(A(42))': B> - 269..270 'A': A(i32) -> A + 269..270 'A': extern "rust-call" A(i32) -> A 269..274 'A(42)': A 271..273 '42': i32 "#]], @@ -910,16 +910,16 @@ fn test(a: A) { 253..254 'a': A 264..310 '{ ...))); }': () 274..275 't': &i32 - 278..279 'A': A(*mut i32) -> A + 278..279 'A': extern "rust-call" A(*mut i32) -> A 278..292 'A(0 as *mut _)': A 278..307 'A(0 as...B(a)))': &i32 280..281 '0': i32 280..291 '0 as *mut _': *mut i32 297..306 '&&B(B(a))': &&B>> 298..306 '&B(B(a))': &B>> - 299..300 'B': B>>(B>) -> B>> + 299..300 'B': extern "rust-call" B>>(B>) -> B>> 299..306 'B(B(a))': B>> - 301..302 'B': B>(A) -> B> + 301..302 'B': extern "rust-call" B>(A) -> B> 301..305 'B(a)': B> 303..304 'a': A "#]], @@ -1273,16 +1273,16 @@ fn infer_tuple_struct_generics() { "#, expect![[r#" 75..183 '{ ...one; }': () - 81..82 'A': A(i32) -> A + 81..82 'A': extern "rust-call" A(i32) -> A 81..86 'A(42)': A 83..85 '42': i32 - 92..93 'A': A(u128) -> A + 92..93 'A': extern "rust-call" A(u128) -> A 92..101 'A(42u128)': A 94..100 '42u128': u128 - 107..111 'Some': Some<&str>(&str) -> Option<&str> + 107..111 'Some': extern "rust-call" Some<&str>(&str) -> Option<&str> 107..116 'Some("x")': Option<&str> 112..115 '"x"': &str - 122..134 'Option::Some': Some<&str>(&str) -> Option<&str> + 122..134 'Option::Some': extern "rust-call" Some<&str>(&str) -> Option<&str> 122..139 'Option...e("x")': Option<&str> 135..138 '"x"': &str 145..149 'None': Option<{unknown}> @@ -1568,7 +1568,7 @@ fn infer_type_alias() { 204..207 'z.y': i8 298..362 '{ ... &e; }': () 308..309 'e': Enum - 312..325 'm::Alias::Foo': Foo(u8) -> Enum + 312..325 'm::Alias::Foo': extern "rust-call" Foo(u8) -> Enum 312..328 'm::Ali...Foo(0)': Enum 326..327 '0': u8 338..354 'm::Ali...Foo(x)': Enum @@ -1949,11 +1949,11 @@ fn closure_return_inferred() { } #[test] -fn generator_types_inferred() { +fn coroutine_types_inferred() { check_infer( r#" -//- minicore: generator, deref -use core::ops::{Generator, GeneratorState}; +//- minicore: coroutine, deref +use core::ops::{Coroutine, CoroutineState}; use core::pin::Pin; fn f(v: i64) {} @@ -1966,8 +1966,8 @@ fn test() { }; match Pin::new(&mut g).resume(0usize) { - GeneratorState::Yielded(y) => { f(y); } - GeneratorState::Complete(r) => {} + CoroutineState::Yielded(y) => { f(y); } + CoroutineState::Complete(r) => {} } } "#, @@ -1992,17 +1992,17 @@ fn test() { 225..360 'match ... }': () 231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str> 231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str> - 231..262 'Pin::n...usize)': GeneratorState + 231..262 'Pin::n...usize)': CoroutineState 240..246 '&mut g': &mut |usize| yields i64 -> &str 245..246 'g': |usize| yields i64 -> &str 255..261 '0usize': usize - 273..299 'Genera...ded(y)': GeneratorState + 273..299 'Corout...ded(y)': CoroutineState 297..298 'y': i64 303..312 '{ f(y); }': () 305..306 'f': fn f(i64) 305..309 'f(y)': () 307..308 'y': i64 - 321..348 'Genera...ete(r)': GeneratorState + 321..348 'Corout...ete(r)': CoroutineState 346..347 'r': &str 352..354 '{}': () "#]], @@ -2010,11 +2010,11 @@ fn test() { } #[test] -fn generator_resume_yield_return_unit() { +fn coroutine_resume_yield_return_unit() { check_no_mismatches( r#" -//- minicore: generator, deref -use core::ops::{Generator, GeneratorState}; +//- minicore: coroutine, deref +use core::ops::{Coroutine, CoroutineState}; use core::pin::Pin; fn test() { let mut g = || { @@ -2022,8 +2022,8 @@ fn test() { }; match Pin::new(&mut g).resume(()) { - GeneratorState::Yielded(()) => {} - GeneratorState::Complete(()) => {} + CoroutineState::Yielded(()) => {} + CoroutineState::Complete(()) => {} } } "#, @@ -2184,10 +2184,10 @@ fn main() { 103..231 '{ ... }); }': () 109..161 'async ... }': impl Future> 125..139 'return Err(())': ! - 132..135 'Err': Err<(), ()>(()) -> Result<(), ()> + 132..135 'Err': extern "rust-call" Err<(), ()>(()) -> Result<(), ()> 132..139 'Err(())': Result<(), ()> 136..138 '()': () - 149..151 'Ok': Ok<(), ()>(()) -> Result<(), ()> + 149..151 'Ok': extern "rust-call" Ok<(), ()>(()) -> Result<(), ()> 149..155 'Ok(())': Result<(), ()> 152..154 '()': () 167..171 'test': fn test<(), (), impl Fn() -> impl Future>, impl Future>>(impl Fn() -> impl Future>) @@ -2195,10 +2195,10 @@ fn main() { 172..227 '|| asy... }': impl Fn() -> impl Future> 175..227 'async ... }': impl Future> 191..205 'return Err(())': ! - 198..201 'Err': Err<(), ()>(()) -> Result<(), ()> + 198..201 'Err': extern "rust-call" Err<(), ()>(()) -> Result<(), ()> 198..205 'Err(())': Result<(), ()> 202..204 '()': () - 215..217 'Ok': Ok<(), ()>(()) -> Result<(), ()> + 215..217 'Ok': extern "rust-call" Ok<(), ()>(()) -> Result<(), ()> 215..221 'Ok(())': Result<(), ()> 218..220 '()': () "#]], @@ -2227,7 +2227,7 @@ fn infer_generic_from_later_assignment() { 94..127 '{ ... }': () 104..107 'end': Option 104..120 'end = ...(true)': () - 110..114 'Some': Some(bool) -> Option + 110..114 'Some': extern "rust-call" Some(bool) -> Option 110..120 'Some(true)': Option 115..119 'true': bool "#]], @@ -2262,7 +2262,7 @@ fn infer_loop_break_with_val() { 111..121 'break None': ! 117..121 'None': Option 142..158 'break ...(true)': ! - 148..152 'Some': Some(bool) -> Option + 148..152 'Some': extern "rust-call" Some(bool) -> Option 148..158 'Some(true)': Option 153..157 'true': bool "#]], @@ -2509,7 +2509,7 @@ fn generic_default_in_struct_literal() { 254..281 'OtherT...1i32 }': OtherThing 275..279 '1i32': i32 291..292 'b': OtherThing - 295..310 'OtherThing::Two': Two(i32) -> OtherThing + 295..310 'OtherThing::Two': extern "rust-call" Two(i32) -> OtherThing 295..316 'OtherT...(1i32)': OtherThing 311..315 '1i32': i32 "#]], @@ -2984,7 +2984,7 @@ fn f() { expect![[r#" 72..166 '{ ... } }': () 78..164 'match ... }': () - 84..92 'Foo::Bar': Bar(i32) -> Foo + 84..92 'Foo::Bar': extern "rust-call" Bar(i32) -> Foo 84..95 'Foo::Bar(3)': Foo 93..94 '3': i32 106..119 'Qux::Bar(bar)': Foo @@ -3043,9 +3043,9 @@ fn main() { 322..324 '{}': Foo 338..559 '{ ...r(); }': () 348..353 'boxed': Box> - 356..359 'Box': Box>(Foo) -> Box> + 356..359 'Box': extern "rust-call" Box>(Foo) -> Box> 356..371 'Box(Foo(0_i32))': Box> - 360..363 'Foo': Foo(i32) -> Foo + 360..363 'Foo': extern "rust-call" Foo(i32) -> Foo 360..370 'Foo(0_i32)': Foo 364..369 '0_i32': i32 382..386 'bad1': &i32 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index d270328605a9b..db14addaf185b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -522,7 +522,7 @@ fn test() -> u64 { expect![[r#" 37..86 '{ ... a.1 }': u64 47..48 'a': S - 51..52 'S': S(i32, u64) -> S + 51..52 'S': extern "rust-call" S(i32, u64) -> S 51..58 'S(4, 6)': S 53..54 '4': i32 56..57 '6': u64 @@ -548,7 +548,7 @@ fn test() -> u64 { expect![[r#" 43..108 '{ ...0(2) }': u64 53..54 'a': S - 57..58 'S': S(fn(u32) -> u64) -> S + 57..58 'S': extern "rust-call" S(fn(u32) -> u64) -> S 57..74 'S(|i| ...s u64)': S 59..73 '|i| 2*i as u64': impl Fn(u32) -> u64 60..61 'i': u32 @@ -1026,7 +1026,7 @@ fn test(x: impl Trait, y: &impl Trait) { 201..202 'x': impl Trait 208..209 'y': &impl Trait 219..220 'z': S - 223..224 'S': S(u16) -> S + 223..224 'S': extern "rust-call" S(u16) -> S 223..227 'S(1)': S 225..226 '1': u16 233..236 'bar': fn bar(S) @@ -1339,7 +1339,7 @@ fn foo() -> (impl FnOnce(&str, T), impl Trait) { 142..147 'input': &str 149..150 't': T 152..154 '{}': () - 156..159 'Bar': Bar(u8) -> Bar + 156..159 'Bar': extern "rust-call" Bar(u8) -> Bar 156..162 'Bar(C)': Bar 160..161 'C': u8 "#]], @@ -1958,7 +1958,7 @@ fn test() { 118..120 '{}': () 136..255 '{ ... 1); }': () 146..147 'x': Option - 150..162 'Option::Some': Some(u32) -> Option + 150..162 'Option::Some': extern "rust-call" Some(u32) -> Option 150..168 'Option...(1u32)': Option 163..167 '1u32': u32 174..175 'x': Option @@ -2514,7 +2514,7 @@ fn test() -> impl Trait { 178..180 '{}': () 213..309 '{ ...t()) }': S 223..225 's1': S - 228..229 'S': S(u32) -> S + 228..229 'S': extern "rust-call" S(u32) -> S 228..240 'S(default())': S 230..237 'default': fn default() -> u32 230..239 'default()': u32 @@ -2524,11 +2524,11 @@ fn test() -> impl Trait { 263..264 'x': i32 272..275 'bar': fn bar(S) -> i32 272..289 'bar(S(...lt()))': i32 - 276..277 'S': S(i32) -> S + 276..277 'S': extern "rust-call" S(i32) -> S 276..288 'S(default())': S 278..285 'default': fn default() -> i32 278..287 'default()': i32 - 295..296 'S': S(i32) -> S + 295..296 'S': extern "rust-call" S(i32) -> S 295..307 'S(default())': S 297..304 'default': fn default() -> i32 297..306 'default()': i32 @@ -2758,7 +2758,7 @@ fn main() { 1036..1041 'x > 0': bool 1040..1041 '0': i32 1042..1060 '{ Some...u32) }': Option - 1044..1048 'Some': Some(u32) -> Option + 1044..1048 'Some': extern "rust-call" Some(u32) -> Option 1044..1058 'Some(x as u32)': Option 1049..1050 'x': i32 1049..1057 'x as u32': u32 @@ -2894,9 +2894,9 @@ fn test() { 175..185 'foo.test()': bool 191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown} 191..201 'bar.test()': bool - 207..213 'Struct': Struct(usize) -> Struct + 207..213 'Struct': extern "rust-call" Struct(usize) -> Struct 207..220 'Struct.test()': bool - 226..239 'Enum::Variant': Variant(usize) -> Enum + 226..239 'Enum::Variant': extern "rust-call" Variant(usize) -> Enum 226..246 'Enum::...test()': bool "#]], ); @@ -3424,7 +3424,7 @@ fn bin_op_with_rhs_is_self_for_assoc_bound() { fn repro(t: T) -> bool where T: Request, - T::Output: Convertable, + T::Output: Convertible, { let a = execute(&t).convert(); let b = execute(&t).convert(); @@ -3439,7 +3439,7 @@ where { ::output() } -trait Convertable { +trait Convertible { type TraitSelf: PartialEq; type AssocAsDefaultSelf: PartialEq; fn convert(self) -> Self::AssocAsDefaultSelf; @@ -3475,12 +3475,12 @@ fn main(){ 95..99 'self': Wrapper 101..104 'rhs': u32 122..150 '{ ... }': Wrapper - 132..139 'Wrapper': Wrapper(u32) -> Wrapper + 132..139 'Wrapper': extern "rust-call" Wrapper(u32) -> Wrapper 132..144 'Wrapper(rhs)': Wrapper 140..143 'rhs': u32 162..248 '{ ...um; }': () 172..179 'wrapped': Wrapper - 182..189 'Wrapper': Wrapper(u32) -> Wrapper + 182..189 'Wrapper': extern "rust-call" Wrapper(u32) -> Wrapper 182..193 'Wrapper(10)': Wrapper 190..192 '10': u32 203..206 'num': u32 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs index 83814ed0ec1f1..db5fa3205778d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs @@ -107,10 +107,7 @@ impl DebugContext<'_> { let name = match def { CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(), CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(), - CallableDefId::EnumVariantId(e) => { - let enum_data = self.0.enum_data(e.parent); - enum_data.variants[e.local_id].name.clone() - } + CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(), }; match def { CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index b6bc76bc98d53..3a1a4e63ea121 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -100,13 +100,14 @@ pub(crate) fn trait_solve_query( block: Option, goal: Canonical>, ) -> Option { - let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) { + let detail = match &goal.value.goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string() } GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(), _ => "??".to_string(), - }); + }; + let _p = tracing::span!(tracing::Level::INFO, "trait_solve_query", ?detail).entered(); tracing::info!("trait_solve_query({:?})", goal.value.goal); if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 75b8b9afa7085..c150314138ade 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -19,24 +19,23 @@ use hir_def::{ lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, - LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, + ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, Lookup, + OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, }; use hir_expand::name::Name; use intern::Interned; +use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; use stdx::never; -use triomphe::Arc; use crate::{ consteval::unknown_const, db::HirDatabase, layout::{Layout, TagEncoding}, mir::pad16, - ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitEnvironment, - TraitRef, TraitRefExt, Ty, WhereClause, + ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt, + Ty, WhereClause, }; pub(crate) fn fn_traits( @@ -193,7 +192,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { /// and it doesn't store the closure types and fields. /// /// Codes should not assume this ordering, and should always use methods available -/// on this struct for retriving, and `TyBuilder::substs_for_closure` for creating. +/// on this struct for retrieving, and `TyBuilder::substs_for_closure` for creating. pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution); impl<'a> ClosureSubst<'a> { @@ -355,7 +354,7 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).container, GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), + GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) @@ -432,25 +431,26 @@ impl FallibleTypeFolder for UnevaluatedConstEvaluatorFolder<'_> { pub(crate) fn detect_variant_from_bytes<'a>( layout: &'a Layout, db: &dyn HirDatabase, - trait_env: Arc, + target_data_layout: &TargetDataLayout, b: &[u8], e: EnumId, -) -> Option<(LocalEnumVariantId, &'a Layout)> { - let krate = trait_env.krate; +) -> Option<(EnumVariantId, &'a Layout)> { let (var_id, var_layout) = match &layout.variants { - hir_def::layout::Variants::Single { index } => (index.0, &*layout), + hir_def::layout::Variants::Single { index } => { + (db.enum_data(e).variants[index.0].0, layout) + } hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => { - let target_data_layout = db.target_data_layout(krate)?; - let size = tag.size(&*target_data_layout).bytes_usize(); + let size = tag.size(target_data_layout).bytes_usize(); let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field let tag = i128::from_le_bytes(pad16(&b[offset..offset + size], false)); match tag_encoding { TagEncoding::Direct => { - let x = variants.iter_enumerated().find(|x| { - db.const_eval_discriminant(EnumVariantId { parent: e, local_id: x.0 .0 }) - == Ok(tag) - })?; - (x.0 .0, x.1) + let (var_idx, layout) = + variants.iter_enumerated().find_map(|(var_idx, v)| { + let def = db.enum_data(e).variants[var_idx.0].0; + (db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v)) + })?; + (var_idx, layout) } TagEncoding::Niche { untagged_variant, niche_start, .. } => { let candidate_tag = tag.wrapping_sub(*niche_start as i128) as usize; @@ -460,7 +460,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( .filter(|x| x != untagged_variant) .nth(candidate_tag) .unwrap_or(*untagged_variant); - (variant.0, &variants[variant]) + (db.enum_data(e).variants[variant.0].0, &variants[variant]) } } } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index e4e4bcea6108d..7fea8372876ee 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -17,6 +17,7 @@ either.workspace = true arrayvec.workspace = true itertools.workspace = true smallvec.workspace = true +tracing.workspace = true triomphe.workspace = true once_cell = "1.17.1" @@ -30,9 +31,10 @@ profile.workspace = true stdx.workspace = true syntax.workspace = true tt.workspace = true +span.workspace = true [features] in-rust-tree = [] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 5a21f41dca84a..5c369f42e6e7d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -2,7 +2,6 @@ use std::ops::ControlFlow; -use base_db::FileId; use hir_def::{ attr::AttrsWithOwner, item_scope::ItemInNs, @@ -11,12 +10,8 @@ use hir_def::{ resolver::{HasResolver, Resolver, TypeNs}, AssocItemId, AttrDefId, ModuleDefId, }; -use hir_expand::{ - name::Name, - span_map::{RealSpanMap, SpanMapRef}, -}; +use hir_expand::{mod_path::PathKind, name::Name}; use hir_ty::{db::HirDatabase, method_resolution}; -use syntax::{ast, AstNode}; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -115,7 +110,7 @@ fn resolve_doc_path_on_( AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()), AttrDefId::AdtId(it) => it.resolver(db.upcast()), AttrDefId::FunctionId(it) => it.resolver(db.upcast()), - AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()), + AttrDefId::EnumVariantId(it) => it.resolver(db.upcast()), AttrDefId::StaticId(it) => it.resolver(db.upcast()), AttrDefId::ConstId(it) => it.resolver(db.upcast()), AttrDefId::TraitId(it) => it.resolver(db.upcast()), @@ -129,7 +124,7 @@ fn resolve_doc_path_on_( AttrDefId::GenericParamId(_) => return None, }; - let mut modpath = modpath_from_str(db, link)?; + let mut modpath = modpath_from_str(link)?; let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); if resolved.is_none() { @@ -244,10 +239,9 @@ fn resolve_impl_trait_item( ) -> Option { let canonical = ty.canonical(); let krate = ty.krate(db); - let environment = resolver.generic_def().map_or_else( - || crate::TraitEnvironment::empty(krate.id).into(), - |d| db.trait_environment(d), - ); + let environment = resolver + .generic_def() + .map_or_else(|| crate::TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); let traits_in_scope = resolver.traits_in_scope(db.upcast()); let mut result = None; @@ -302,37 +296,40 @@ fn as_module_def_if_namespace_matches( AssocItem::TypeAlias(it) => (ModuleDef::TypeAlias(it), Namespace::Types), }; - (ns.unwrap_or(expected_ns) == expected_ns).then(|| DocLinkDef::ModuleDef(def)) + (ns.unwrap_or(expected_ns) == expected_ns).then_some(DocLinkDef::ModuleDef(def)) } -fn modpath_from_str(db: &dyn HirDatabase, link: &str) -> Option { +fn modpath_from_str(link: &str) -> Option { // FIXME: this is not how we should get a mod path here. let try_get_modpath = |link: &str| { - let ast_path = ast::SourceFile::parse(&format!("type T = {link};")) - .syntax_node() - .descendants() - .find_map(ast::Path::cast)?; - if ast_path.syntax().text() != link { - return None; - } - ModPath::from_src( - db.upcast(), - ast_path, - SpanMapRef::RealSpanMap(&RealSpanMap::absolute(FileId::BOGUS)), - ) + let mut parts = link.split("::"); + let mut first_segment = None; + let kind = match parts.next()? { + "" => PathKind::Abs, + "crate" => PathKind::Crate, + "self" => PathKind::Super(0), + "super" => { + let mut deg = 1; + for segment in parts.by_ref() { + if segment == "super" { + deg += 1; + } else { + first_segment = Some(segment); + break; + } + } + PathKind::Super(deg) + } + segment => { + first_segment = Some(segment); + PathKind::Plain + } + }; + let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { + Ok(idx) => Name::new_tuple_field(idx), + Err(_) => Name::new_text_dont_use(segment.into()), + }); + Some(ModPath::from_segments(kind, parts)) }; - - let full = try_get_modpath(link); - if full.is_some() { - return full; - } - - // Tuple field names cannot be a part of `ModPath` usually, but rustdoc can - // resolve doc paths like `TupleStruct::0`. - // FIXME: Find a better way to handle these. - let (base, maybe_tuple_field) = link.rsplit_once("::")?; - let tuple_field = Name::new_tuple_field(maybe_tuple_field.parse().ok()?); - let mut modpath = try_get_modpath(base)?; - modpath.push_segment(tuple_field); - Some(modpath) + try_get_modpath(link) } diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index 403a6c88ab0f5..557c8d29a1731 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -7,19 +7,17 @@ pub use hir_def::db::{ AttrsQuery, BlockDefMapQuery, BlockItemTreeQueryQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQueryQuery, CrateLangItemsQuery, CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, - EnumDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery, + EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, - FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataQuery, - ImplDataWithDiagnosticsQuery, ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, - InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, - InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery, - InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, - InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery, - InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, - MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery, - StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery, - TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery, - UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery, + FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery, + ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase, + InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery, + InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query, + InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery, + InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, + InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, + StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery, + TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery, }; pub use hir_expand::db::{ AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage, diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index bf29a53913d1d..2d8f1dbad51a6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -4,11 +4,12 @@ //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; +use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDiagnostic}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use either::Either; -use hir_def::{path::ModPath, AssocItemId}; +use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId}; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; @@ -30,14 +31,28 @@ macro_rules! diagnostics { )* }; } +// FIXME Accept something like the following in the macro call instead +// diagnostics![ +// pub struct BreakOutsideOfLoop { +// pub expr: InFile>, +// pub is_break: bool, +// pub bad_value_break: bool, +// }, ... +// or more concisely +// BreakOutsideOfLoop { +// expr: InFile>, +// is_break: bool, +// bad_value_break: bool, +// }, ... +// ] diagnostics![ BreakOutsideOfLoop, ExpectedFunction, InactiveCode, + IncoherentImpl, IncorrectCase, InvalidDeriveTarget, - IncoherentImpl, MacroDefError, MacroError, MacroExpansionParseError, @@ -55,8 +70,8 @@ diagnostics![ ReplaceFilterMapNextWithFindMap, TraitImplIncorrectSafety, TraitImplMissingAssocItems, - TraitImplRedundantAssocItems, TraitImplOrphan, + TraitImplRedundantAssocItems, TypedHole, TypeMismatch, UndeclaredLabel, @@ -326,3 +341,219 @@ pub struct TraitImplRedundantAssocItems { pub impl_: AstPtr, pub assoc_item: (Name, AssocItem), } + +impl AnyDiagnostic { + pub(crate) fn body_validation_diagnostic( + db: &dyn HirDatabase, + diagnostic: BodyValidationDiagnostic, + source_map: &hir_def::body::BodySourceMap, + ) -> Option { + match diagnostic { + BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => { + let variant_data = variant.variant_data(db.upcast()); + let missed_fields = missed_fields + .into_iter() + .map(|idx| variant_data.fields()[idx].name.clone()) + .collect(); + + match record { + Either::Left(record_expr) => match source_map.expr_syntax(record_expr) { + Ok(source_ptr) => { + let root = source_ptr.file_syntax(db.upcast()); + if let ast::Expr::RecordExpr(record_expr) = + source_ptr.value.to_node(&root) + { + if record_expr.record_expr_field_list().is_some() { + let field_list_parent_path = + record_expr.path().map(|path| AstPtr::new(&path)); + return Some( + MissingFields { + file: source_ptr.file_id, + field_list_parent: AstPtr::new(&Either::Left( + record_expr, + )), + field_list_parent_path, + missed_fields, + } + .into(), + ); + } + } + } + Err(SyntheticSyntax) => (), + }, + Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { + Ok(source_ptr) => { + if let Some(ptr) = source_ptr.value.cast::() { + let root = source_ptr.file_syntax(db.upcast()); + let record_pat = ptr.to_node(&root); + if record_pat.record_pat_field_list().is_some() { + let field_list_parent_path = + record_pat.path().map(|path| AstPtr::new(&path)); + return Some( + MissingFields { + file: source_ptr.file_id, + field_list_parent: AstPtr::new(&Either::Right( + record_pat, + )), + field_list_parent_path, + missed_fields, + } + .into(), + ); + } + } + } + Err(SyntheticSyntax) => (), + }, + } + } + BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { + if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { + return Some( + ReplaceFilterMapNextWithFindMap { + file: next_source_ptr.file_id, + next_expr: next_source_ptr.value, + } + .into(), + ); + } + } + BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => { + match source_map.expr_syntax(match_expr) { + Ok(source_ptr) => { + let root = source_ptr.file_syntax(db.upcast()); + if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { + match match_expr.expr() { + Some(scrut_expr) if match_expr.match_arm_list().is_some() => { + return Some( + MissingMatchArms { + scrutinee_expr: InFile::new( + source_ptr.file_id, + AstPtr::new(&scrut_expr), + ), + uncovered_patterns, + } + .into(), + ); + } + _ => {} + } + } + } + Err(SyntheticSyntax) => (), + } + } + } + None + } + + pub(crate) fn inference_diagnostic( + db: &dyn HirDatabase, + def: DefWithBodyId, + d: &InferenceDiagnostic, + source_map: &hir_def::body::BodySourceMap, + ) -> Option { + let expr_syntax = |expr| source_map.expr_syntax(expr).expect("unexpected synthetic"); + let pat_syntax = |pat| source_map.pat_syntax(pat).expect("unexpected synthetic"); + Some(match d { + &InferenceDiagnostic::NoSuchField { field: expr, private } => { + let expr_or_pat = match expr { + ExprOrPatId::ExprId(expr) => { + source_map.field_syntax(expr).map(AstPtr::wrap_left) + } + ExprOrPatId::PatId(pat) => { + source_map.pat_field_syntax(pat).map(AstPtr::wrap_right) + } + }; + NoSuchField { field: expr_or_pat, private }.into() + } + &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { + MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found }.into() + } + &InferenceDiagnostic::PrivateField { expr, field } => { + let expr = expr_syntax(expr); + let field = field.into(); + PrivateField { expr, field }.into() + } + &InferenceDiagnostic::PrivateAssocItem { id, item } => { + let expr_or_pat = match id { + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), + ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right), + }; + let item = item.into(); + PrivateAssocItem { expr_or_pat, item }.into() + } + InferenceDiagnostic::ExpectedFunction { call_expr, found } => { + let call_expr = expr_syntax(*call_expr); + ExpectedFunction { call: call_expr, found: Type::new(db, def, found.clone()) } + .into() + } + InferenceDiagnostic::UnresolvedField { + expr, + receiver, + name, + method_with_same_name_exists, + } => { + let expr = expr_syntax(*expr); + UnresolvedField { + expr, + name: name.clone(), + receiver: Type::new(db, def, receiver.clone()), + method_with_same_name_exists: *method_with_same_name_exists, + } + .into() + } + InferenceDiagnostic::UnresolvedMethodCall { + expr, + receiver, + name, + field_with_same_name, + assoc_func_with_same_name, + } => { + let expr = expr_syntax(*expr); + UnresolvedMethodCall { + expr, + name: name.clone(), + receiver: Type::new(db, def, receiver.clone()), + field_with_same_name: field_with_same_name + .clone() + .map(|ty| Type::new(db, def, ty)), + assoc_func_with_same_name: *assoc_func_with_same_name, + } + .into() + } + &InferenceDiagnostic::UnresolvedAssocItem { id } => { + let expr_or_pat = match id { + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), + ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right), + }; + UnresolvedAssocItem { expr_or_pat }.into() + } + &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => { + let expr = expr_syntax(expr); + BreakOutsideOfLoop { expr, is_break, bad_value_break }.into() + } + InferenceDiagnostic::TypedHole { expr, expected } => { + let expr = expr_syntax(*expr); + TypedHole { expr, expected: Type::new(db, def, expected.clone()) }.into() + } + &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => { + let expr_or_pat = match pat { + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), + ExprOrPatId::PatId(pat) => { + let InFile { file_id, value } = + source_map.pat_syntax(pat).expect("unexpected synthetic"); + + // cast from Either -> Either<_, Pat> + let Some(ptr) = AstPtr::try_from_raw(value.syntax_node_ptr()) else { + return None; + }; + InFile { file_id, value: ptr } + } + }; + MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into() + } + }) + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index fc4bbffdb8361..887227bf4d071 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -93,13 +93,13 @@ impl From for GenericParamId { impl From for Variant { fn from(id: EnumVariantId) -> Self { - Variant { parent: id.parent.into(), id: id.local_id } + Variant { id } } } impl From for EnumVariantId { fn from(def: Variant) -> Self { - EnumVariantId { parent: def.parent.id, local_id: def.id } + def.id } } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 31cf8ba336434..d10884517f92d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -116,7 +116,7 @@ impl HasSource for Enum { impl HasSource for Variant { type Ast = ast::Variant; fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())) + Some(self.id.lookup(db.upcast()).source(db.upcast())) } } impl HasSource for Function { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 3180a2b713a89..1e21045e9818b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -24,12 +24,12 @@ mod semantics; mod source_analyzer; -mod from_id; mod attrs; +mod from_id; mod has_source; -pub mod diagnostics; pub mod db; +pub mod diagnostics; pub mod symbols; mod display; @@ -44,7 +44,7 @@ use hir_def::{ data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, - item_tree::ItemTreeNode, + item_tree::ItemTreeModItemNode, lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, @@ -54,14 +54,14 @@ use hir_def::{ src::HasSource as _, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, - ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, - Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, - TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, + MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind}; use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, - consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, + consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, diagnostics::BodyValidationDiagnostic, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, @@ -76,12 +76,11 @@ use hir_ty::{ }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; -use once_cell::unsync::Lazy; use rustc_hash::FxHashSet; use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasName}, - AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, + format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, }; use triomphe::Arc; @@ -132,8 +131,10 @@ pub use { MacroFileIdExt, }, hir_ty::{ + consteval::ConstEvalError, display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, layout::LayoutError, + mir::{MirEvalError, MirLowerError}, PointerCast, Safety, }, // FIXME: Properly encapsulate mir @@ -234,8 +235,8 @@ impl Crate { db: &dyn DefDatabase, query: import_map::Query, ) -> impl Iterator> { - let _p = profile::span("query_external_importables"); - import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| { + let _p = tracing::span!(tracing::Level::INFO, "query_external_importables"); + import_map::search_dependencies(db, self.into(), &query).into_iter().map(|item| { match ItemInNs::from(item) { ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id), ItemInNs::Macros(mac_id) => Either::Right(mac_id), @@ -375,9 +376,7 @@ impl ModuleDef { ModuleDef::Module(it) => it.id.into(), ModuleDef::Const(it) => it.id.into(), ModuleDef::Static(it) => it.id.into(), - ModuleDef::Variant(it) => { - EnumVariantId { parent: it.parent.into(), local_id: it.id }.into() - } + ModuleDef::Variant(it) => it.id.into(), ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(), }; @@ -540,13 +539,8 @@ impl Module { /// Fills `acc` with the module's diagnostics. pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { - let _p = profile::span("Module::diagnostics").detail(|| { - format!( - "{:?}", - self.name(db) - .map_or("".into(), |name| name.display(db.upcast()).to_string()) - ) - }); + let name = self.name(db); + let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", ?name); let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { if diag.in_module != self.id.local_id { @@ -586,10 +580,9 @@ impl Module { Adt::Enum(e) => { for v in e.variants(db) { acc.extend(ModuleDef::Variant(v).diagnostics(db)); - } - - for diag in db.enum_data_with_diagnostics(e.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { + emit_def_diagnostic(db, acc, diag); + } } } } @@ -910,7 +903,7 @@ fn emit_def_diagnostic_( } DefDiagnosticKind::InvalidDeriveTarget { ast, id } => { let node = ast.to_node(db.upcast()); - let derive = node.attrs().nth(*id as usize); + let derive = node.attrs().nth(*id); match derive { Some(derive) => { acc.push( @@ -925,7 +918,7 @@ fn emit_def_diagnostic_( } DefDiagnosticKind::MalformedDerive { ast, id } => { let node = ast.to_node(db.upcast()); - let derive = node.attrs().nth(*id as usize); + let derive = node.attrs().nth(*id); match derive { Some(derive) => { acc.push( @@ -1084,7 +1077,7 @@ impl Field { let generic_def_id: GenericDefId = match self.parent { VariantDef::Struct(it) => it.id.into(), VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.parent.id.into(), + VariantDef::Variant(it) => it.id.into(), }; let substs = TyBuilder::placeholder_subst(db, generic_def_id); let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); @@ -1224,7 +1217,7 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec { - db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() + db.enum_data(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect() } pub fn repr(self, db: &dyn HirDatabase) -> Option { @@ -1292,25 +1285,24 @@ impl From<&Variant> for DefWithBodyId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Variant { - pub(crate) parent: Enum, - pub(crate) id: LocalEnumVariantId, + pub(crate) id: EnumVariantId, } impl Variant { pub fn module(self, db: &dyn HirDatabase) -> Module { - self.parent.module(db) + Module { id: self.id.module(db.upcast()) } } - pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { - self.parent + pub fn parent_enum(self, db: &dyn HirDatabase) -> Enum { + self.id.lookup(db.upcast()).parent.into() } pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { - Type::from_value_def(db, EnumVariantId { parent: self.parent.id, local_id: self.id }) + Type::from_value_def(db, self.id) } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.enum_data(self.parent.id).variants[self.id].name.clone() + db.enum_variant_data(self.id).name.clone() } pub fn fields(self, db: &dyn HirDatabase) -> Vec { @@ -1326,7 +1318,7 @@ impl Variant { } pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc { - db.enum_data(self.parent.id).variants[self.id].variant_data.clone() + db.enum_variant_data(self.id).variant_data.clone() } pub fn value(self, db: &dyn HirDatabase) -> Option { @@ -1342,7 +1334,11 @@ impl Variant { let parent_layout = parent_enum.layout(db)?; Ok(match &parent_layout.0.variants { layout::Variants::Multiple { variants, .. } => Layout( - Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()), + { + let lookup = self.id.lookup(db.upcast()); + let rustc_enum_variant_idx = RustcEnumVariantIdx(lookup.index as usize); + Arc::new(variants[rustc_enum_variant_idx].clone()) + }, db.target_data_layout(parent_enum.krate(db).into()).unwrap(), ), _ => parent_layout, @@ -1439,7 +1435,7 @@ impl Adt { resolver .generic_params() .and_then(|gp| { - (&gp.lifetimes) + gp.lifetimes .iter() // there should only be a single lifetime // but `Arena` requires to use an iterator @@ -1547,7 +1543,7 @@ impl DefWithBody { DefWithBody::Function(it) => it.ret_type(db), DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), - DefWithBody::Variant(it) => it.parent.variant_body_ty(db), + DefWithBody::Variant(it) => it.parent_enum(db).variant_body_ty(db), DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner( db, &DefWithBodyId::from(it.id).resolver(db.upcast()), @@ -1592,182 +1588,43 @@ impl DefWithBody { } for diag in source_map.diagnostics() { - match diag { - BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push( - InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } - .into(), - ), - BodyDiagnostic::MacroError { node, message } => acc.push( - MacroError { - node: node.clone().map(|it| it.into()), - precise_location: None, - message: message.to_string(), - } - .into(), - ), - BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push( - UnresolvedProcMacro { - node: node.clone().map(|it| it.into()), - precise_location: None, - macro_name: None, - kind: MacroKind::ProcMacro, - krate: *krate, - } - .into(), - ), - BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push( - UnresolvedMacroCall { - macro_call: node.clone().map(|ast_ptr| ast_ptr.into()), - precise_location: None, - path: path.clone(), - is_bang: true, - } - .into(), - ), + acc.push(match diag { + BodyDiagnostic::InactiveCode { node, cfg, opts } => { + InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into() + } + BodyDiagnostic::MacroError { node, message } => MacroError { + node: (*node).map(|it| it.into()), + precise_location: None, + message: message.to_string(), + } + .into(), + BodyDiagnostic::UnresolvedProcMacro { node, krate } => UnresolvedProcMacro { + node: (*node).map(|it| it.into()), + precise_location: None, + macro_name: None, + kind: MacroKind::ProcMacro, + krate: *krate, + } + .into(), + BodyDiagnostic::UnresolvedMacroCall { node, path } => UnresolvedMacroCall { + macro_call: (*node).map(|ast_ptr| ast_ptr.into()), + precise_location: None, + path: path.clone(), + is_bang: true, + } + .into(), BodyDiagnostic::UnreachableLabel { node, name } => { - acc.push(UnreachableLabel { node: node.clone(), name: name.clone() }.into()) + UnreachableLabel { node: *node, name: name.clone() }.into() } BodyDiagnostic::UndeclaredLabel { node, name } => { - acc.push(UndeclaredLabel { node: node.clone(), name: name.clone() }.into()) + UndeclaredLabel { node: *node, name: name.clone() }.into() } - } + }); } let infer = db.infer(self.into()); - let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1); - let expr_syntax = |expr| source_map.expr_syntax(expr).expect("unexpected synthetic"); - let pat_syntax = |pat| source_map.pat_syntax(pat).expect("unexpected synthetic"); for d in &infer.diagnostics { - match d { - &hir_ty::InferenceDiagnostic::NoSuchField { field: expr, private } => { - let expr_or_pat = match expr { - ExprOrPatId::ExprId(expr) => { - source_map.field_syntax(expr).map(AstPtr::wrap_left) - } - ExprOrPatId::PatId(pat) => { - source_map.pat_field_syntax(pat).map(AstPtr::wrap_right) - } - }; - acc.push(NoSuchField { field: expr_or_pat, private }.into()) - } - &hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { - acc.push( - MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found } - .into(), - ) - } - &hir_ty::InferenceDiagnostic::PrivateField { expr, field } => { - let expr = expr_syntax(expr); - let field = field.into(); - acc.push(PrivateField { expr, field }.into()) - } - &hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => { - let expr_or_pat = match id { - ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), - ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right), - }; - let item = item.into(); - acc.push(PrivateAssocItem { expr_or_pat, item }.into()) - } - hir_ty::InferenceDiagnostic::ExpectedFunction { call_expr, found } => { - let call_expr = expr_syntax(*call_expr); - - acc.push( - ExpectedFunction { - call: call_expr, - found: Type::new(db, DefWithBodyId::from(self), found.clone()), - } - .into(), - ) - } - hir_ty::InferenceDiagnostic::UnresolvedField { - expr, - receiver, - name, - method_with_same_name_exists, - } => { - let expr = expr_syntax(*expr); - - acc.push( - UnresolvedField { - expr, - name: name.clone(), - receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()), - method_with_same_name_exists: *method_with_same_name_exists, - } - .into(), - ) - } - hir_ty::InferenceDiagnostic::UnresolvedMethodCall { - expr, - receiver, - name, - field_with_same_name, - assoc_func_with_same_name, - } => { - let expr = expr_syntax(*expr); - - acc.push( - UnresolvedMethodCall { - expr, - name: name.clone(), - receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()), - field_with_same_name: field_with_same_name - .clone() - .map(|ty| Type::new(db, DefWithBodyId::from(self), ty)), - assoc_func_with_same_name: assoc_func_with_same_name.clone(), - } - .into(), - ) - } - &hir_ty::InferenceDiagnostic::UnresolvedAssocItem { id } => { - let expr_or_pat = match id { - ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), - ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right), - }; - acc.push(UnresolvedAssocItem { expr_or_pat }.into()) - } - &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { - expr, - is_break, - bad_value_break, - } => { - let expr = expr_syntax(expr); - acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()) - } - hir_ty::InferenceDiagnostic::TypedHole { expr, expected } => { - let expr = expr_syntax(*expr); - acc.push( - TypedHole { - expr, - expected: Type::new(db, DefWithBodyId::from(self), expected.clone()), - } - .into(), - ) - } - &hir_ty::InferenceDiagnostic::MismatchedTupleStructPatArgCount { - pat, - expected, - found, - } => { - let expr_or_pat = match pat { - ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), - ExprOrPatId::PatId(pat) => { - let InFile { file_id, value } = - source_map.pat_syntax(pat).expect("unexpected synthetic"); - - // cast from Either -> Either<_, Pat> - let Some(ptr) = AstPtr::try_from_raw(value.syntax_node_ptr()) else { - continue; - }; - InFile { file_id, value: ptr } - } - }; - acc.push( - MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into(), - ) - } - } + acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map)); } for (pat_or_expr, mismatch) in infer.type_mismatches() { let expr_or_pat = match pat_or_expr { @@ -1806,8 +1663,6 @@ impl DefWithBody { } } - let hir_body = db.body(self.into()); - if let Ok(borrowck_results) = db.borrowck(self.into()) { for borrowck_result in borrowck_results.iter() { let mir_body = &borrowck_result.mir_body; @@ -1829,7 +1684,7 @@ impl DefWithBody { ) } let mol = &borrowck_result.mutability_of_locals; - for (binding_id, binding_data) in hir_body.bindings.iter() { + for (binding_id, binding_data) in body.bindings.iter() { if binding_data.problems.is_some() { // We should report specific diagnostics for these problems, not `need-mut` and `unused-mut`. continue; @@ -1891,110 +1746,7 @@ impl DefWithBody { } for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) { - match diagnostic { - BodyValidationDiagnostic::RecordMissingFields { - record, - variant, - missed_fields, - } => { - let variant_data = variant.variant_data(db.upcast()); - let missed_fields = missed_fields - .into_iter() - .map(|idx| variant_data.fields()[idx].name.clone()) - .collect(); - - match record { - Either::Left(record_expr) => match source_map.expr_syntax(record_expr) { - Ok(source_ptr) => { - let root = source_ptr.file_syntax(db.upcast()); - if let ast::Expr::RecordExpr(record_expr) = - source_ptr.value.to_node(&root) - { - if record_expr.record_expr_field_list().is_some() { - let field_list_parent_path = - record_expr.path().map(|path| AstPtr::new(&path)); - acc.push( - MissingFields { - file: source_ptr.file_id, - field_list_parent: AstPtr::new(&Either::Left( - record_expr, - )), - field_list_parent_path, - missed_fields, - } - .into(), - ) - } - } - } - Err(SyntheticSyntax) => (), - }, - Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { - Ok(source_ptr) => { - if let Some(ptr) = source_ptr.value.clone().cast::() - { - let root = source_ptr.file_syntax(db.upcast()); - let record_pat = ptr.to_node(&root); - if record_pat.record_pat_field_list().is_some() { - let field_list_parent_path = - record_pat.path().map(|path| AstPtr::new(&path)); - acc.push( - MissingFields { - file: source_ptr.file_id, - field_list_parent: AstPtr::new(&Either::Right( - record_pat, - )), - field_list_parent_path, - missed_fields, - } - .into(), - ) - } - } - } - Err(SyntheticSyntax) => (), - }, - } - } - BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { - if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { - acc.push( - ReplaceFilterMapNextWithFindMap { - file: next_source_ptr.file_id, - next_expr: next_source_ptr.value, - } - .into(), - ); - } - } - BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => { - match source_map.expr_syntax(match_expr) { - Ok(source_ptr) => { - let root = source_ptr.file_syntax(db.upcast()); - if let ast::Expr::MatchExpr(match_expr) = - &source_ptr.value.to_node(&root) - { - match match_expr.expr() { - Some(scrut_expr) if match_expr.match_arm_list().is_some() => { - acc.push( - MissingMatchArms { - scrutinee_expr: InFile::new( - source_ptr.file_id, - AstPtr::new(&scrut_expr), - ), - uncovered_patterns, - } - .into(), - ); - } - _ => {} - } - } - } - Err(SyntheticSyntax) => (), - } - } - } + acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map)); } let def: ModuleDef = match self { @@ -2010,7 +1762,6 @@ impl DefWithBody { } } } - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Function { pub(crate) id: FunctionId, @@ -2083,9 +1834,7 @@ impl Function { } pub fn method_params(self, db: &dyn HirDatabase) -> Option> { - if self.self_param(db).is_none() { - return None; - } + self.self_param(db)?; Some(self.params_without_self(db)) } @@ -2406,10 +2155,10 @@ impl Const { } } if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) { - return Ok(s); + Ok(s) + } else { + Ok(format!("{}", c.display(db))) } - let r = format!("{}", c.display(db)); - return Ok(r); } } @@ -2497,14 +2246,7 @@ impl Trait { db.generic_params(GenericDefId::from(self.id)) .type_or_consts .iter() - .filter(|(_, ty)| match ty { - TypeOrConstParamData::TypeParamData(ty) - if ty.provenance != TypeParamProvenance::TypeParamList => - { - false - } - _ => true, - }) + .filter(|(_, ty)| !matches!(ty, TypeOrConstParamData::TypeParamData(ty) if ty.provenance != TypeParamProvenance::TypeParamList)) .filter(|(_, ty)| !count_required_only || !ty.has_default()) .count() } @@ -2828,7 +2570,7 @@ where ID: Lookup = dyn DefDatabase + 'db, Data = AssocItemLoc>, DEF: From, CTOR: FnOnce(DEF) -> AssocItem, - AST: ItemTreeNode, + AST: ItemTreeModItemNode, { match id.lookup(db.upcast()).container { ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), @@ -2844,6 +2586,7 @@ impl AssocItem { AssocItem::TypeAlias(it) => Some(it.name(db)), } } + pub fn module(self, db: &dyn HirDatabase) -> Module { match self { AssocItem::Function(f) => f.module(db), @@ -2851,6 +2594,7 @@ impl AssocItem { AssocItem::TypeAlias(t) => t.module(db), } } + pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { let container = match self { AssocItem::Function(it) => it.id.lookup(db.upcast()).container, @@ -2886,6 +2630,27 @@ impl AssocItem { AssocItemContainer::Impl(i) => i.trait_(db), } } + + pub fn as_function(self) -> Option { + match self { + Self::Function(v) => Some(v), + _ => None, + } + } + + pub fn as_const(self) -> Option { + match self { + Self::Const(v) => Some(v), + _ => None, + } + } + + pub fn as_type_alias(self) -> Option { + match self { + Self::TypeAlias(v) => Some(v), + _ => None, + } + } } impl HasVisibility for AssocItem { @@ -3024,6 +2789,7 @@ impl LocalSource { impl Local { pub fn is_param(self, db: &dyn HirDatabase) -> bool { + // FIXME: This parses! let src = self.primary_source(db); match src.source.value { Either::Left(pat) => pat @@ -3139,7 +2905,7 @@ impl DeriveHelper { .and_then(|it| it.get(self.idx as usize)) .cloned(), } - .unwrap_or_else(|| Name::missing()) + .unwrap_or_else(Name::missing) } } @@ -3786,7 +3552,9 @@ impl Type { } fn from_value_def(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { - let ty = db.value_ty(def.into()); + let Some(ty) = db.value_ty(def.into()) else { + return Type::new(db, def, TyKind::Error.intern(Interner)); + }; let substs = TyBuilder::unknown_subst( db, match def.into() { @@ -3848,10 +3616,7 @@ impl Type { } pub fn is_int_or_uint(&self) -> bool { - match self.ty.kind(Interner) { - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) => true, - _ => false, - } + matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) } pub fn is_scalar(&self) -> bool { @@ -4103,8 +3868,8 @@ impl Type { | TyKind::Function(_) | TyKind::Alias(_) | TyKind::Foreign(_) - | TyKind::Generator(..) - | TyKind::GeneratorWitness(..) => false, + | TyKind::Coroutine(..) + | TyKind::CoroutineWitness(..) => false, } } } @@ -4258,11 +4023,9 @@ impl Type { .filter_map(|arg| { // arg can be either a `Ty` or `constant` if let Some(ty) = arg.ty(Interner) { - Some(SmolStr::new(ty.display(db).to_string())) - } else if let Some(const_) = arg.constant(Interner) { - Some(SmolStr::new_inline(&const_.display(db).to_string())) + Some(format_smolstr!("{}", ty.display(db))) } else { - None + arg.constant(Interner).map(|const_| format_smolstr!("{}", const_.display(db))) } }) } @@ -4274,7 +4037,7 @@ impl Type { ) -> impl Iterator + 'a { // iterate the lifetime self.as_adt() - .and_then(|a| a.lifetime(db).and_then(|lt| Some((<.name).to_smol_str()))) + .and_then(|a| a.lifetime(db).map(|lt| lt.name.to_smol_str())) .into_iter() // add the type and const parameters .chain(self.type_and_const_arguments(db)) @@ -4289,7 +4052,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(Function) -> Option, ) -> Option { - let _p = profile::span("iterate_method_candidates"); + let _p = tracing::span!(tracing::Level::INFO, "iterate_method_candidates"); let mut slot = None; self.iterate_method_candidates_dyn( @@ -4368,7 +4131,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(AssocItem) -> Option, ) -> Option { - let _p = profile::span("iterate_path_candidates"); + let _p = tracing::span!(tracing::Level::INFO, "iterate_path_candidates"); let mut slot = None; self.iterate_path_candidates_dyn( db, @@ -4411,7 +4174,7 @@ impl Type { traits_in_scope, with_local_impls.and_then(|b| b.id.containing_block()).into(), name, - &mut |id| callback(id), + callback, ); } @@ -4434,7 +4197,7 @@ impl Type { &'a self, db: &'a dyn HirDatabase, ) -> impl Iterator + 'a { - let _p = profile::span("applicable_inherent_traits"); + let _p = tracing::span!(tracing::Level::INFO, "applicable_inherent_traits"); self.autoderef_(db) .filter_map(|ty| ty.dyn_trait()) .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) @@ -4442,7 +4205,7 @@ impl Type { } pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { - let _p = profile::span("env_traits"); + let _p = tracing::span!(tracing::Level::INFO, "env_traits"); self.autoderef_(db) .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) .flat_map(|ty| { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index f51fe80931c6f..a869029d09663 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -25,6 +25,7 @@ use hir_expand::{ use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; +use span::{Span, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, @@ -131,6 +132,7 @@ pub struct SemanticsImpl<'db> { /// Rootnode to HirFileId cache cache: RefCell>, // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens + // So we might wanna move them out into something specific for semantic highlighting expansion_info_cache: RefCell>, /// MacroCall to its expansion's MacroFileId cache macro_call_cache: RefCell, MacroFileId>>, @@ -433,7 +435,7 @@ impl<'db> SemanticsImpl<'db> { .find_map(|token| { self.resolve_offset_in_format_args( ast::String::cast(token)?, - offset - quote.end(), + offset.checked_sub(quote.end())?, ) }) .map(|(range, res)| (range + quote.end(), res)); @@ -607,29 +609,102 @@ impl<'db> SemanticsImpl<'db> { res } - fn descend_into_macros_impl( + // return: + // SourceAnalyzer(file_id that original call include!) + // macro file id + // token in include! macro mapped from token in params + // span for the mapped token + fn is_from_include_file( &self, token: SyntaxToken, - f: &mut dyn FnMut(InFile) -> ControlFlow<()>, - ) { - let _p = profile::span("descend_into_macros"); - let sa = match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) { - Some(it) => it, - None => return, - }; + ) -> Option<(SourceAnalyzer, HirFileId, SyntaxToken, Span)> { + let parent = token.parent()?; + let file_id = self.find_file(&parent).file_id.file_id()?; - let span = match sa.file_id.file_id() { - Some(file_id) => self.db.real_span_map(file_id).span_for_range(token.text_range()), - None => { - stdx::never!(); - return; + let mut cache = self.expansion_info_cache.borrow_mut(); + + // iterate related crates and find all include! invocations that include_file_id matches + for (invoc, _) in self + .db + .relevant_crates(file_id) + .iter() + .flat_map(|krate| self.db.include_macro_invoc(*krate)) + .filter(|&(_, include_file_id)| include_file_id == file_id) + { + let macro_file = invoc.as_macro_file(); + let expansion_info = cache + .entry(macro_file) + .or_insert_with(|| macro_file.expansion_info(self.db.upcast())); + + // Create the source analyzer for the macro call scope + let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file())) + else { + continue; + }; + { + let InMacroFile { file_id: macro_file, value } = expansion_info.expanded(); + self.cache(value, macro_file.into()); } - }; + + // get mapped token in the include! macro file + let span = span::SpanData { + range: token.text_range(), + anchor: span::SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, + ctx: SyntaxContextId::ROOT, + }; + let Some(InMacroFile { file_id, value: mut mapped_tokens }) = + expansion_info.map_range_down(span) + else { + continue; + }; + + // if we find one, then return + if let Some(t) = mapped_tokens.next() { + return Some((sa, file_id.into(), t, span)); + } + } + + None + } + + fn descend_into_macros_impl( + &self, + mut token: SyntaxToken, + f: &mut dyn FnMut(InFile) -> ControlFlow<()>, + ) { + let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros"); + let (sa, span, file_id) = + match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) { + Some(sa) => match sa.file_id.file_id() { + Some(file_id) => ( + sa, + self.db.real_span_map(file_id).span_for_range(token.text_range()), + file_id.into(), + ), + None => { + stdx::never!(); + return; + } + }, + None => { + // if we cannot find a source analyzer for this token, then we try to find out + // whether this file is an included file and treat that as the include input + let Some((it, macro_file_id, mapped_token, s)) = + self.is_from_include_file(token) + else { + return; + }; + token = mapped_token; + (it, s, macro_file_id) + } + }; let mut cache = self.expansion_info_cache.borrow_mut(); let mut mcache = self.macro_call_cache.borrow_mut(); let def_map = sa.resolver.def_map(); + let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])]; + let mut process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { let expansion_info = cache .entry(macro_file) @@ -651,18 +726,14 @@ impl<'db> SemanticsImpl<'db> { res }; - let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(sa.file_id, smallvec![token])]; - while let Some((file_id, mut tokens)) = stack.pop() { while let Some(token) = tokens.pop() { let was_not_remapped = (|| { // First expand into attribute invocations let containing_attribute_macro_call = self.with_ctx(|ctx| { token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| { - if item.attrs().next().is_none() { - // Don't force populate the dyn cache for items that don't have an attribute anyways - return None; - } + // Don't force populate the dyn cache for items that don't have an attribute anyways + item.attrs().next()?; Some(( ctx.item_to_macro_call(InFile::new(file_id, item.clone()))?, item, @@ -1008,9 +1079,7 @@ impl<'db> SemanticsImpl<'db> { // Update `source_ty` for the next adjustment let source = mem::replace(&mut source_ty, target.clone()); - let adjustment = Adjustment { source, target, kind }; - - adjustment + Adjustment { source, target, kind } }) .collect() }) @@ -1226,7 +1295,7 @@ impl<'db> SemanticsImpl<'db> { offset: Option, infer_body: bool, ) -> Option { - let _p = profile::span("Semantics::analyze_impl"); + let _p = tracing::span!(tracing::Level::INFO, "Semantics::analyze_impl"); let node = self.find_file(node); let container = self.with_ctx(|ctx| ctx.find_container(node))?; @@ -1255,7 +1324,7 @@ impl<'db> SemanticsImpl<'db> { assert!(root_node.parent().is_none()); let mut cache = self.cache.borrow_mut(); let prev = cache.insert(root_node, file_id); - assert!(prev == None || prev == Some(file_id)) + assert!(prev.is_none() || prev == Some(file_id)) } pub fn assert_contains_node(&self, node: &SyntaxNode) { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index df8c1e904fe89..14dbe6924032f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -117,7 +117,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> { impl SourceToDefCtx<'_, '_> { pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> { - let _p = profile::span("SourceBinder::to_module_def"); + let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::to_module_def"); let mut mods = SmallVec::new(); for &crate_id in self.db.relevant_crates(file).iter() { // FIXME: inner items @@ -132,7 +132,7 @@ impl SourceToDefCtx<'_, '_> { } pub(super) fn module_to_def(&self, src: InFile) -> Option { - let _p = profile::span("module_to_def"); + let _p = tracing::span!(tracing::Level::INFO, "module_to_def"); let parent_declaration = src .syntax() .ancestors_with_macros_skip_attr_item(self.db.upcast()) @@ -142,7 +142,7 @@ impl SourceToDefCtx<'_, '_> { Some(parent_declaration) => self.module_to_def(parent_declaration), None => { let file_id = src.file_id.original_file(self.db.upcast()); - self.file_to_def(file_id).get(0).copied() + self.file_to_def(file_id).first().copied() } }?; @@ -153,9 +153,9 @@ impl SourceToDefCtx<'_, '_> { } pub(super) fn source_file_to_def(&self, src: InFile) -> Option { - let _p = profile::span("source_file_to_def"); + let _p = tracing::span!(tracing::Level::INFO, "source_file_to_def"); let file_id = src.file_id.original_file(self.db.upcast()); - self.file_to_def(file_id).get(0).copied() + self.file_to_def(file_id).first().copied() } pub(super) fn trait_to_def(&mut self, src: InFile) -> Option { @@ -201,7 +201,7 @@ impl SourceToDefCtx<'_, '_> { &mut self, src: InFile, ) -> Option { - self.to_def(src, keys::VARIANT) + self.to_def(src, keys::ENUM_VARIANT) } pub(super) fn extern_crate_to_def( &mut self, @@ -308,7 +308,7 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn type_param_to_def(&mut self, src: InFile) -> Option { let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); let dyn_map = self.cache_for(container, src.file_id); - dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|it| TypeParamId::from_unchecked(it)) + dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(TypeParamId::from_unchecked) } pub(super) fn lifetime_param_to_def( @@ -326,10 +326,7 @@ impl SourceToDefCtx<'_, '_> { ) -> Option { let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); let dyn_map = self.cache_for(container, src.file_id); - dyn_map[keys::CONST_PARAM] - .get(&src.value) - .copied() - .map(|it| ConstParamId::from_unchecked(it)) + dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(ConstParamId::from_unchecked) } pub(super) fn generic_param_to_def( @@ -370,7 +367,7 @@ impl SourceToDefCtx<'_, '_> { } } - let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; + let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).first().copied()?; Some(def.into()) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 73f8db762ae83..fd0a117842151 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -197,10 +197,8 @@ impl SourceAnalyzer { ) -> Option<(Type, Option)> { let pat_id = self.pat_id(pat)?; let infer = self.infer.as_ref()?; - let coerced = infer - .pat_adjustments - .get(&pat_id) - .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone())); + let coerced = + infer.pat_adjustments.get(&pat_id).and_then(|adjusts| adjusts.last().cloned()); let ty = infer[pat_id].clone(); let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); Some((mk_ty(ty), coerced.map(mk_ty))) @@ -268,7 +266,7 @@ impl SourceAnalyzer { ) -> Option { let expr_id = self.expr_id(db, &call.clone().into())?; let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; - let ty = db.value_ty(func.into()).substitute(Interner, &substs); + let ty = db.value_ty(func.into())?.substitute(Interner, &substs); let ty = Type::new_with_resolver(db, &self.resolver, ty); let mut res = ty.as_callable(db)?; res.is_bound_method = true; @@ -616,7 +614,7 @@ impl SourceAnalyzer { } None })(); - if let Some(_) = resolved { + if resolved.is_some() { return resolved; } @@ -661,7 +659,7 @@ impl SourceAnalyzer { if let Some(name_ref) = path.as_single_name_ref() { let builtin = BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text()); - if let Some(_) = builtin { + if builtin.is_some() { return builtin.map(PathResolution::BuiltinAttr); } diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index e1101dd8236e6..28ac5940e6922 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -262,9 +262,7 @@ impl<'a> SymbolCollector<'a> { DefWithBodyId::FunctionId(id) => Some(self.db.function_data(id).name.to_smol_str()), DefWithBodyId::StaticId(id) => Some(self.db.static_data(id).name.to_smol_str()), DefWithBodyId::ConstId(id) => Some(self.db.const_data(id).name.as_ref()?.to_smol_str()), - DefWithBodyId::VariantId(id) => { - Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) - } + DefWithBodyId::VariantId(id) => Some(self.db.enum_variant_data(id).name.to_smol_str()), DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml index 4d4bac5fb9664..98961a18de257 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml @@ -17,6 +17,7 @@ cov-mark = "2.0.0-pre.1" itertools.workspace = true either.workspace = true smallvec.workspace = true +tracing.workspace = true # local deps stdx.workspace = true @@ -38,4 +39,4 @@ sourcegen.workspace = true in-rust-tree = [] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 410c623109ea0..c1b95bb1e253e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -105,7 +105,7 @@ fn add_missing_impl_members_inner( assist_id: &'static str, label: &'static str, ) -> Option<()> { - let _p = profile::span("add_missing_impl_members_inner"); + let _p = tracing::span!(tracing::Level::INFO, "add_missing_impl_members_inner"); let impl_def = ctx.find_node_at_offset::()?; let impl_ = ctx.sema.to_def(&impl_def)?; @@ -370,17 +370,17 @@ impl Foo for S { add_missing_impl_members, r#" pub trait Trait<'a, 'b, A, B, C> { - fn foo(&self, one: &'a A, anoter: &'b B) -> &'a C; + fn foo(&self, one: &'a A, another: &'b B) -> &'a C; } impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () {$0}"#, r#" pub trait Trait<'a, 'b, A, B, C> { - fn foo(&self, one: &'a A, anoter: &'b B) -> &'a C; + fn foo(&self, one: &'a A, another: &'b B) -> &'a C; } impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () { - fn foo(&self, one: &'x T, anoter: &'y V) -> &'x U { + fn foo(&self, one: &'x T, another: &'y V) -> &'x U { ${0:todo!()} } }"#, @@ -393,7 +393,7 @@ impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () { add_missing_default_members, r#" pub trait Trait<'a, 'b, A, B, C: Default> { - fn foo(&self, _one: &'a A, _anoter: &'b B) -> (C, &'a i32) { + fn foo(&self, _one: &'a A, _another: &'b B) -> (C, &'a i32) { let value: &'a i32 = &0; (C::default(), value) } @@ -402,14 +402,14 @@ pub trait Trait<'a, 'b, A, B, C: Default> { impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () {$0}"#, r#" pub trait Trait<'a, 'b, A, B, C: Default> { - fn foo(&self, _one: &'a A, _anoter: &'b B) -> (C, &'a i32) { + fn foo(&self, _one: &'a A, _another: &'b B) -> (C, &'a i32) { let value: &'a i32 = &0; (C::default(), value) } } impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () { - $0fn foo(&self, _one: &'x T, _anoter: &'y V) -> (U, &'x i32) { + $0fn foo(&self, _one: &'x T, _another: &'y V) -> (U, &'x i32) { let value: &'x i32 = &0; (::default(), value) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 2374da9a343f4..5ef374506ecc2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -188,7 +188,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) build_pat( ctx.db(), module, - variant.clone(), + variant, ctx.config.prefer_no_std, ctx.config.prefer_prelude, ) @@ -312,7 +312,7 @@ fn cursor_at_trivial_match_arm_list( match_arm_list: &MatchArmList, ) -> Option<()> { // match x { $0 } - if match_arm_list.arms().next() == None { + if match_arm_list.arms().next().is_none() { cov_mark::hit!(add_missing_match_arms_empty_body); return Some(()); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index 88fd0b1b7339b..363aa142b25bd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -85,9 +85,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti if let Some(let_stmt) = ctx.find_node_at_offset::() { if let_stmt.colon_token().is_none() { - if let_stmt.pat().is_none() { - return None; - } + let_stmt.pat()?; acc.add( AssistId("add_type_ascription", AssistKind::RefactorRewrite), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index a64591c9ca090..62696d1a9a808 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -49,6 +49,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; // - `item`: Don't merge imports at all, creating one import per item. // - `preserve`: Do not change the granularity of any imports. For auto-import this has the same // effect as `item`. +// - `one`: Merge all imports into a single use statement as long as they have the same visibility +// and attributes. // // In `VS Code` the configuration for this is `rust-analyzer.imports.granularity.group`. // @@ -196,7 +198,7 @@ pub(super) fn find_importable_node( { ImportAssets::for_method_call(&method_under_caret, &ctx.sema) .zip(Some(method_under_caret.syntax().clone().into())) - } else if let Some(_) = ctx.find_node_at_offset_with_descend::() { + } else if ctx.find_node_at_offset_with_descend::().is_some() { None } else if let Some(pat) = ctx .find_node_at_offset_with_descend::() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index dc1952c3ff3ce..fd3a0506ab677 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -422,9 +422,7 @@ fn find_record_pat_field_usage(name: &ast::NameLike) -> Option { fn find_assoc_const_usage(name: &ast::NameLike) -> Option<(ast::Type, ast::Expr)> { let const_ = name.syntax().parent().and_then(ast::Const::cast)?; - if const_.syntax().parent().and_then(ast::AssocItemList::cast).is_none() { - return None; - } + const_.syntax().parent().and_then(ast::AssocItemList::cast)?; Some((const_.ty()?, const_.body()?)) } @@ -986,7 +984,7 @@ fn foo() { } //- /main.rs -use foo::{Foo, Bool}; +use foo::{Bool, Foo}; mod foo; @@ -1662,7 +1660,7 @@ impl Foo { } //- /foo.rs -use crate::{Foo, Bool}; +use crate::{Bool, Foo}; fn foo() -> bool { Foo::BOOL == Bool::True diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs index e6179ab8b1bac..07fd5e34181ef 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs @@ -96,7 +96,7 @@ fn can_add(node: &SyntaxNode) -> bool { if p.kind() == ASSOC_ITEM_LIST { p.parent() - .and_then(|it| ast::Impl::cast(it)) + .and_then(ast::Impl::cast) // inherent impls i.e 'non-trait impls' have a non-local // effect, thus can have visibility even when nested. // so filter them out diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs index ff2195f7e6c4a..fd3378e8c2636 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs @@ -20,7 +20,7 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_> _ => return None, }; let radix = literal.radix(); - let value = literal.value()?; + let value = literal.value().ok()?; let suffix = literal.suffix(); let range = literal.syntax().text_range(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs index fc6236a17558c..c7f41ffce046e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs @@ -38,7 +38,7 @@ pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<' let Some(ast::Expr::MatchExpr(initializer)) = let_stmt.initializer() else { return None }; let initializer_expr = initializer.expr()?; - let Some((extracting_arm, diverging_arm)) = find_arms(ctx, &initializer) else { return None }; + let (extracting_arm, diverging_arm) = find_arms(ctx, &initializer)?; if extracting_arm.guard().is_some() { cov_mark::hit!(extracting_arm_has_guard); return None; @@ -113,7 +113,7 @@ fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Opti } _ => { cov_mark::hit!(extracting_arm_is_not_an_identity_expr); - return None; + None } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index 73ba3f5c4cdc8..6f30ffa622dc5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -8,7 +8,7 @@ use syntax::{ make, }, ted, AstNode, - SyntaxKind::{FN, LOOP_EXPR, WHILE_EXPR, WHITESPACE}, + SyntaxKind::{FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE}, T, }; @@ -82,14 +82,12 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<' let parent_container = parent_block.syntax().parent()?; let early_expression: ast::Expr = match parent_container.kind() { - WHILE_EXPR | LOOP_EXPR => make::expr_continue(None), + WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None), FN => make::expr_return(None), _ => return None, }; - if then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{']).is_none() { - return None; - } + then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?; then_block.syntax().last_child_or_token().filter(|t| t.kind() == T!['}'])?; @@ -426,6 +424,32 @@ fn main() { ); } + #[test] + fn convert_let_inside_for() { + check_assist( + convert_to_guarded_return, + r#" +fn main() { + for n in ns { + if$0 let Some(n) = n { + foo(n); + bar(); + } + } +} +"#, + r#" +fn main() { + for n in ns { + let Some(n) = n else { continue }; + foo(n); + bar(); + } +} +"#, + ); + } + #[test] fn convert_arbitrary_if_let_patterns() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 65b497e83aa2a..06f7b6cc5a082 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -84,8 +84,8 @@ fn destructure_tuple_edit_impl( data: &TupleData, in_sub_pattern: bool, ) { - let assignment_edit = edit_tuple_assignment(ctx, edit, &data, in_sub_pattern); - let current_file_usages_edit = edit_tuple_usages(&data, edit, ctx, in_sub_pattern); + let assignment_edit = edit_tuple_assignment(ctx, edit, data, in_sub_pattern); + let current_file_usages_edit = edit_tuple_usages(data, edit, ctx, in_sub_pattern); assignment_edit.apply(); if let Some(usages_edit) = current_file_usages_edit { @@ -258,7 +258,7 @@ fn edit_tuple_usage( Some(index) => Some(edit_tuple_field_usage(ctx, builder, data, index)), None if in_sub_pattern => { cov_mark::hit!(destructure_tuple_call_with_subpattern); - return None; + None } None => Some(EditTupleUsage::NoIndex(usage.range)), } @@ -375,7 +375,7 @@ impl RefData { expr = make::expr_paren(expr); } - return expr; + expr } } fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> (ast::Expr, RefData) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index 4b9fedc7e8557..30c3983dc411e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -668,7 +668,7 @@ fn check_intersection_and_push( // check for intersection between all current members // and combine all such ranges into one. let s: SmallVec<[_; 2]> = import_paths_to_be_removed - .into_iter() + .iter_mut() .positions(|it| it.intersect(import_path).is_some()) .collect(); for pos in s.into_iter().rev() { @@ -689,27 +689,22 @@ fn does_source_exists_outside_sel_in_same_mod( match def { Definition::Module(x) => { let source = x.definition_source(ctx.db()); - let have_same_parent; - if let Some(ast_module) = &curr_parent_module { + let have_same_parent = if let Some(ast_module) = &curr_parent_module { if let Some(hir_module) = x.parent(ctx.db()) { - have_same_parent = - compare_hir_and_ast_module(ast_module, hir_module, ctx).is_some(); + compare_hir_and_ast_module(ast_module, hir_module, ctx).is_some() } else { let source_file_id = source.file_id.original_file(ctx.db()); - have_same_parent = source_file_id == curr_file_id; + source_file_id == curr_file_id } } else { let source_file_id = source.file_id.original_file(ctx.db()); - have_same_parent = source_file_id == curr_file_id; - } + source_file_id == curr_file_id + }; if have_same_parent { - match source.value { - ModuleSource::Module(module_) => { - source_exists_outside_sel_in_same_mod = - !selection_range.contains_range(module_.syntax().text_range()); - } - _ => {} + if let ModuleSource::Module(module_) = source.value { + source_exists_outside_sel_in_same_mod = + !selection_range.contains_range(module_.syntax().text_range()); } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 65e2a01847799..81a639e0b9f3d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -412,6 +412,13 @@ fn reference_to_node( ) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> { let segment = reference.name.as_name_ref()?.syntax().parent().and_then(ast::PathSegment::cast)?; + + // filter out the reference in marco + let segment_range = segment.syntax().text_range(); + if segment_range != reference.range { + return None; + } + let parent = segment.parent_path().syntax().parent()?; let expr_or_pat = match_ast! { match parent { @@ -432,6 +439,45 @@ mod tests { use super::*; + #[test] + fn test_with_marco() { + check_assist( + extract_struct_from_enum_variant, + r#" +macro_rules! foo { + ($x:expr) => { + $x + }; +} + +enum TheEnum { + TheVariant$0 { the_field: u8 }, +} + +fn main() { + foo![TheEnum::TheVariant { the_field: 42 }]; +} +"#, + r#" +macro_rules! foo { + ($x:expr) => { + $x + }; +} + +struct TheVariant{ the_field: u8 } + +enum TheEnum { + TheVariant(TheVariant), +} + +fn main() { + foo![TheEnum::TheVariant { the_field: 42 }]; +} +"#, + ); + } + #[test] fn issue_16197() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index b6e7d6209c9cd..3612eda7847a2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -185,7 +185,7 @@ fn collect_used_generics<'gp>( ast::GenericParam::TypeParam(_) => 1, }); - Some(generics).filter(|it| it.len() > 0) + Some(generics).filter(|it| !it.is_empty()) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 0b3bd0bed6edb..22d16cf6b36e4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -115,7 +115,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let trailing_ws = if prev_ws.is_some_and(|it| it.text().starts_with('\n')) { format!("\n{indent_to}") } else { - format!(" ") + " ".to_string() }; ted::insert_all_raw( @@ -163,7 +163,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op block } else { // `expr_replace` is a descendant of `to_wrap`, so both steps need to be - // handled seperately, otherwise we wrap the wrong expression + // handled separately, otherwise we wrap the wrong expression let to_wrap = edit.make_mut(to_wrap); // Replace the target expr first so that we don't need to find where diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs index e3ae4970b6a7a..430cd5b080bd5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs @@ -23,9 +23,7 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let plus = ctx.find_token_syntax_at_offset(T![+])?; // Make sure we're in a `TypeBoundList` - if ast::TypeBoundList::cast(plus.parent()?).is_none() { - return None; - } + ast::TypeBoundList::cast(plus.parent()?)?; let (before, after) = ( non_trivia_sibling(plus.clone().into(), Direction::Prev)?, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs index 8b8c6ceee99e2..4d8116a7156cb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs @@ -107,10 +107,10 @@ fn get_text_for_generate_constant( type_name: String, ) -> Option { let constant_token = not_exist_name_ref.pop()?; - let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " }; + let vis = if not_exist_name_ref.is_empty() && !outer_exists { "" } else { "\npub " }; let mut text = format!("{vis}const {constant_token}: {type_name} = $0;"); while let Some(name_ref) = not_exist_name_ref.pop() { - let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " }; + let vis = if not_exist_name_ref.is_empty() && !outer_exists { "" } else { "\npub " }; text = text.replace('\n', "\n "); text = format!("{vis}mod {name_ref} {{{text}\n}}"); } @@ -136,8 +136,7 @@ fn target_data_for_generate_constant( let siblings_has_newline = l_curly_token .siblings_with_tokens(Direction::Next) - .find(|it| it.kind() == SyntaxKind::WHITESPACE && it.to_string().contains('\n')) - .is_some(); + .any(|it| it.kind() == SyntaxKind::WHITESPACE && it.to_string().contains('\n')); let post_string = if siblings_has_newline { format!("{indent}") } else { format!("\n{indent}") }; Some((offset, indent + 1, Some(file_id), post_string)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs index 7e4f140a28faa..dc27af5cbed20 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs @@ -418,7 +418,7 @@ where } #[test] - fn new_function_with_generics_and_wheres() { + fn new_function_with_generics_and_where() { check_assist( generate_default_from_new, r#" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 1f5c24f8ea446..d59bd71d312d8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -134,7 +134,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' // compute the `body` let arg_list = method_source .param_list() - .map(|list| convert_param_list_to_arg_list(list)) + .map(convert_param_list_to_arg_list) .unwrap_or_else(|| make::arg_list([])); let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 339c3ac71ecd9..898bd01291a25 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -88,11 +88,11 @@ pub(crate) fn generate_delegate_trait(acc: &mut Assists, ctx: &AssistContext<'_> let strukt = Struct::new(ctx.find_node_at_offset::()?)?; let field: Field = match ctx.find_node_at_offset::() { - Some(field) => Field::new(&ctx, Either::Left(field))?, + Some(field) => Field::new(ctx, Either::Left(field))?, None => { let field = ctx.find_node_at_offset::()?; let field_list = ctx.find_node_at_offset::()?; - Field::new(&ctx, either::Right((field, field_list)))? + Field::new(ctx, either::Right((field, field_list)))? } }; @@ -236,7 +236,7 @@ fn generate_impl( ctx: &AssistContext<'_>, strukt: &Struct, field_ty: &ast::Type, - field_name: &String, + field_name: &str, delegee: &Delegee, ) -> Option { let delegate: ast::Impl; @@ -270,25 +270,22 @@ fn generate_impl( make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); - match bound_def.assoc_item_list() { - Some(ai) => { - ai.assoc_items() - .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) - .for_each(|item| { - let assoc = - process_assoc_item(item, qualified_path_type.clone(), &field_name); - if let Some(assoc) = assoc { - delegate_assoc_items.add_item(assoc); - } - }); - } - None => {} + if let Some(ai) = bound_def.assoc_item_list() { + ai.assoc_items() + .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) + .for_each(|item| { + let assoc = + process_assoc_item(item, qualified_path_type.clone(), field_name); + if let Some(assoc) = assoc { + delegate_assoc_items.add_item(assoc); + } + }); }; let target_scope = ctx.sema.scope(strukt.strukt.syntax())?; let source_scope = ctx.sema.scope(bound_def.syntax())?; let transform = PathTransform::generic_transformation(&target_scope, &source_scope); - transform.apply(&delegate.syntax()); + transform.apply(delegate.syntax()); } Delegee::Impls(trait_, old_impl) => { let old_impl = ctx.sema.source(old_impl.to_owned())?.value; @@ -298,7 +295,7 @@ fn generate_impl( // those in strukt. // // These generics parameters will also be used in `field_ty` and - // `where_clauses`, so we should substitude arguments in them as well. + // `where_clauses`, so we should substitute arguments in them as well. let strukt_params = resolve_name_conflicts(strukt_params, &old_impl_params); let (field_ty, ty_where_clause) = match &strukt_params { Some(strukt_params) => { @@ -306,7 +303,7 @@ fn generate_impl( let field_ty = rename_strukt_args(ctx, ast_strukt, field_ty, &args)?; let where_clause = ast_strukt .where_clause() - .and_then(|wc| Some(rename_strukt_args(ctx, ast_strukt, &wc, &args)?)); + .and_then(|wc| rename_strukt_args(ctx, ast_strukt, &wc, &args)); (field_ty, where_clause) } None => (field_ty.clone_for_update(), None), @@ -323,7 +320,7 @@ fn generate_impl( .trait_()? .generic_arg_list() .map(|l| l.generic_args().map(|arg| arg.to_string())) - .map_or_else(|| FxHashSet::default(), |it| it.collect()); + .map_or_else(FxHashSet::default, |it| it.collect()); let trait_gen_params = remove_instantiated_params( &old_impl.self_ty()?, @@ -345,13 +342,13 @@ fn generate_impl( let mut trait_gen_args = old_impl.trait_()?.generic_arg_list(); if let Some(trait_args) = &mut trait_gen_args { *trait_args = trait_args.clone_for_update(); - transform_impl(ctx, ast_strukt, &old_impl, &transform_args, &trait_args.syntax())?; + transform_impl(ctx, ast_strukt, &old_impl, &transform_args, trait_args.syntax())?; } let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args()); let path_type = make::ty(&trait_.name(db).to_smol_str()).clone_for_update(); - transform_impl(ctx, ast_strukt, &old_impl, &transform_args, &path_type.syntax())?; + transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?; // 3) Generate delegate trait impl delegate = make::impl_trait( @@ -383,7 +380,7 @@ fn generate_impl( let item = item.clone_for_update(); transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item.syntax())?; - let assoc = process_assoc_item(item, qualified_path_type.clone(), &field_name)?; + let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?; delegate_assoc_items.add_item(assoc); } @@ -404,8 +401,8 @@ fn transform_impl( args: &Option, syntax: &syntax::SyntaxNode, ) -> Option<()> { - let source_scope = ctx.sema.scope(&old_impl.self_ty()?.syntax())?; - let target_scope = ctx.sema.scope(&strukt.syntax())?; + let source_scope = ctx.sema.scope(old_impl.self_ty()?.syntax())?; + let target_scope = ctx.sema.scope(strukt.syntax())?; let hir_old_impl = ctx.sema.to_impl_def(old_impl)?; let transform = args.as_ref().map_or_else( @@ -420,7 +417,7 @@ fn transform_impl( }, ); - transform.apply(&syntax); + transform.apply(syntax); Some(()) } @@ -481,7 +478,7 @@ fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: a .skip(1) .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE) }) - .for_each(|ws| ted::remove(ws)); + .for_each(ted::remove); ted::insert( ted::Position::after(wc.syntax()), @@ -494,7 +491,7 @@ fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: a // Generate generic args that should be apply to current impl. // -// For exmaple, say we have implementation `impl Trait for B`, +// For example, say we have implementation `impl Trait for B`, // and `b: B` in struct `S`. Then the `A` should be instantiated to `T`. // While the last two generic args `B` and `C` doesn't change, it remains // ``. So we apply `` as generic arguments to impl. @@ -512,17 +509,14 @@ fn generate_args_for_impl( // form the substitution list let mut arg_substs = FxHashMap::default(); - match field_ty { - field_ty @ ast::Type::PathType(_) => { - let field_args = field_ty.generic_arg_list().map(|gal| gal.generic_args()); - let self_ty_args = self_ty.generic_arg_list().map(|gal| gal.generic_args()); - if let (Some(field_args), Some(self_ty_args)) = (field_args, self_ty_args) { - self_ty_args.zip(field_args).for_each(|(self_ty_arg, field_arg)| { - arg_substs.entry(self_ty_arg.to_string()).or_insert(field_arg); - }) - } + if let field_ty @ ast::Type::PathType(_) = field_ty { + let field_args = field_ty.generic_arg_list().map(|gal| gal.generic_args()); + let self_ty_args = self_ty.generic_arg_list().map(|gal| gal.generic_args()); + if let (Some(field_args), Some(self_ty_args)) = (field_args, self_ty_args) { + self_ty_args.zip(field_args).for_each(|(self_ty_arg, field_arg)| { + arg_substs.entry(self_ty_arg.to_string()).or_insert(field_arg); + }) } - _ => {} } let args = old_impl_args @@ -539,7 +533,7 @@ fn generate_args_for_impl( ) }) .collect_vec(); - args.is_empty().not().then(|| make::generic_arg_list(args.into_iter())) + args.is_empty().not().then(|| make::generic_arg_list(args)) } fn rename_strukt_args( @@ -558,7 +552,7 @@ where let scope = ctx.sema.scope(item.syntax())?; let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone()); - transform.apply(&item.syntax()); + transform.apply(item.syntax()); Some(item) } @@ -643,7 +637,7 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); // We want rhs of the const assignment to be a qualified path - // The general case for const assigment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`) + // The general case for const assignment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`) // The qualified will have the following generic syntax : // >::ConstName; // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it. @@ -785,7 +779,7 @@ impl Trait for Base {} #[test] fn test_self_ty() { - // trait whith `Self` type cannot be delegated + // trait with `Self` type cannot be delegated // // See the function `fn f() -> Self`. // It should be `fn f() -> Base` in `Base`, and `fn f() -> S` in `S` diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs index e87132218ea90..f298ce8916dbe 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -148,7 +148,7 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option bool { matches!(self, Self::Complete) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs index 2aaf9d0679d34..681f8c1fcf522 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -124,7 +124,9 @@ fn add_variant_to_accumulator( builder.edit_file(file_id); let node = builder.make_mut(enum_node); let variant = make_variant(ctx, name_ref, parent); - node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); + if let Some(it) = node.variant_list() { + it.add_variant(variant.clone_for_update()) + } }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index 742f1f78c2ec9..6091f06b96699 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -90,7 +90,7 @@ fn existing_from_impl( let enum_type = enum_.ty(sema.db); - let wrapped_type = variant.fields(sema.db).get(0)?.ty(sema.db); + let wrapped_type = variant.fields(sema.db).first()?.ty(sema.db); if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) { Some(()) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 9c9478b040d1f..79307fcec5afc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -42,7 +42,7 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt let (strukt, info_of_record_fields, mut fn_names) = extract_and_parse(ctx, AssistType::Set)?; // No record fields to do work on :( - if info_of_record_fields.len() == 0 { + if info_of_record_fields.is_empty() { return None; } @@ -163,7 +163,7 @@ pub(crate) fn generate_getter_impl( let (strukt, info_of_record_fields, fn_names) = extract_and_parse(ctx, if mutable { AssistType::MutGet } else { AssistType::Get })?; // No record fields to do work on :( - if info_of_record_fields.len() == 0 { + if info_of_record_fields.is_empty() { return None; } @@ -318,15 +318,13 @@ fn extract_and_parse_record_fields( }) .collect::>(); - if info_of_record_fields_in_selection.len() == 0 { + if info_of_record_fields_in_selection.is_empty() { return None; } Some((info_of_record_fields_in_selection, field_names)) } - ast::FieldList::TupleFieldList(_) => { - return None; - } + ast::FieldList::TupleFieldList(_) => None, } } @@ -379,10 +377,8 @@ fn build_source_change( }; // Insert `$0` only for last getter we generate - if i == record_fields_count - 1 { - if ctx.config.snippet_cap.is_some() { - getter_buf = getter_buf.replacen("fn ", "fn $0", 1); - } + if i == record_fields_count - 1 && ctx.config.snippet_cap.is_some() { + getter_buf = getter_buf.replacen("fn ", "fn $0", 1); } // For first element we do not merge with '\n', as @@ -409,7 +405,7 @@ fn build_source_change( // getter and end of impl ( i.e. `}` ) with an // extra line for no reason if i < record_fields_count - 1 { - buf = buf + "\n"; + buf += "\n"; } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index 9ad14a819d97b..d52d778d344a3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -29,7 +29,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio let name = nominal.name()?; let target = nominal.syntax().text_range(); - if let Some(_) = ctx.find_node_at_offset::() { + if ctx.find_node_at_offset::().is_some() { return None; } @@ -77,7 +77,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> let name = nominal.name()?; let target = nominal.syntax().text_range(); - if let Some(_) = ctx.find_node_at_offset::() { + if ctx.find_node_at_offset::().is_some() { return None; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs index 4429186196044..6bfc69b0ada65 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs @@ -95,7 +95,7 @@ fn get_impl_method( let scope = ctx.sema.scope(impl_.syntax())?; let ty = impl_def.self_ty(db); - ty.iterate_method_candidates(db, &scope, None, Some(fn_name), |func| Some(func)) + ty.iterate_method_candidates(db, &scope, None, Some(fn_name), Some) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs index d90d366ffe4c4..91eaa96b6cb0d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -6,7 +6,7 @@ use syntax::{ use crate::{AssistContext, AssistId, AssistKind, Assists}; -// FIXME: Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredicable case [#15581]. +// FIXME: Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredictable case [#15581]. // Here just leave the `index_mut` method body be same as `index` method body, user can modify it manually to meet their need. // Assist: generate_mut_trait_impl diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index 315b6487b5140..8881aa69f29d3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -85,10 +85,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ let assoc_items = impl_ast.assoc_item_list()?; let first_element = assoc_items.assoc_items().next(); - if first_element.is_none() { - // No reason for an assist. - return None; - } + first_element.as_ref()?; let impl_name = impl_ast.self_ty()?; @@ -184,21 +181,18 @@ fn remove_items_visibility(item: &ast::AssocItem) { } fn strip_body(item: &ast::AssocItem) { - match item { - ast::AssocItem::Fn(f) => { - if let Some(body) = f.body() { - // In constrast to function bodies, we want to see no ws before a semicolon. - // So let's remove them if we see any. - if let Some(prev) = body.syntax().prev_sibling_or_token() { - if prev.kind() == SyntaxKind::WHITESPACE { - ted::remove(prev); - } + if let ast::AssocItem::Fn(f) = item { + if let Some(body) = f.body() { + // In contrast to function bodies, we want to see no ws before a semicolon. + // So let's remove them if we see any. + if let Some(prev) = body.syntax().prev_sibling_or_token() { + if prev.kind() == SyntaxKind::WHITESPACE { + ted::remove(prev); } - - ted::replace(body.syntax(), make::tokens::semicolon()); } + + ted::replace(body.syntax(), make::tokens::semicolon()); } - _ => (), }; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 2eb7089b7c38e..4ba33ada48c75 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -15,7 +15,7 @@ use ide_db::{ }; use itertools::{izip, Itertools}; use syntax::{ - ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, PathExpr}, + ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, Pat, PathExpr}, ted, AstNode, NodeOrToken, SyntaxKind, }; @@ -278,7 +278,7 @@ fn get_fn_params( let mut params = Vec::new(); if let Some(self_param) = param_list.self_param() { - // FIXME this should depend on the receiver as well as the self_param + // Keep `ref` and `mut` and transform them into `&` and `mut` later params.push(( make::ident_pat( self_param.amp_token().is_some(), @@ -409,16 +409,55 @@ fn inline( let mut let_stmts = Vec::new(); // Inline parameter expressions or generate `let` statements depending on whether inlining works or not. - for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments) { + for ((pat, param_ty, param), usages, expr) in izip!(params, param_use_nodes, arguments) { // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors let usages: &[ast::PathExpr] = &usages; let expr: &ast::Expr = expr; let mut insert_let_stmt = || { let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone()); - let_stmts.push( - make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(), - ); + + let is_self = param + .name(sema.db) + .and_then(|name| name.as_text()) + .is_some_and(|name| name == "self"); + + if is_self { + let mut this_pat = make::ident_pat(false, false, make::name("this")); + let mut expr = expr.clone(); + if let Pat::IdentPat(pat) = pat { + match (pat.ref_token(), pat.mut_token()) { + // self => let this = obj + (None, None) => {} + // mut self => let mut this = obj + (None, Some(_)) => { + this_pat = make::ident_pat(false, true, make::name("this")); + } + // &self => let this = &obj + (Some(_), None) => { + expr = make::expr_ref(expr, false); + } + // let foo = &mut X; &mut self => let this = &mut obj + // let mut foo = X; &mut self => let this = &mut *obj (reborrow) + (Some(_), Some(_)) => { + let should_reborrow = sema + .type_of_expr(&expr) + .map(|ty| ty.original.is_mutable_reference()); + expr = if let Some(true) = should_reborrow { + make::expr_reborrow(expr) + } else { + make::expr_ref(expr, true) + }; + } + } + }; + let_stmts + .push(make::let_stmt(this_pat.into(), ty, Some(expr)).clone_for_update().into()) + } else { + let_stmts.push( + make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(), + ); + } }; // check if there is a local var in the function that conflicts with parameter @@ -484,12 +523,10 @@ fn inline( body = make::block_expr(let_stmts, Some(body.into())).clone_for_update(); } } else if let Some(stmt_list) = body.stmt_list() { - ted::insert_all( - ted::Position::after( - stmt_list.l_curly_token().expect("L_CURLY for StatementList is missing."), - ), - let_stmts.into_iter().map(|stmt| stmt.syntax().clone().into()).collect(), - ); + let position = stmt_list.l_curly_token().expect("L_CURLY for StatementList is missing."); + let_stmts.into_iter().rev().for_each(|let_stmt| { + ted::insert(ted::Position::after(position.clone()), let_stmt.syntax().clone()); + }); } let original_indentation = match node { @@ -721,7 +758,7 @@ impl Foo { fn main() { let x = { - let ref this = Foo(3); + let this = &Foo(3); Foo(this.0 + 2) }; } @@ -757,7 +794,7 @@ impl Foo { fn main() { let x = { - let ref this = Foo(3); + let this = &Foo(3); Foo(this.0 + 2) }; } @@ -795,7 +832,7 @@ impl Foo { fn main() { let mut foo = Foo(3); { - let ref mut this = foo; + let this = &mut foo; this.0 = 0; }; } @@ -882,7 +919,7 @@ impl Foo { } fn bar(&self) { { - let ref this = self; + let this = &self; this; this; }; @@ -1557,7 +1594,7 @@ impl Enum { fn a() -> bool { { - let ref this = Enum::A; + let this = &Enum::A; this == &Enum::A || this == &Enum::B } } @@ -1619,6 +1656,82 @@ fn main() { a as A }; } +"#, + ) + } + + #[test] + fn method_by_reborrow() { + check_assist( + inline_call, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(&mut self) { + self.0 += 1; + } +} + +pub fn main() { + let f = &mut Foo(0); + f.add1$0(); +} +"#, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(&mut self) { + self.0 += 1; + } +} + +pub fn main() { + let f = &mut Foo(0); + { + let this = &mut *f; + this.0 += 1; + }; +} +"#, + ) + } + + #[test] + fn method_by_mut() { + check_assist( + inline_call, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(mut self) { + self.0 += 1; + } +} + +pub fn main() { + let mut f = Foo(0); + f.add1$0(); +} +"#, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(mut self) { + self.0 += 1; + } +} + +pub fn main() { + let mut f = Foo(0); + { + let mut this = f; + this.0 += 1; + }; +} "#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs index 5b1540b50ca4a..18437453761c2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -60,7 +60,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_> let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline); - let label = format!("Inline const as literal"); + let label = "Inline const as literal".to_string(); let target = variable.syntax().text_range(); return acc.add(id, label, target, |edit| { @@ -100,7 +100,7 @@ fn validate_type_recursively( } (_, Some(ty)) => match ty.as_builtin() { // `const A: str` is not correct, but `const A: &builtin` is. - Some(builtin) if refed || (!refed && !builtin.is_str()) => Some(()), + Some(builtin) if refed || !builtin.is_str() => Some(()), _ => None, }, _ => None, @@ -138,7 +138,7 @@ mod tests { // -----------Not supported----------- #[test] fn inline_const_as_literal_const_fn_call_slice() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist_not_applicable( inline_const_as_literal, &format!( @@ -240,7 +240,7 @@ mod tests { #[test] fn inline_const_as_literal_const_expr() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( @@ -261,7 +261,7 @@ mod tests { #[test] fn inline_const_as_literal_const_block_expr() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( @@ -282,7 +282,7 @@ mod tests { #[test] fn inline_const_as_literal_const_block_eval_expr() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( @@ -303,7 +303,7 @@ mod tests { #[test] fn inline_const_as_literal_const_block_eval_block_expr() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( @@ -324,7 +324,7 @@ mod tests { #[test] fn inline_const_as_literal_const_fn_call_block_nested_builtin() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( @@ -347,7 +347,7 @@ mod tests { #[test] fn inline_const_as_literal_const_fn_call_tuple() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( @@ -370,7 +370,7 @@ mod tests { #[test] fn inline_const_as_literal_const_fn_call_builtin() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + TEST_PAIRS.iter().for_each(|(ty, val, _)| { check_assist( inline_const_as_literal, &format!( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index 5d956b1a5e870..c1beb46c8096c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -41,7 +41,7 @@ pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option acc.add( AssistId("inline_macro", AssistKind::RefactorInline), - format!("Inline macro"), + "Inline macro".to_string(), text_range, |builder| builder.replace(text_range, expanded.to_string()), ) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs index 965e4aa786e7a..f7da88b2c1838 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs @@ -120,7 +120,7 @@ fn main() -> () { } #[test] - fn fromed_in_child_mod_imported() { + fn from_in_child_mod_imported() { check_assist( into_to_qualified_from, r#" @@ -168,7 +168,7 @@ fn main() -> () { } #[test] - fn fromed_in_child_mod_not_imported() { + fn from_in_child_mod_not_imported() { check_assist( into_to_qualified_from, r#" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index b1daa7802ed89..543b7f7ab6329 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -18,7 +18,7 @@ use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let impl_trait_type = ctx.find_node_at_offset::()?; - let param = impl_trait_type.syntax().ancestors().find_map(|node| ast::Param::cast(node))?; + let param = impl_trait_type.syntax().ancestors().find_map(ast::Param::cast)?; let fn_ = param.syntax().ancestors().find_map(ast::Fn::cast)?; let type_bound_list = impl_trait_type.type_bound_list()?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index d7ddc5f23f5dc..797c5c0653321 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,5 +1,9 @@ use either::Either; -use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior}; +use ide_db::imports::{ + insert_use::{ImportGranularity, InsertUseConfig}, + merge_imports::{try_merge_imports, try_merge_trees, try_normalize_use_tree, MergeBehavior}, +}; +use itertools::Itertools; use syntax::{ algo::neighbor, ast::{self, edit_in_place::Removable}, @@ -16,7 +20,7 @@ use Edit::*; // Assist: merge_imports // -// Merges two imports with a common prefix. +// Merges neighbor imports with a common prefix. // // ``` // use std::$0fmt::Formatter; @@ -29,16 +33,13 @@ use Edit::*; pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (target, edits) = if ctx.has_empty_selection() { // Merge a neighbor - let tree: ast::UseTree = ctx.find_node_at_offset()?; + cov_mark::hit!(merge_with_use_item_neighbors); + let tree = ctx.find_node_at_offset::()?.top_use_tree(); let target = tree.syntax().text_range(); - let edits = if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { - let mut neighbor = next_prev().find_map(|dir| neighbor(&use_item, dir)).into_iter(); - use_item.try_merge_from(&mut neighbor) - } else { - let mut neighbor = next_prev().find_map(|dir| neighbor(&tree, dir)).into_iter(); - tree.try_merge_from(&mut neighbor) - }; + let use_item = tree.syntax().parent().and_then(ast::Use::cast)?; + let mut neighbor = next_prev().find_map(|dir| neighbor(&use_item, dir)).into_iter(); + let edits = use_item.try_merge_from(&mut neighbor, &ctx.config.insert_use); (target, edits?) } else { // Merge selected @@ -54,10 +55,12 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio let edits = match_ast! { match first_selected { ast::Use(use_item) => { - use_item.try_merge_from(&mut selected_nodes.filter_map(ast::Use::cast)) + cov_mark::hit!(merge_with_selected_use_item_neighbors); + use_item.try_merge_from(&mut selected_nodes.filter_map(ast::Use::cast), &ctx.config.insert_use) }, ast::UseTree(use_tree) => { - use_tree.try_merge_from(&mut selected_nodes.filter_map(ast::UseTree::cast)) + cov_mark::hit!(merge_with_selected_use_tree_neighbors); + use_tree.try_merge_from(&mut selected_nodes.filter_map(ast::UseTree::cast), &ctx.config.insert_use) }, _ => return None, } @@ -81,7 +84,35 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio for edit in edits_mut { match edit { Remove(it) => it.as_ref().either(Removable::remove, Removable::remove), - Replace(old, new) => ted::replace(old, new), + Replace(old, new) => { + ted::replace(old, &new); + + // If there's a selection and we're replacing a use tree in a tree list, + // normalize the parent use tree if it only contains the merged subtree. + if !ctx.has_empty_selection() { + let normalized_use_tree = ast::UseTree::cast(new) + .as_ref() + .and_then(ast::UseTree::parent_use_tree_list) + .and_then(|use_tree_list| { + if use_tree_list.use_trees().collect_tuple::<(_,)>().is_some() { + Some(use_tree_list.parent_use_tree()) + } else { + None + } + }) + .and_then(|target_tree| { + try_normalize_use_tree( + &target_tree, + ctx.config.insert_use.granularity.into(), + ) + .map(|top_use_tree_flat| (target_tree, top_use_tree_flat)) + }); + if let Some((old_tree, new_tree)) = normalized_use_tree { + cov_mark::hit!(replace_parent_with_normalized_use_tree); + ted::replace(old_tree.syntax(), new_tree.syntax()); + } + } + } } } }, @@ -89,11 +120,15 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio } trait Merge: AstNode + Clone { - fn try_merge_from(self, items: &mut dyn Iterator) -> Option> { + fn try_merge_from( + self, + items: &mut dyn Iterator, + cfg: &InsertUseConfig, + ) -> Option> { let mut edits = Vec::new(); let mut merged = self.clone(); for item in items { - merged = merged.try_merge(&item)?; + merged = merged.try_merge(&item, cfg)?; edits.push(Edit::Remove(item.into_either())); } if !edits.is_empty() { @@ -103,13 +138,17 @@ trait Merge: AstNode + Clone { None } } - fn try_merge(&self, other: &Self) -> Option; + fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option; fn into_either(self) -> Either; } impl Merge for ast::Use { - fn try_merge(&self, other: &Self) -> Option { - try_merge_imports(self, other, MergeBehavior::Crate) + fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option { + let mb = match cfg.granularity { + ImportGranularity::One => MergeBehavior::One, + _ => MergeBehavior::Crate, + }; + try_merge_imports(self, other, mb) } fn into_either(self) -> Either { Either::Left(self) @@ -117,7 +156,7 @@ impl Merge for ast::Use { } impl Merge for ast::UseTree { - fn try_merge(&self, other: &Self) -> Option { + fn try_merge(&self, other: &Self, _: &InsertUseConfig) -> Option { try_merge_trees(self, other, MergeBehavior::Crate) } fn into_either(self) -> Either { @@ -138,12 +177,41 @@ impl Edit { #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; + use crate::tests::{ + check_assist, check_assist_import_one, check_assist_not_applicable, + check_assist_not_applicable_for_import_one, + }; use super::*; + macro_rules! check_assist_import_one_variations { + ($first: literal, $second: literal, $expected: literal) => { + check_assist_import_one( + merge_imports, + concat!(concat!("use ", $first, ";"), concat!("use ", $second, ";")), + $expected, + ); + check_assist_import_one( + merge_imports, + concat!(concat!("use {", $first, "};"), concat!("use ", $second, ";")), + $expected, + ); + check_assist_import_one( + merge_imports, + concat!(concat!("use ", $first, ";"), concat!("use {", $second, "};")), + $expected, + ); + check_assist_import_one( + merge_imports, + concat!(concat!("use {", $first, "};"), concat!("use {", $second, "};")), + $expected, + ); + }; + } + #[test] fn test_merge_equal() { + cov_mark::check!(merge_with_use_item_neighbors); check_assist( merge_imports, r" @@ -151,9 +219,18 @@ use std::fmt$0::{Display, Debug}; use std::fmt::{Display, Debug}; ", r" -use std::fmt::{Display, Debug}; +use std::fmt::{Debug, Display}; ", - ) + ); + + // The assist macro below calls `check_assist_import_one` 4 times with different input + // use item variations based on the first 2 input parameters. + cov_mark::check_count!(merge_with_use_item_neighbors, 4); + check_assist_import_one_variations!( + "std::fmt$0::{Display, Debug}", + "std::fmt::{Display, Debug}", + "use {std::fmt::{Debug, Display}};" + ); } #[test] @@ -167,7 +244,12 @@ use std::fmt::Display; r" use std::fmt::{Debug, Display}; ", - ) + ); + check_assist_import_one_variations!( + "std::fmt$0::Debug", + "std::fmt::Display", + "use {std::fmt::{Debug, Display}};" + ); } #[test] @@ -179,13 +261,18 @@ use std::fmt::Debug; use std::fmt$0::Display; ", r" -use std::fmt::{Display, Debug}; +use std::fmt::{Debug, Display}; ", ); + check_assist_import_one_variations!( + "std::fmt::Debug", + "std::fmt$0::Display", + "use {std::fmt::{Debug, Display}};" + ); } #[test] - fn merge_self1() { + fn merge_self() { check_assist( merge_imports, r" @@ -196,18 +283,19 @@ use std::fmt::Display; use std::fmt::{self, Display}; ", ); + check_assist_import_one_variations!( + "std::fmt$0", + "std::fmt::Display", + "use {std::fmt::{self, Display}};" + ); } #[test] - fn merge_self2() { - check_assist( + fn not_applicable_to_single_import() { + check_assist_not_applicable(merge_imports, "use std::{fmt, $0fmt::Display};"); + check_assist_not_applicable_for_import_one( merge_imports, - r" -use std::{fmt, $0fmt::Display}; -", - r" -use std::{fmt::{Display, self}}; -", + "use {std::{fmt, $0fmt::Display}};", ); } @@ -302,10 +390,11 @@ pub(in this::path) use std::fmt::{Debug, Display}; check_assist( merge_imports, r" -use std::{fmt$0::Debug, fmt::Display}; +use std::{fmt$0::Debug, fmt::Error}; +use std::{fmt::Write, fmt::Display}; ", r" -use std::{fmt::{Debug, Display}}; +use std::fmt::{Debug, Display, Error, Write}; ", ); } @@ -315,10 +404,11 @@ use std::{fmt::{Debug, Display}}; check_assist( merge_imports, r" -use std::{fmt::Debug, fmt$0::Display}; +use std::{fmt::Debug, fmt$0::Error}; +use std::{fmt::Write, fmt::Display}; ", r" -use std::{fmt::{Display, Debug}}; +use std::fmt::{Debug, Display, Error, Write}; ", ); } @@ -332,9 +422,14 @@ use std$0::{fmt::{Write, Display}}; use std::{fmt::{self, Debug}}; ", r" -use std::{fmt::{Write, Display, self, Debug}}; +use std::fmt::{self, Debug, Display, Write}; ", ); + check_assist_import_one_variations!( + "std$0::{fmt::{Write, Display}}", + "std::{fmt::{self, Debug}}", + "use {std::fmt::{self, Debug, Display, Write}};" + ); } #[test] @@ -346,21 +441,13 @@ use std$0::{fmt::{self, Debug}}; use std::{fmt::{Write, Display}}; ", r" -use std::{fmt::{self, Debug, Write, Display}}; +use std::fmt::{self, Debug, Display, Write}; ", ); - } - - #[test] - fn test_merge_self_with_nested_self_item() { - check_assist( - merge_imports, - r" -use std::{fmt$0::{self, Debug}, fmt::{Write, Display}}; -", - r" -use std::{fmt::{self, Debug, Write, Display}}; -", + check_assist_import_one_variations!( + "std$0::{fmt::{self, Debug}}", + "std::{fmt::{Write, Display}}", + "use {std::fmt::{self, Debug, Display, Write}};" ); } @@ -373,9 +460,14 @@ use foo::$0{bar::{self}}; use foo::{bar}; ", r" -use foo::{bar::{self}}; +use foo::bar; ", - ) + ); + check_assist_import_one_variations!( + "foo::$0{bar::{self}}", + "foo::{bar}", + "use {foo::bar};" + ); } #[test] @@ -387,9 +479,14 @@ use foo::$0{bar}; use foo::{bar::{self}}; ", r" -use foo::{bar::{self}}; +use foo::bar; ", - ) + ); + check_assist_import_one_variations!( + "foo::$0{bar}", + "foo::{bar::{self}}", + "use {foo::bar};" + ); } #[test] @@ -401,9 +498,14 @@ use std$0::{fmt::*}; use std::{fmt::{self, Display}}; ", r" -use std::{fmt::{*, self, Display}}; +use std::fmt::{self, Display, *}; ", - ) + ); + check_assist_import_one_variations!( + "std$0::{fmt::*}", + "std::{fmt::{self, Display}}", + "use {std::fmt::{self, Display, *}};" + ); } #[test] @@ -417,7 +519,12 @@ use std::str; r" use std::{cell::*, str}; ", - ) + ); + check_assist_import_one_variations!( + "std$0::cell::*", + "std::str", + "use {std::{cell::*, str}};" + ); } #[test] @@ -431,7 +538,12 @@ use std::str::*; r" use std::{cell::*, str::*}; ", - ) + ); + check_assist_import_one_variations!( + "std$0::cell::*", + "std::str::*", + "use {std::{cell::*, str::*}};" + ); } #[test] @@ -457,29 +569,27 @@ use foo::{bar, baz}; check_assist( merge_imports, r" -use { - foo$0::bar, - foo::baz, +use foo$0::{ + bar, baz, }; +use foo::qux; ", r" -use { - foo::{bar, baz}, +use foo::{ + bar, baz, qux, }; ", ); check_assist( merge_imports, r" -use { - foo::baz, - foo$0::bar, +use foo::{ + baz, bar, }; +use foo$0::qux; ", r" -use { - foo::{bar, baz}, -}; +use foo::{bar, baz, qux}; ", ); } @@ -496,7 +606,7 @@ use foo::$0{ ", r" use foo::{ - FooBar, bar::baz, + bar::baz, FooBar }; ", ) @@ -521,13 +631,19 @@ use foo::$0*; use foo::bar::Baz; ", r" -use foo::{*, bar::Baz}; +use foo::{bar::Baz, *}; ", ); + check_assist_import_one_variations!( + "foo::$0*", + "foo::bar::Baz", + "use {foo::{bar::Baz, *}};" + ); } #[test] fn merge_selection_uses() { + cov_mark::check!(merge_with_selected_use_item_neighbors); check_assist( merge_imports, r" @@ -539,7 +655,24 @@ $0use std::fmt::Result; ", r" use std::fmt::Error; -use std::fmt::{Display, Debug, Write}; +use std::fmt::{Debug, Display, Write}; +use std::fmt::Result; +", + ); + + cov_mark::check!(merge_with_selected_use_item_neighbors); + check_assist_import_one( + merge_imports, + r" +use std::fmt::Error; +$0use std::fmt::Display; +use std::fmt::Debug; +use std::fmt::Write; +$0use std::fmt::Result; +", + r" +use std::fmt::Error; +use {std::fmt::{Debug, Display, Write}}; use std::fmt::Result; ", ); @@ -547,6 +680,7 @@ use std::fmt::Result; #[test] fn merge_selection_use_trees() { + cov_mark::check!(merge_with_selected_use_tree_neighbors); check_assist( merge_imports, r" @@ -560,15 +694,24 @@ use std::{ r" use std::{ fmt::Error, - fmt::{Display, Debug, Write}, + fmt::{Debug, Display, Write}, fmt::Result, };", ); - // FIXME: Remove redundant braces. See also unnecessary-braces diagnostic. + + cov_mark::check!(merge_with_selected_use_tree_neighbors); + check_assist( + merge_imports, + r"use std::{fmt::Result, $0fmt::Display, fmt::Debug$0};", + r"use std::{fmt::Result, fmt::{Debug, Display}};", + ); + + cov_mark::check!(merge_with_selected_use_tree_neighbors); + cov_mark::check!(replace_parent_with_normalized_use_tree); check_assist( merge_imports, r"use std::$0{fmt::Display, fmt::Debug}$0;", - r"use std::{fmt::{Display, Debug}};", + r"use std::fmt::{Debug, Display};", ); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs new file mode 100644 index 0000000000000..7d003efe721d1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs @@ -0,0 +1,219 @@ +use ide_db::imports::merge_imports::try_normalize_import; +use syntax::{ast, AstNode}; + +use crate::{ + assist_context::{AssistContext, Assists}, + AssistId, AssistKind, +}; + +// Assist: normalize_import +// +// Normalizes an import. +// +// ``` +// use$0 std::{io, {fmt::Formatter}}; +// ``` +// -> +// ``` +// use std::{fmt::Formatter, io}; +// ``` +pub(crate) fn normalize_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let use_item = if ctx.has_empty_selection() { + ctx.find_node_at_offset()? + } else { + ctx.covering_element().ancestors().find_map(ast::Use::cast)? + }; + + let target = use_item.syntax().text_range(); + let normalized_use_item = + try_normalize_import(&use_item, ctx.config.insert_use.granularity.into())?; + + acc.add( + AssistId("normalize_import", AssistKind::RefactorRewrite), + "Normalize import", + target, + |builder| { + builder.replace_ast(use_item, normalized_use_item); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{ + check_assist, check_assist_import_one, check_assist_not_applicable, + check_assist_not_applicable_for_import_one, + }; + + use super::*; + + macro_rules! check_assist_variations { + ($fixture: literal, $expected: literal) => { + check_assist( + normalize_import, + concat!("use $0", $fixture, ";"), + concat!("use ", $expected, ";"), + ); + check_assist( + normalize_import, + concat!("$0use ", $fixture, ";"), + concat!("use ", $expected, ";"), + ); + + check_assist_import_one( + normalize_import, + concat!("use $0", $fixture, ";"), + concat!("use {", $expected, "};"), + ); + check_assist_import_one( + normalize_import, + concat!("$0use ", $fixture, ";"), + concat!("use {", $expected, "};"), + ); + + check_assist_import_one( + normalize_import, + concat!("use $0{", $fixture, "};"), + concat!("use {", $expected, "};"), + ); + check_assist_import_one( + normalize_import, + concat!("$0use {", $fixture, "};"), + concat!("use {", $expected, "};"), + ); + + check_assist( + normalize_import, + concat!("use $0", $fixture, "$0;"), + concat!("use ", $expected, ";"), + ); + check_assist( + normalize_import, + concat!("$0use ", $fixture, ";$0"), + concat!("use ", $expected, ";"), + ); + }; + } + + macro_rules! check_assist_not_applicable_variations { + ($fixture: literal) => { + check_assist_not_applicable(normalize_import, concat!("use $0", $fixture, ";")); + check_assist_not_applicable(normalize_import, concat!("$0use ", $fixture, ";")); + + check_assist_not_applicable_for_import_one( + normalize_import, + concat!("use $0{", $fixture, "};"), + ); + check_assist_not_applicable_for_import_one( + normalize_import, + concat!("$0use {", $fixture, "};"), + ); + }; + } + + #[test] + fn test_order() { + check_assist_variations!( + "foo::{*, Qux, bar::{Quux, Bar}, baz, FOO_BAZ, self, Baz}", + "foo::{self, bar::{Bar, Quux}, baz, Baz, Qux, FOO_BAZ, *}" + ); + } + + #[test] + fn test_redundant_braces() { + check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{baz, Qux}"); + check_assist_variations!("foo::{bar::{self}}", "foo::bar"); + check_assist_variations!("foo::{bar::{*}}", "foo::bar::*"); + check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux"); + check_assist_variations!( + "foo::bar::{{FOO_BAZ, Qux, self}, {*, baz}}", + "foo::bar::{self, baz, Qux, FOO_BAZ, *}" + ); + check_assist_variations!( + "foo::bar::{{{FOO_BAZ}, {{Qux}, {self}}}, {{*}, {baz}}}", + "foo::bar::{self, baz, Qux, FOO_BAZ, *}" + ); + } + + #[test] + fn test_merge() { + check_assist_variations!( + "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux}}", + "foo::{bar::{self, baz, *}, qux, Quux, FOO_BAZ, *}" + ); + check_assist_variations!( + "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux, bar::{baz::Foo}}}", + "foo::{bar::{self, baz::{self, Foo}, *}, qux, Quux, FOO_BAZ, *}" + ); + } + + #[test] + fn test_merge_self() { + check_assist_variations!("std::{fmt, fmt::Display}", "std::fmt::{self, Display}"); + } + + #[test] + fn test_merge_nested() { + check_assist_variations!("std::{fmt::Debug, fmt::Display}", "std::fmt::{Debug, Display}"); + } + + #[test] + fn test_merge_nested2() { + check_assist_variations!("std::{fmt::Debug, fmt::Display}", "std::fmt::{Debug, Display}"); + } + + #[test] + fn test_merge_self_with_nested_self_item() { + check_assist_variations!( + "std::{fmt::{self, Debug}, fmt::{Write, Display}}", + "std::fmt::{self, Debug, Display, Write}" + ); + } + + #[test] + fn works_with_trailing_comma() { + check_assist( + normalize_import, + r" +use $0{ + foo::bar, + foo::baz, +}; + ", + r" +use foo::{bar, baz}; + ", + ); + check_assist_import_one( + normalize_import, + r" +use $0{ + foo::bar, + foo::baz, +}; +", + r" +use { + foo::{bar, baz}, +}; +", + ); + } + + #[test] + fn not_applicable_to_normalized_import() { + check_assist_not_applicable_variations!("foo::bar"); + check_assist_not_applicable_variations!("foo::bar::*"); + check_assist_not_applicable_variations!("foo::bar::Qux as Quux"); + check_assist_not_applicable_variations!("foo::bar::{self, baz, Qux, FOO_BAZ, *}"); + check_assist_not_applicable_variations!( + "foo::{self, bar::{Bar, Quux}, baz, Baz, Qux, FOO_BAZ, *}" + ); + check_assist_not_applicable_variations!( + "foo::{bar::{self, baz, *}, qux, Quux, FOO_BAZ, *}" + ); + check_assist_not_applicable_variations!( + "foo::{bar::{self, baz::{self, Foo}, *}, qux, Quux, FOO_BAZ, *}" + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index 859ed1476c457..35bf84c434988 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -54,7 +54,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) .filter_map(|u| { // Find any uses trees that are unused - let use_module = ctx.sema.scope(&u.syntax()).map(|s| s.module())?; + let use_module = ctx.sema.scope(u.syntax()).map(|s| s.module())?; let scope = match search_scopes.entry(use_module) { Entry::Occupied(o) => o.into_mut(), Entry::Vacant(v) => v.insert(module_search_scope(ctx.db(), use_module)), @@ -113,10 +113,8 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) { return Some(u); } - } else { - if !used_once_in_scope(ctx, def, &scope) { - return Some(u); - } + } else if !used_once_in_scope(ctx, def, scope) { + return Some(u); } None @@ -208,7 +206,7 @@ fn module_search_scope(db: &RootDatabase, module: hir::Module) -> Vec return None, + _ => None, } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs index a7e3ed793f172..7f3b0d758839f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs @@ -133,7 +133,7 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<' None, None, |func| { - let valid = func.name(ctx.sema.db).as_str() == Some(&*method_name_eager) + let valid = func.name(ctx.sema.db).as_str() == Some(method_name_eager) && func.num_params(ctx.sema.db) == n_params; valid.then_some(func) }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index f03eb6118a524..ba1c25fa5a749 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -313,7 +313,7 @@ fn main() { ", r" mod std { pub mod fmt { pub trait Display {} } } -use std::fmt::{Display, self}; +use std::fmt::{self, Display}; fn main() { fmt; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index 43a97d7d3a551..1794c88743990 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -69,7 +69,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( return None; } - if let None = let_stmt.colon_token() { + if let_stmt.colon_token().is_none() { // If there's no colon in a let statement, then there is no explicit type. // let x = fn::<...>(); let ident_range = let_stmt.pat()?.syntax().text_range(); @@ -111,7 +111,7 @@ fn generic_arg_list(expr: &Expr) -> Option { pe.path()?.segment()?.generic_arg_list() } else { cov_mark::hit!(not_applicable_if_non_path_function_call); - return None; + None } } Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs index 3a0121f55fa02..64e30b1834522 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs @@ -116,11 +116,9 @@ trait AddRewrite { new: Vec, target: TextRange, ) -> Option<()>; - fn yeet() {} } impl AddRewrite for Assists { - fn yeet() {} fn add_rewrite( &mut self, label: &str, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs index 1cfa291a29d8e..b2e8c4cf9fd53 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs @@ -37,16 +37,14 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O return None; } // Do nothing if the function isn't async. - if let None = function.async_token() { - return None; - } + function.async_token()?; // Do nothing if the function has an `await` expression in its body. if function.body()?.syntax().descendants().find_map(ast::AwaitExpr::cast).is_some() { return None; } // Do nothing if the method is a member of trait. if let Some(impl_) = function.syntax().ancestors().nth(2).and_then(ast::Impl::cast) { - if let Some(_) = impl_.trait_() { + if impl_.trait_().is_some() { return None; } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs index 939055f148c45..de801279a0e1f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs @@ -53,7 +53,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let stmts: Vec = list.statements().collect(); let initializer = ast::Expr::cast(last)?; let let_stmt = make::let_stmt(pattern, ty, Some(initializer)); - if stmts.len() > 0 { + if !stmts.is_empty() { let block = make::block_expr(stmts, None); format!("{}\n {}", update_expr_string(block.to_string()), let_stmt) } else { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 1eb4903ab2033..2fec104323dc7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -111,6 +111,8 @@ mod handlers { mod add_label_to_loop; mod add_lifetime_to_type; mod add_missing_impl_members; + mod add_missing_match_arms; + mod add_return_type; mod add_turbo_fish; mod apply_demorgan; mod auto_import; @@ -124,15 +126,15 @@ mod handlers { mod convert_iter_for_each_to_for; mod convert_let_else_to_match; mod convert_match_to_let_else; + mod convert_named_struct_to_tuple_struct; mod convert_nested_function_to_closure; + mod convert_to_guarded_return; mod convert_tuple_return_type_to_struct; mod convert_tuple_struct_to_named_struct; - mod convert_named_struct_to_tuple_struct; - mod convert_to_guarded_return; mod convert_two_arm_bool_match_to_matches_macro; mod convert_while_to_loop; - mod desugar_doc_comment; mod destructure_tuple_binding; + mod desugar_doc_comment; mod expand_glob_import; mod extract_expressions_from_format_string; mod extract_function; @@ -140,7 +142,6 @@ mod handlers { mod extract_struct_from_enum_variant; mod extract_type_alias; mod extract_variable; - mod add_missing_match_arms; mod fix_visibility; mod flip_binexpr; mod flip_comma; @@ -148,6 +149,7 @@ mod handlers { mod generate_constant; mod generate_default_from_enum_variant; mod generate_default_from_new; + mod generate_delegate_methods; mod generate_delegate_trait; mod generate_deref; mod generate_derive; @@ -162,62 +164,61 @@ mod handlers { mod generate_is_empty_from_len; mod generate_mut_trait_impl; mod generate_new; - mod generate_delegate_methods; mod generate_trait_from_impl; - mod add_return_type; mod inline_call; mod inline_const_as_literal; mod inline_local_variable; mod inline_macro; mod inline_type_alias; + mod into_to_qualified_from; + mod introduce_named_generic; mod introduce_named_lifetime; mod invert_if; mod merge_imports; mod merge_match_arms; + mod merge_nested_if; mod move_bounds; mod move_const_to_impl; + mod move_from_mod_rs; mod move_guard; mod move_module_to_file; mod move_to_mod_rs; - mod move_from_mod_rs; + mod normalize_import; mod number_representation; mod promote_local_to_const; mod pull_assignment_up; - mod qualify_path; mod qualify_method_call; + mod qualify_path; mod raw_string; mod remove_dbg; mod remove_mut; + mod remove_parentheses; mod remove_unused_imports; mod remove_unused_param; - mod remove_parentheses; mod reorder_fields; mod reorder_impl_items; - mod replace_try_expr_with_match; + mod replace_arith_op; mod replace_derive_with_manual_impl; mod replace_if_let_with_match; mod replace_is_method_with_if_let_method; - mod replace_method_eager_lazy; - mod replace_arith_op; - mod introduce_named_generic; mod replace_let_with_if_let; + mod replace_method_eager_lazy; mod replace_named_generic_with_impl; mod replace_qualified_name_with_use; mod replace_string_with_char; + mod replace_try_expr_with_match; mod replace_turbofish_with_explicit_type; - mod split_import; - mod unmerge_match_arm; - mod unwrap_tuple; mod sort_items; + mod split_import; mod toggle_ignore; + mod unmerge_match_arm; mod unmerge_use; mod unnecessary_async; + mod unqualify_method_call; mod unwrap_block; mod unwrap_result_return_type; - mod unqualify_method_call; + mod unwrap_tuple; mod wrap_return_type_in_result; - mod into_to_qualified_from; - mod merge_nested_if; pub(crate) fn all() -> &'static [Handler] { &[ @@ -300,6 +301,7 @@ mod handlers { move_module_to_file::move_module_to_file, move_to_mod_rs::move_to_mod_rs, move_from_mod_rs::move_from_mod_rs, + normalize_import::normalize_import, number_representation::reformat_number_literal, pull_assignment_up::pull_assignment_up, promote_local_to_const::promote_local_to_const, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 95b9eb52948f8..573d69b5c6d31 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -50,6 +50,21 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { assist_emit_must_use: false, }; +pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { + snippet_cap: SnippetCap::new(true), + allowed: None, + insert_use: InsertUseConfig { + granularity: ImportGranularity::One, + prefix_kind: hir::PrefixKind::Plain, + enforce_granularity: true, + group: true, + skip_glob_imports: true, + }, + prefer_no_std: false, + prefer_prelude: true, + assist_emit_must_use: false, +}; + pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { RootDatabase::with_single_file(text) } @@ -76,6 +91,22 @@ pub(crate) fn check_assist_no_snippet_cap( ); } +#[track_caller] +pub(crate) fn check_assist_import_one( + assist: Handler, + ra_fixture_before: &str, + ra_fixture_after: &str, +) { + let ra_fixture_after = trim_indent(ra_fixture_after); + check_with_config( + TEST_CONFIG_IMPORT_ONE, + assist, + ra_fixture_before, + ExpectedResult::After(&ra_fixture_after), + None, + ); +} + // There is no way to choose what assist within a group you want to test against, // so this is here to allow you choose. pub(crate) fn check_assist_by_label( @@ -106,6 +137,17 @@ pub(crate) fn check_assist_not_applicable_by_label(assist: Handler, ra_fixture: check(assist, ra_fixture, ExpectedResult::NotApplicable, Some(label)); } +#[track_caller] +pub(crate) fn check_assist_not_applicable_for_import_one(assist: Handler, ra_fixture: &str) { + check_with_config( + TEST_CONFIG_IMPORT_ONE, + assist, + ra_fixture, + ExpectedResult::NotApplicable, + None, + ); +} + /// Check assist in unresolved state. Useful to check assists for lazy computation. #[track_caller] pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) { @@ -201,7 +243,7 @@ fn check_with_config( .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty()) .expect("Assist did not contain any source changes"); let skip_header = source_change.source_file_edits.len() == 1 - && source_change.file_system_edits.len() == 0; + && source_change.file_system_edits.is_empty(); let mut buf = String::new(); for (file_id, (edit, snippet_edit)) in source_change.source_file_edits { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 0ce89ae0a9a5e..8d7c49d52c23d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -2217,6 +2217,19 @@ fn t() {} ) } +#[test] +fn doctest_normalize_import() { + check_doc_test( + "normalize_import", + r#####" +use$0 std::{io, {fmt::Formatter}}; +"#####, + r#####" +use std::{fmt::Formatter, io}; +"#####, + ) +} + #[test] fn doctest_promote_local_to_const() { check_doc_test( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs index 3da90e9052f2f..088d93f9a6ba4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs @@ -2,6 +2,7 @@ use std::{fmt, fs, path::Path}; +use stdx::format_to_acc; use test_utils::project_root; #[test] @@ -103,7 +104,7 @@ impl Assist { let doc = take_until(lines.by_ref(), "```").trim().to_string(); assert!( (doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.')) - || assist.sections.len() > 0, + || !assist.sections.is_empty(), "\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n", &assist.id, doc, @@ -172,8 +173,7 @@ impl fmt::Display for Assist { fn hide_hash_comments(text: &str) -> String { text.split('\n') // want final newline .filter(|&it| !(it.starts_with("# ") || it == "#")) - .map(|it| format!("{it}\n")) - .collect() + .fold(String::new(), |mut acc, it| format_to_acc!(acc, "{it}\n")) } fn reveal_hash_comments(text: &str) -> String { @@ -187,6 +187,5 @@ fn reveal_hash_comments(text: &str) -> String { it } }) - .map(|it| format!("{it}\n")) - .collect() + .fold(String::new(), |mut acc, it| format_to_acc!(acc, "{it}\n")) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 927a8e3c19a18..eeb3d80d07bd1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -23,8 +23,8 @@ use syntax::{ use crate::assist_context::{AssistContext, SourceChangeBuilder}; -pub(crate) mod suggest_name; mod gen_trait_fn_body; +pub(crate) mod suggest_name; pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr { extract_trivial_expression(&block_expr) @@ -117,7 +117,7 @@ pub fn filter_assoc_items( return false; } - return true; + true }) // Note: This throws away items with no source. .filter_map(|assoc_item| { @@ -165,7 +165,7 @@ pub fn add_trait_assoc_items_to_impl( target_scope: hir::SemanticsScope<'_>, ) -> ast::AssocItem { let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; - let items = original_items.into_iter().map(|InFile { file_id, value: original_item }| { + let items = original_items.iter().map(|InFile { file_id, value: original_item }| { let cloned_item = { if file_id.is_macro() { if let Some(formatted) = diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 808b23405951c..ad9cb6a171d2a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -648,7 +648,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) .into_iter() .map(gen_partial_eq_match) .collect::>>()?; - make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1)) + make::block_expr(stmts, tail).indent(ast::edit::IndentLevel(1)) } Some(ast::FieldList::TupleFieldList(field_list)) => { @@ -667,7 +667,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) .into_iter() .map(gen_partial_eq_match) .collect::>>()?; - make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1)) + make::block_expr(stmts, tail).indent(ast::edit::IndentLevel(1)) } // No fields in the body means there's nothing to compare. diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs index b4c6cbff2a4fa..78dee24a6d3a6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs @@ -185,10 +185,10 @@ fn normalize(name: &str) -> Option { } fn is_valid_name(name: &str) -> bool { - match ide_db::syntax_helpers::LexedStr::single_token(name) { - Some((syntax::SyntaxKind::IDENT, _error)) => true, - _ => false, - } + matches!( + ide_db::syntax_helpers::LexedStr::single_token(name), + Some((syntax::SyntaxKind::IDENT, _error)) + ) } fn is_useless_method(method: &ast::MethodCallExpr) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml index 7fbcf3d19e0f1..f2a11276ba2b8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml @@ -14,6 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" itertools.workspace = true +tracing.workspace = true once_cell = "1.17.0" smallvec.workspace = true @@ -38,4 +39,4 @@ test-utils.workspace = true test-fixture.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 7d38c638a8ed5..ba3c0cf3fd60e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -2,8 +2,10 @@ pub(crate) mod attribute; pub(crate) mod dot; +pub(crate) mod env_vars; pub(crate) mod expr; pub(crate) mod extern_abi; +pub(crate) mod extern_crate; pub(crate) mod field; pub(crate) mod flyimport; pub(crate) mod fn_param; @@ -19,14 +21,12 @@ pub(crate) mod snippet; pub(crate) mod r#type; pub(crate) mod use_; pub(crate) mod vis; -pub(crate) mod env_vars; -pub(crate) mod extern_crate; use std::iter; use hir::{known, HasAttrs, ScopeDef, Variant}; use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind}; -use syntax::ast; +use syntax::{ast, SmolStr}; use crate::{ context::{ @@ -80,7 +80,11 @@ impl Completions { } pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) { - let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword); + let item = CompletionItem::new( + CompletionItemKind::Keyword, + ctx.source_range(), + SmolStr::new_static(keyword), + ); item.add_to(self, ctx.db); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index 9155caa2e0b85..a7a6cdebd361e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -25,8 +25,8 @@ use crate::{ mod cfg; mod derive; mod lint; -mod repr; mod macro_use; +mod repr; pub(crate) use self::derive::complete_derive_path; @@ -44,9 +44,7 @@ pub(crate) fn complete_known_attribute_input( None => None, }; let (path, tt) = name_ref.zip(attribute.token_tree())?; - if tt.l_paren_token().is_none() { - return None; - } + tt.l_paren_token()?; match path.text().as_str() { "repr" => repr::complete_repr(acc, ctx, tt), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 53a1c8405c2c1..00135a6d202cb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -1,6 +1,7 @@ //! Completes references after dot (fields and method calls). use ide_db::FxHashSet; +use syntax::SmolStr; use crate::{ context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified}, @@ -20,14 +21,17 @@ pub(crate) fn complete_dot( // Suggest .await syntax for types that implement Future trait if receiver_ty.impls_into_future(ctx.db) { - let mut item = - CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await"); + let mut item = CompletionItem::new( + CompletionItemKind::Keyword, + ctx.source_range(), + SmolStr::new_static("await"), + ); item.detail("expr.await"); item.add_to(acc, ctx.db); } let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. }); - let is_method_acces_with_parens = + let is_method_access_with_parens = matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); complete_fields( @@ -37,7 +41,7 @@ pub(crate) fn complete_dot( |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty), |acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty), is_field_access, - is_method_acces_with_parens, + is_method_access_with_parens, ); complete_methods(ctx, receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None)); @@ -110,14 +114,14 @@ fn complete_fields( mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type), mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type), is_field_access: bool, - is_method_acess_with_parens: bool, + is_method_access_with_parens: bool, ) { let mut seen_names = FxHashSet::default(); for receiver in receiver.autoderef(ctx.db) { for (field, ty) in receiver.fields(ctx.db) { if seen_names.insert(field.name(ctx.db)) && (is_field_access - || (is_method_acess_with_parens && (ty.is_fn() || ty.is_closure()))) + || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure()))) { named_field(acc, field, ty); } @@ -127,7 +131,7 @@ fn complete_fields( // already seen without inserting into the hashset. if !seen_names.contains(&hir::Name::new_tuple_field(i)) && (is_field_access - || (is_method_acess_with_parens && (ty.is_fn() || ty.is_closure()))) + || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure()))) { // Tuple fields are always public (tuple struct fields are handled above). tuple_index(acc, i, ty); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs index 419b864565559..35e6b97eb783a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs @@ -37,7 +37,7 @@ pub(crate) fn complete_cargo_env_vars( guard_env_macro(expanded, &ctx.sema)?; let range = expanded.text_range_between_quotes()?; - CARGO_DEFINED_VARS.into_iter().for_each(|&(var, detail)| { + CARGO_DEFINED_VARS.iter().for_each(|&(var, detail)| { let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var); item.detail(detail); item.add_to(acc, ctx.db); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index d3c817d4b43ad..1433216d6111d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -15,7 +15,7 @@ pub(crate) fn complete_expr_path( path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, expr_ctx: &ExprCtx, ) { - let _p = profile::span("complete_expr_path"); + let _p = tracing::span!(tracing::Level::INFO, "complete_expr_path").entered(); if !ctx.qualifier_ctx.none() { return; } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index e411c1c869c55..b5d5604c7519f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -1,7 +1,7 @@ //! Completes function abi strings. use syntax::{ ast::{self, IsString}, - AstNode, AstToken, + AstNode, AstToken, SmolStr, }; use crate::{ @@ -26,7 +26,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ "ptx-kernel", "msp430-interrupt", "x86-interrupt", - "amdgpu-kernel", "efiapi", "avr-interrupt", "avr-non-blocking-interrupt", @@ -53,7 +52,8 @@ pub(crate) fn complete_extern_abi( let abi_str = expanded; let source_range = abi_str.text_range_between_quotes()?; for &abi in SUPPORTED_CALLING_CONVENTIONS { - CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc, ctx.db); + CompletionItem::new(CompletionItemKind::Keyword, source_range, SmolStr::new_static(abi)) + .add_to(acc, ctx.db); } Some(()) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs index 870df63b7bf2a..53fcb7ca6c029 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs @@ -11,22 +11,18 @@ pub(crate) fn complete_field_list_tuple_variant( path_ctx: &PathCompletionCtx, ) { if ctx.qualifier_ctx.vis_node.is_some() { - return; - } - match path_ctx { - PathCompletionCtx { - has_macro_bang: false, - qualified: Qualified::No, - parent: None, - has_type_args: false, - .. - } => { - let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); - add_keyword("pub(crate)", "pub(crate)"); - add_keyword("pub(super)", "pub(super)"); - add_keyword("pub", "pub"); - } - _ => (), + } else if let PathCompletionCtx { + has_macro_bang: false, + qualified: Qualified::No, + parent: None, + has_type_args: false, + .. + } = path_ctx + { + let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); + add_keyword("pub(crate)", "pub(crate)"); + add_keyword("pub(super)", "pub(super)"); + add_keyword("pub", "pub"); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index 446f0be83481f..0e04ad35d33d1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -207,11 +207,10 @@ fn import_on_the_fly( position: SyntaxNode, potential_import_name: String, ) -> Option<()> { - let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone()); + let _p = + tracing::span!(tracing::Level::INFO, "import_on_the_fly", ?potential_import_name).entered(); - if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() { - return None; - } + ImportScope::find_insert_use_container(&position, &ctx.sema)?; let ns_filter = |import: &LocatedImport| { match (kind, import.original_item) { @@ -295,11 +294,10 @@ fn import_on_the_fly_pat_( position: SyntaxNode, potential_import_name: String, ) -> Option<()> { - let _p = profile::span("import_on_the_fly_pat").detail(|| potential_import_name.clone()); + let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat", ?potential_import_name) + .entered(); - if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() { - return None; - } + ImportScope::find_insert_use_container(&position, &ctx.sema)?; let ns_filter = |import: &LocatedImport| match import.original_item { ItemInNs::Macros(mac) => mac.is_fn_like(ctx.db), @@ -347,11 +345,11 @@ fn import_on_the_fly_method( position: SyntaxNode, potential_import_name: String, ) -> Option<()> { - let _p = profile::span("import_on_the_fly_method").detail(|| potential_import_name.clone()); + let _p = + tracing::span!(tracing::Level::INFO, "import_on_the_fly_method", ?potential_import_name) + .entered(); - if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() { - return None; - } + ImportScope::find_insert_use_container(&position, &ctx.sema)?; let user_input_lowercased = potential_import_name.to_lowercase(); @@ -375,11 +373,10 @@ fn import_on_the_fly_method( }; key(&a.import_path).cmp(&key(&b.import_path)) }) - .for_each(|import| match import.original_item { - ItemInNs::Values(hir::ModuleDef::Function(f)) => { + .for_each(|import| { + if let ItemInNs::Values(hir::ModuleDef::Function(f)) = import.original_item { acc.add_method_with_import(ctx, dot_access, f, import); } - _ => (), }); Some(()) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index 8b38d4f01f673..d67c00c6c6942 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -108,7 +108,7 @@ fn fill_fn_params( remove_duplicated(&mut file_params, param_list.params()); let self_completion_items = ["self", "&self", "mut self", "&mut self"]; if should_add_self_completions(ctx.token.text_range().start(), param_list, impl_) { - self_completion_items.into_iter().for_each(|self_item| add_new_item_to_acc(self_item)); + self_completion_items.into_iter().for_each(&mut add_new_item_to_acc); } file_params.keys().for_each(|whole_param| add_new_item_to_acc(whole_param)); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs index 5ea6a49b1ae15..addd9dac1a766 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs @@ -28,7 +28,7 @@ pub(crate) fn complete_item_list( path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, kind: &ItemListKind, ) { - let _p = profile::span("complete_item_list"); + let _p = tracing::span!(tracing::Level::INFO, "complete_item_list").entered(); if path_ctx.is_trivial_path() { add_keywords(acc, ctx, Some(kind)); } @@ -80,7 +80,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_))); let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); - let in_block = matches!(kind, None); + let in_block = kind.is_none(); if !in_trait_impl { if ctx.qualifier_ctx.unsafe_tok.is_some() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index b0e4d8a5acd10..3c4b89ca742ec 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -38,7 +38,7 @@ use ide_db::{ }; use syntax::{ ast::{self, edit_in_place::AttrsOwnerEdit, HasTypeBounds}, - AstNode, SyntaxElement, SyntaxKind, TextRange, T, + format_smolstr, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, T, }; use text_edit::TextEdit; @@ -180,7 +180,7 @@ fn add_function_impl( ) { let fn_name = func.name(ctx.db); - let label = format!( + let label = format_smolstr!( "fn {}({})", fn_name.display(ctx.db), if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } @@ -254,7 +254,7 @@ fn add_type_alias_impl( ) { let alias_name = type_alias.name(ctx.db).unescaped().to_smol_str(); - let label = format!("type {alias_name} ="); + let label = format_smolstr!("type {alias_name} ="); let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); item.lookup_by(format!("type {alias_name}")) @@ -329,7 +329,7 @@ fn add_const_impl( let replacement = format!("{label} "); let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label); - item.lookup_by(format!("const {const_name}")) + item.lookup_by(format_smolstr!("const {const_name}")) .set_documentation(const_.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, @@ -348,7 +348,7 @@ fn add_const_impl( } } -fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String { +fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> SmolStr { let const_ = if needs_whitespace { insert_whitespace_into_node::insert_ws_into(const_.syntax().clone()) } else { @@ -368,7 +368,7 @@ fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> Strin let syntax = const_.text().slice(range).to_string(); - format!("{} =", syntax.trim_end()) + format_smolstr!("{} =", syntax.trim_end()) } fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index 5d138eea46f4b..ecf5b29e2c0c3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -21,7 +21,7 @@ pub(crate) fn complete_mod( return None; } - let _p = profile::span("completion::complete_mod"); + let _p = tracing::span!(tracing::Level::INFO, "completion::complete_mod").entered(); let mut current_module = ctx.module; // For `mod $0`, `ctx.module` is its parent, but for `mod f$0`, it's `mod f` itself, but we're diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index fc21bba456b56..af83d4104f76e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -84,6 +84,13 @@ pub(crate) fn complete_postfix( ) .add_to(acc, ctx.db); + postfix_snippet( + "lete", + "let Ok else {}", + &format!("let Ok($1) = {receiver_text} else {{\n $2\n}};\n$0"), + ) + .add_to(acc, ctx.db); + postfix_snippet( "while", "while let Ok {}", @@ -99,6 +106,13 @@ pub(crate) fn complete_postfix( ) .add_to(acc, ctx.db); + postfix_snippet( + "lete", + "let Some else {}", + &format!("let Some($1) = {receiver_text} else {{\n $2\n}};\n$0"), + ) + .add_to(acc, ctx.db); + postfix_snippet( "while", "while let Some {}", @@ -306,9 +320,7 @@ fn add_custom_postfix_completions( postfix_snippet: impl Fn(&str, &str, &str) -> Builder, receiver_text: &str, ) -> Option<()> { - if ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema).is_none() { - return None; - } + ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema)?; ctx.config.postfix_snippets().filter(|(_, snip)| snip.scope == SnippetScope::Expr).for_each( |(trigger, snippet)| { let imports = match snippet.imports(ctx) { @@ -471,6 +483,29 @@ fn main() { ); } + #[test] + fn option_letelse() { + check_edit( + "lete", + r#" +//- minicore: option +fn main() { + let bar = Some(true); + bar.$0 +} +"#, + r#" +fn main() { + let bar = Some(true); + let Some($1) = bar else { + $2 +}; +$0 +} +"#, + ); + } + #[test] fn result_match() { check_edit( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 46213deb0afef..e53d1cc6322eb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -1,6 +1,9 @@ //! Complete fields in record literals and patterns. use ide_db::SymbolKind; -use syntax::ast::{self, Expr}; +use syntax::{ + ast::{self, Expr}, + SmolStr, +}; use crate::{ context::{DotAccess, DotAccessKind, PatternContext}, @@ -66,8 +69,11 @@ pub(crate) fn complete_record_expr_fields( } if dot_prefix { cov_mark::hit!(functional_update_one_dot); - let mut item = - CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); + let mut item = CompletionItem::new( + CompletionItemKind::Snippet, + ctx.source_range(), + SmolStr::new_static(".."), + ); item.insert_text("."); item.add_to(acc, ctx.db); return; @@ -91,7 +97,11 @@ pub(crate) fn add_default_update( // FIXME: This should make use of scope_def like completions so we get all the other goodies // that is we should handle this like actually completing the default function let completion_text = "..Default::default()"; - let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); + let mut item = CompletionItem::new( + SymbolKind::Field, + ctx.source_range(), + SmolStr::new_static(completion_text), + ); let completion_text = completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); item.insert_text(completion_text).set_relevance(CompletionRelevance { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs index 3ff68b97882d2..a01919220503d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs @@ -129,9 +129,7 @@ fn add_custom_completions( cap: SnippetCap, scope: SnippetScope, ) -> Option<()> { - if ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema).is_none() { - return None; - } + ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema)?; ctx.config.prefix_snippets().filter(|(_, snip)| snip.scope == scope).for_each( |(trigger, snip)| { let imports = match snip.imports(ctx) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index a30fd13b1d5f3..e6a4335c3fec8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -15,7 +15,7 @@ pub(crate) fn complete_type_path( path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, location: &TypeLocation, ) { - let _p = profile::span("complete_type_path"); + let _p = tracing::span!(tracing::Level::INFO, "complete_type_path").entered(); let scope_def_applicable = |def| { use hir::{GenericParam::*, ModuleDef::*}; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs index 81107c1f419d2..27e9d1d6cfe0c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs @@ -2,7 +2,7 @@ use hir::ScopeDef; use ide_db::{FxHashSet, SymbolKind}; -use syntax::{ast, AstNode}; +use syntax::{ast, format_smolstr, AstNode}; use crate::{ context::{CompletionContext, PathCompletionCtx, Qualified}, @@ -108,7 +108,7 @@ pub(crate) fn complete_use_path( let item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Enum), ctx.source_range(), - format!("{}::", e.name(ctx.db).display(ctx.db)), + format_smolstr!("{}::", e.name(ctx.db).display(ctx.db)), ); acc.add(item.build(ctx.db)); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 92aa1da89c411..2c0370c58f70a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -186,14 +186,13 @@ impl TypeLocation { } pub(crate) fn complete_consts(&self) -> bool { - match self { + matches!( + self, TypeLocation::GenericArg { corresponding_param: Some(ast::GenericParam::ConstParam(_)), .. - } => true, - TypeLocation::AssocConstEq => true, - _ => false, - } + } | TypeLocation::AssocConstEq + ) } pub(crate) fn complete_types(&self) -> bool { @@ -569,7 +568,8 @@ impl CompletionContext<'_> { /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items and /// passes all doc-aliases along, to funnel it into [`Completions::add_path_resolution`]. pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec)) { - let _p = profile::span("CompletionContext::process_all_names"); + let _p = + tracing::span!(tracing::Level::INFO, "CompletionContext::process_all_names").entered(); self.scope.process_all_names(&mut |name, def| { if self.is_scope_def_hidden(def) { return; @@ -580,7 +580,8 @@ impl CompletionContext<'_> { } pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { - let _p = profile::span("CompletionContext::process_all_names_raw"); + let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::process_all_names_raw") + .entered(); self.scope.process_all_names(f); } @@ -638,7 +639,7 @@ impl<'a> CompletionContext<'a> { position @ FilePosition { file_id, offset }: FilePosition, config: &'a CompletionConfig, ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> { - let _p = profile::span("CompletionContext::new"); + let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::new").entered(); let sema = Semantics::new(db); let original_file = sema.parse(file_id); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 7da6648365740..c06b64df1c525 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -72,7 +72,7 @@ fn expand( mut fake_ident_token: SyntaxToken, relative_offset: TextSize, ) -> ExpansionResult { - let _p = profile::span("CompletionContext::expand"); + let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::expand").entered(); let mut derive_ctx = None; 'expansion: loop { @@ -211,7 +211,7 @@ fn analyze( original_token: &SyntaxToken, self_token: &SyntaxToken, ) -> Option<(CompletionAnalysis, (Option, Option), QualifierCtx)> { - let _p = profile::span("CompletionContext::analyze"); + let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::analyze").entered(); let ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx } = expansion_result; @@ -796,8 +796,7 @@ fn classify_name_ref( ast::AssocTypeArg(arg) => { let trait_ = ast::PathSegment::cast(arg.syntax().parent()?.parent()?)?; match sema.resolve_path(&trait_.parent_path().top_path())? { - hir::PathResolution::Def(def) => match def { - hir::ModuleDef::Trait(trait_) => { + hir::PathResolution::Def(hir::ModuleDef::Trait(trait_)) => { let arg_name = arg.name_ref()?; let arg_name = arg_name.text(); let trait_items = trait_.items_with_supertraits(sema.db); @@ -810,8 +809,6 @@ fn classify_name_ref( })?; sema.source(*assoc_ty)?.value.generic_param_list() } - _ => None, - }, _ => None, } }, @@ -866,9 +863,7 @@ fn classify_name_ref( TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body())) }, ast::RetType(it) => { - if it.thin_arrow_token().is_none() { - return None; - } + it.thin_arrow_token()?; let parent = match ast::Fn::cast(parent.parent()?) { Some(it) => it.param_list(), None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(), @@ -888,15 +883,11 @@ fn classify_name_ref( })) }, ast::Param(it) => { - if it.colon_token().is_none() { - return None; - } + it.colon_token()?; TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat()))) }, ast::LetStmt(it) => { - if it.colon_token().is_none() { - return None; - } + it.colon_token()?; TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat()))) }, ast::Impl(it) => { @@ -1276,8 +1267,7 @@ fn pattern_context_for( pat .syntax() .ancestors() - .skip_while(|it| ast::Pat::can_cast(it.kind())) - .next() + .find(|it| !ast::Pat::can_cast(it.kind())) .map_or((PatternRefutability::Irrefutable, false), |node| { let refutability = match_ast! { match node { @@ -1312,7 +1302,7 @@ fn pattern_context_for( .parent() .and_then(ast::MatchExpr::cast) .and_then(|match_expr| { - let expr_opt = find_opt_node_in_file(&original_file, match_expr.expr()); + let expr_opt = find_opt_node_in_file(original_file, match_expr.expr()); expr_opt.and_then(|expr| { sema.type_of_expr(&expr)? @@ -1321,24 +1311,20 @@ fn pattern_context_for( .find_map(|ty| match ty.as_adt() { Some(hir::Adt::Enum(e)) => Some(e), _ => None, - }).and_then(|enum_| { - Some(enum_.variants(sema.db)) - }) + }).map(|enum_| enum_.variants(sema.db)) }) - }).and_then(|variants| { - Some(variants.iter().filter_map(|variant| { + }).map(|variants| variants.iter().filter_map(|variant| { let variant_name = variant.name(sema.db).display(sema.db).to_string(); let variant_already_present = match_arm_list.arms().any(|arm| { arm.pat().and_then(|pat| { let pat_already_present = pat.syntax().to_string().contains(&variant_name); - pat_already_present.then(|| pat_already_present) + pat_already_present.then_some(pat_already_present) }).is_some() }); - (!variant_already_present).then_some(variant.clone()) + (!variant_already_present).then_some(*variant) }).collect::>()) - }) }); if let Some(missing_variants_) = missing_variants_opt { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index affd9b729646d..bcf169f46530d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -10,7 +10,7 @@ use ide_db::{ use itertools::Itertools; use smallvec::SmallVec; use stdx::{impl_from, never}; -use syntax::{SmolStr, TextRange, TextSize}; +use syntax::{format_smolstr, SmolStr, TextRange, TextSize}; use text_edit::TextEdit; use crate::{ @@ -433,7 +433,7 @@ impl Builder { } pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem { - let _p = profile::span("item::Builder::build"); + let _p = tracing::span!(tracing::Level::INFO, "item::Builder::build").entered(); let label = self.label; let mut label_detail = None; @@ -442,7 +442,7 @@ impl Builder { if !self.doc_aliases.is_empty() { let doc_aliases = self.doc_aliases.iter().join(", "); - label_detail.replace(SmolStr::from(format!(" (alias {doc_aliases})"))); + label_detail.replace(format_smolstr!(" (alias {doc_aliases})")); let lookup_doc_aliases = self .doc_aliases .iter() @@ -459,21 +459,21 @@ impl Builder { // after typing a comma or space. .join(""); if !lookup_doc_aliases.is_empty() { - lookup = SmolStr::from(format!("{lookup}{lookup_doc_aliases}")); + lookup = format_smolstr!("{lookup}{lookup_doc_aliases}"); } } if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one - label_detail.replace(SmolStr::from(format!( + label_detail.replace(format_smolstr!( "{} (use {})", label_detail.as_deref().unwrap_or_default(), import_edit.import_path.display(db) - ))); + )); } else if let Some(trait_name) = self.trait_name { - label_detail.replace(SmolStr::from(format!( + label_detail.replace(format_smolstr!( "{} (as {trait_name})", label_detail.as_deref().unwrap_or_default(), - ))); + )); } let text_edit = match self.text_edit { @@ -553,7 +553,7 @@ impl Builder { self.detail = detail.map(Into::into); if let Some(detail) = &self.detail { if never!(detail.contains('\n'), "multiline detail:\n{}", detail) { - self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string()); + self.detail = Some(detail.split('\n').next().unwrap().to_string()); } } self diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 6a98e109f6dff..733523d369424 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -8,9 +8,9 @@ mod context; mod item; mod render; +mod snippet; #[cfg(test)] mod tests; -mod snippet; use ide_db::{ base_db::FilePosition, @@ -236,7 +236,7 @@ pub fn resolve_completion_edits( FilePosition { file_id, offset }: FilePosition, imports: impl IntoIterator, ) -> Option> { - let _p = profile::span("resolve_completion_edits"); + let _p = tracing::span!(tracing::Level::INFO, "resolve_completion_edits").entered(); let sema = hir::Semantics::new(db); let original_file = sema.parse(file_id); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 8c0e6694761ed..4d49d2f4987f1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -1,14 +1,14 @@ //! `render` module provides utilities for rendering completion suggestions //! into code pieces that will be presented to user. -pub(crate) mod macro_; -pub(crate) mod function; pub(crate) mod const_; +pub(crate) mod function; +pub(crate) mod literal; +pub(crate) mod macro_; pub(crate) mod pattern; pub(crate) mod type_alias; -pub(crate) mod variant; pub(crate) mod union_literal; -pub(crate) mod literal; +pub(crate) mod variant; use hir::{AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type}; use ide_db::{ @@ -17,7 +17,7 @@ use ide_db::{ imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, }; -use syntax::{AstNode, SmolStr, SyntaxKind, TextRange}; +use syntax::{format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange}; use text_edit::TextEdit; use crate::{ @@ -202,7 +202,7 @@ fn field_with_receiver( ) -> SmolStr { receiver.map_or_else( || field_name.into(), - |receiver| format!("{}.{field_name}", receiver.display(db)).into(), + |receiver| format_smolstr!("{}.{field_name}", receiver.display(db)), ) } @@ -292,18 +292,15 @@ fn render_resolution_pat( import_to_add: Option, resolution: ScopeDef, ) -> Builder { - let _p = profile::span("render_resolution"); + let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered(); use hir::ModuleDef::*; - match resolution { - ScopeDef::ModuleDef(Macro(mac)) => { - let ctx = ctx.import_to_add(import_to_add); - return render_macro_pat(ctx, pattern_ctx, local_name, mac); - } - _ => (), + if let ScopeDef::ModuleDef(Macro(mac)) = resolution { + let ctx = ctx.import_to_add(import_to_add); + render_macro_pat(ctx, pattern_ctx, local_name, mac) + } else { + render_resolution_simple_(ctx, &local_name, import_to_add, resolution) } - - render_resolution_simple_(ctx, &local_name, import_to_add, resolution) } fn render_resolution_path( @@ -313,7 +310,7 @@ fn render_resolution_path( import_to_add: Option, resolution: ScopeDef, ) -> Builder { - let _p = profile::span("render_resolution"); + let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered(); use hir::ModuleDef::*; match resolution { @@ -421,7 +418,7 @@ fn render_resolution_simple_( import_to_add: Option, resolution: ScopeDef, ) -> Builder { - let _p = profile::span("render_resolution"); + let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered(); let db = ctx.db(); let ctx = ctx.import_to_add(import_to_add); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs index 3c73983c39a2b..a2bfac994ff0b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs @@ -6,7 +6,7 @@ use ide_db::SymbolKind; use crate::{item::CompletionItem, render::RenderContext}; pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option { - let _p = profile::span("render_const"); + let _p = tracing::span!(tracing::Level::INFO, "render_const").entered(); render(ctx, const_) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 6ad84eba33bea..4ae7ea861c75b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -4,7 +4,7 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay}; use ide_db::{SnippetCap, SymbolKind}; use itertools::Itertools; use stdx::{format_to, to_lower_snake_case}; -use syntax::{AstNode, SmolStr}; +use syntax::{format_smolstr, AstNode, SmolStr}; use crate::{ context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind}, @@ -25,7 +25,7 @@ pub(crate) fn render_fn( local_name: Option, func: hir::Function, ) -> Builder { - let _p = profile::span("render_fn"); + let _p = tracing::span!(tracing::Level::INFO, "render_fn").entered(); render(ctx, local_name, func, FuncKind::Function(path_ctx)) } @@ -36,7 +36,7 @@ pub(crate) fn render_method( local_name: Option, func: hir::Function, ) -> Builder { - let _p = profile::span("render_method"); + let _p = tracing::span!(tracing::Level::INFO, "render_method").entered(); render(ctx, local_name, func, FuncKind::Method(dot_access, receiver)) } @@ -52,13 +52,12 @@ fn render( let (call, escaped_call) = match &func_kind { FuncKind::Method(_, Some(receiver)) => ( - format!( + format_smolstr!( "{}.{}", receiver.unescaped().display(ctx.db()), name.unescaped().display(ctx.db()) - ) - .into(), - format!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())).into(), + ), + format_smolstr!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())), ), _ => (name.unescaped().to_smol_str(), name.to_smol_str()), }; @@ -305,9 +304,7 @@ fn params( func_kind: &FuncKind<'_>, has_dot_receiver: bool, ) -> Option<(Option, Vec)> { - if ctx.config.callable.is_none() { - return None; - } + ctx.config.callable.as_ref()?; // Don't add parentheses if the expected type is a function reference with the same signature. if let Some(expected) = ctx.expected_type.as_ref().filter(|e| e.is_fn()) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs index b218502f7f05d..f52a5f7625557 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs @@ -27,7 +27,7 @@ pub(crate) fn render_variant_lit( variant: hir::Variant, path: Option, ) -> Option { - let _p = profile::span("render_enum_variant"); + let _p = tracing::span!(tracing::Level::INFO, "render_enum_variant").entered(); let db = ctx.db(); let name = local_name.unwrap_or_else(|| variant.name(db)); @@ -41,7 +41,7 @@ pub(crate) fn render_struct_literal( path: Option, local_name: Option, ) -> Option { - let _p = profile::span("render_struct_literal"); + let _p = tracing::span!(tracing::Level::INFO, "render_struct_literal").entered(); let db = ctx.db(); let name = local_name.unwrap_or_else(|| strukt.name(db)); @@ -57,11 +57,11 @@ fn render( ) -> Option { let db = completion.db; let mut kind = thing.kind(db); - let should_add_parens = match &path_ctx { - PathCompletionCtx { has_call_parens: true, .. } => false, - PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } => false, - _ => true, - }; + let should_add_parens = !matches!( + path_ctx, + PathCompletionCtx { has_call_parens: true, .. } + | PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } + ); let fields = thing.fields(completion)?; let (qualified_name, short_qualified_name, qualified) = match path { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs index 68d175c2bd50e..540cfd03d6061 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs @@ -2,7 +2,7 @@ use hir::HirDisplay; use ide_db::{documentation::Documentation, SymbolKind}; -use syntax::SmolStr; +use syntax::{format_smolstr, SmolStr}; use crate::{ context::{PathCompletionCtx, PathKind, PatternContext}, @@ -17,7 +17,7 @@ pub(crate) fn render_macro( name: hir::Name, macro_: hir::Macro, ) -> Builder { - let _p = profile::span("render_macro"); + let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered(); render(ctx, *kind == PathKind::Use, *has_macro_bang, *has_call_parens, name, macro_) } @@ -27,7 +27,7 @@ pub(crate) fn render_macro_pat( name: hir::Name, macro_: hir::Macro, ) -> Builder { - let _p = profile::span("render_macro"); + let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered(); render(ctx, false, false, false, name, macro_) } @@ -94,7 +94,7 @@ fn label( ) -> SmolStr { if needs_bang { if ctx.snippet_cap().is_some() { - SmolStr::from_iter([&*name, "!", bra, "…", ket]) + format_smolstr!("{name}!{bra}…{ket}",) } else { banged_name(name) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 6f998119b7cac..a5f851566cb08 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -20,7 +20,7 @@ pub(crate) fn render_struct_pat( strukt: hir::Struct, local_name: Option, ) -> Option { - let _p = profile::span("render_struct_pat"); + let _p = tracing::span!(tracing::Level::INFO, "render_struct_pat").entered(); let fields = strukt.fields(ctx.db()); let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, strukt)?; @@ -50,7 +50,7 @@ pub(crate) fn render_variant_pat( local_name: Option, path: Option<&hir::ModPath>, ) -> Option { - let _p = profile::span("render_variant_pat"); + let _p = tracing::span!(tracing::Level::INFO, "render_variant_pat").entered(); let fields = variant.fields(ctx.db()); let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs index 343ba7e28d8e0..b192309e93f34 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs @@ -10,7 +10,7 @@ pub(crate) fn render_type_alias( ctx: RenderContext<'_>, type_alias: hir::TypeAlias, ) -> Option { - let _p = profile::span("render_type_alias"); + let _p = tracing::span!(tracing::Level::INFO, "render_type_alias").entered(); render(ctx, type_alias, false) } @@ -18,7 +18,7 @@ pub(crate) fn render_type_alias_with_eq( ctx: RenderContext<'_>, type_alias: hir::TypeAlias, ) -> Option { - let _p = profile::span("render_type_alias_with_eq"); + let _p = tracing::span!(tracing::Level::INFO, "render_type_alias_with_eq").entered(); render(ctx, type_alias, true) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index f13754e2ded05..154b69875aea8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -12,8 +12,8 @@ mod attribute; mod expression; mod flyimport; mod fn_param; -mod item_list; mod item; +mod item_list; mod pattern; mod predicate; mod proc_macros; @@ -210,23 +210,14 @@ pub(crate) fn check_edit_with_config( let mut combined_edit = completion.text_edit.clone(); - resolve_completion_edits( - &db, - &config, - position, - completion - .import_to_add - .iter() - .cloned() - .filter_map(|(import_path, import_name)| Some((import_path, import_name))), - ) - .into_iter() - .flatten() - .for_each(|text_edit| { - combined_edit.union(text_edit).expect( - "Failed to apply completion resolve changes: change ranges overlap, but should not", - ) - }); + resolve_completion_edits(&db, &config, position, completion.import_to_add.iter().cloned()) + .into_iter() + .flatten() + .for_each(|text_edit| { + combined_edit.union(text_edit).expect( + "Failed to apply completion resolve changes: change ranges overlap, but should not", + ) + }); combined_edit.apply(&mut actual); assert_eq_text!(&ra_fixture_after, &actual) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b4f936b35aead..758c254a88289 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -105,7 +105,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) { fn completes_all_the_things_in_fn_body() { check( r#" -use non_existant::Unresolved; +use non_existent::Unresolved; mod qualified { pub enum Enum { Variant } } impl Unit { @@ -170,7 +170,7 @@ impl Unit { ); check( r#" -use non_existant::Unresolved; +use non_existent::Unresolved; mod qualified { pub enum Enum { Variant } } impl Unit { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 1af16ef857d03..eaa1bebc03c7e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -106,7 +106,7 @@ fn main() { } "#, r#" -use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; +use dep::{some_module::{SecondStruct, ThirdStruct}, FirstStruct}; fn main() { ThirdStruct diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs index 167bdec546d63..f8b76571ca0cd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs @@ -8,6 +8,33 @@ fn check(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } +#[test] +fn use_tree_completion() { + check( + r#" +struct implThing; + +use crate::{impl$0}; +"#, + expect![[r#" + st implThing implThing + kw self + "#]], + ); + + check( + r#" +struct implThing; + +use crate::{impl$0; +"#, + expect![[r#" + st implThing implThing + kw self + "#]], + ); +} + #[test] fn use_tree_start() { cov_mark::check!(unqualified_path_selected_only); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index 0da4e729a8ddd..5780b5a5bb93c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -23,7 +23,7 @@ impl ActiveParameter { let idx = active_parameter?; let mut params = signature.params(sema.db); - if !(idx < params.len()) { + if idx >= params.len() { cov_mark::hit!(too_many_arguments); return None; } @@ -66,19 +66,15 @@ pub fn callable_for_node( } ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call), }?; - let active_param = if let Some(arg_list) = calling_node.arg_list() { - Some( - arg_list - .syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .filter(|t| t.kind() == T![,]) - .take_while(|t| t.text_range().start() <= token.text_range().start()) - .count(), - ) - } else { - None - }; + let active_param = calling_node.arg_list().map(|arg_list| { + arg_list + .syntax() + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .filter(|t| t.kind() == T![,]) + .take_while(|t| t.text_range().start() <= token.text_range().start()) + .count() + }); Some((callable, active_param)) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 259d141404d3f..296253aa1ee19 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -15,12 +15,13 @@ use crate::{symbol_index::SymbolsDatabase, Change, RootDatabase}; impl RootDatabase { pub fn request_cancellation(&mut self) { - let _p = profile::span("RootDatabase::request_cancellation"); + let _p = + tracing::span!(tracing::Level::INFO, "RootDatabase::request_cancellation").entered(); self.salsa_runtime_mut().synthetic_write(Durability::LOW); } pub fn apply_change(&mut self, change: Change) { - let _p = profile::span("RootDatabase::apply_change"); + let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered(); self.request_cancellation(); tracing::trace!("apply_change {:?}", change); if let Some(roots) = &change.source_change.roots { @@ -120,7 +121,7 @@ impl RootDatabase { hir::db::InternImplTraitIdQuery hir::db::InternTypeOrConstParamIdQuery hir::db::InternClosureQuery - hir::db::InternGeneratorQuery + hir::db::InternCoroutineQuery hir::db::AssociatedTyDataQuery hir::db::TraitDatumQuery hir::db::StructDatumQuery @@ -136,15 +137,11 @@ impl RootDatabase { hir::db::FileItemTreeQuery hir::db::CrateDefMapQueryQuery hir::db::BlockDefMapQuery - hir::db::StructDataQuery hir::db::StructDataWithDiagnosticsQuery - hir::db::UnionDataQuery hir::db::UnionDataWithDiagnosticsQuery hir::db::EnumDataQuery - hir::db::EnumDataWithDiagnosticsQuery - hir::db::ImplDataQuery + hir::db::EnumVariantDataWithDiagnosticsQuery hir::db::ImplDataWithDiagnosticsQuery - hir::db::TraitDataQuery hir::db::TraitDataWithDiagnosticsQuery hir::db::TraitAliasDataQuery hir::db::TypeAliasDataQuery @@ -158,9 +155,7 @@ impl RootDatabase { hir::db::BodyQuery hir::db::ExprScopesQuery hir::db::GenericParamsQuery - hir::db::VariantsAttrsQuery hir::db::FieldsAttrsQuery - hir::db::VariantsAttrsSourceMapQuery hir::db::FieldsAttrsSourceMapQuery hir::db::AttrsQuery hir::db::CrateLangItemsQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 8f55f30a2dd46..81f2f87d96236 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -230,23 +230,15 @@ impl Definition { Definition::BuiltinType(it) => it.name().display(db).to_string(), Definition::Local(it) => { let ty = it.ty(db); - let ty = ty.display_truncated(db, None); + let ty_display = ty.display_truncated(db, None); let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let desc = match it.primary_source(db).into_ident_pat() { - Some(ident) => { - let name = it.name(db); - let let_kw = if ident.syntax().parent().map_or(false, |p| { - p.kind() == SyntaxKind::LET_STMT || p.kind() == SyntaxKind::LET_EXPR - }) { - "let " - } else { - "" - }; - format!("{let_kw}{is_mut}{}: {ty}", name.display(db)) - } - None => format!("{is_mut}self: {ty}"), - }; - desc + if it.is_self(db) { + format!("{is_mut}self: {ty_display}") + } else { + let name = it.name(db); + let let_kw = if it.is_param(db) { "" } else { "let " }; + format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db)) + } } Definition::SelfType(impl_def) => { impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))? @@ -412,7 +404,7 @@ impl NameClass { } pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option { - let _p = profile::span("classify_name"); + let _p = tracing::span!(tracing::Level::INFO, "classify_name").entered(); let parent = name.syntax().parent()?; @@ -504,7 +496,7 @@ impl NameClass { sema: &Semantics<'_, RootDatabase>, lifetime: &ast::Lifetime, ) -> Option { - let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string()); + let _p = tracing::span!(tracing::Level::INFO, "classify_lifetime", ?lifetime).entered(); let parent = lifetime.syntax().parent()?; if let Some(it) = ast::LifetimeParam::cast(parent.clone()) { @@ -595,7 +587,7 @@ impl NameRefClass { sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameRef, ) -> Option { - let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string()); + let _p = tracing::span!(tracing::Level::INFO, "classify_name_ref", ?name_ref).entered(); let parent = name_ref.syntax().parent()?; @@ -694,7 +686,7 @@ impl NameRefClass { sema: &Semantics<'_, RootDatabase>, lifetime: &ast::Lifetime, ) -> Option { - let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string()); + let _p = tracing::span!(tracing::Level::INFO, "classify_lifetime_ref", ?lifetime).entered(); let parent = lifetime.syntax().parent()?; match parent.kind() { SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index cc8e8431708ab..72ca354365e7b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -1,4 +1,4 @@ -//! Documentation attribute related utilties. +//! Documentation attribute related utilities. use either::Either; use hir::{ db::{DefDatabase, HirDatabase}, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 1cb6ff8627a23..677c8fd54c058 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -5,6 +5,7 @@ pub struct Lint { pub label: &'static str, pub description: &'static str, } + pub struct LintGroup { pub lint: Lint, pub children: &'static [&'static str], @@ -175,7 +176,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, }, Lint { label: "fuzzy_provenance_casts", @@ -226,10 +227,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "internal_features", description: r##"internal features are not supposed to be used"##, }, - Lint { - label: "invalid_alignment", - description: r##"raw pointers must be aligned before dereferencing"##, - }, Lint { label: "invalid_atomic_ordering", description: r##"usage of invalid atomic ordering in atomic operations and memory fences"##, @@ -745,7 +742,7 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, }, children: &[ "deref_into_dyn_supertrait", @@ -765,7 +762,6 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "illegal_floating_point_literal_pattern", "implied_bounds_entailment", "indirect_structural_match", - "invalid_alignment", "invalid_doc_attributes", "invalid_type_param_default", "late_bound_lifetime_arguments", @@ -960,17 +956,6 @@ The tracking issue for this feature is: [#44839] [#44839]: https://github.com/rust-lang/rust/issues/44839 ------------------------- -"##, - }, - Lint { - label: "abi_amdgpu_kernel", - description: r##"# `abi_amdgpu_kernel` - -The tracking issue for this feature is: [#51575] - -[#51575]: https://github.com/rust-lang/rust/issues/51575 - ------------------------ "##, }, @@ -1367,17 +1352,6 @@ The tracking issue for this feature is: [#44874] [#44874]: https://github.com/rust-lang/rust/issues/44874 ------------------------- -"##, - }, - Lint { - label: "arc_unwrap_or_clone", - description: r##"# `arc_unwrap_or_clone` - -The tracking issue for this feature is: [#93610] - -[#93610]: https://github.com/rust-lang/rust/issues/93610 - ------------------------ "##, }, @@ -1411,17 +1385,6 @@ The tracking issue for this feature is: [#91583] [#91583]: https://github.com/rust-lang/rust/issues/91583 ------------------------- -"##, - }, - Lint { - label: "array_methods", - description: r##"# `array_methods` - -The tracking issue for this feature is: [#76118] - -[#76118]: https://github.com/rust-lang/rust/issues/76118 - ------------------------ "##, }, @@ -1594,7 +1557,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `reg_data` | None | `i8`, `i16`, `i32` | | CSKY | `reg` | None | `i8`, `i16`, `i32` | | CSKY | `freg` | None | `f32`, | -| s390x | `reg` | None | `i8`, `i16`, `i32`, `i64` | +| s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | ## Register aliases @@ -1668,9 +1631,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg64` | None | `rd0` | None | | Hexagon | `reg` | None | `r0` | None | | PowerPC | `reg` | None | `0` | None | -| PowerPC | `reg_nonzero` | None | `3` | `b` | +| PowerPC | `reg_nonzero` | None | `3` | None | | PowerPC | `freg` | None | `0` | None | | s390x | `reg` | None | `%r0` | None | +| s390x | `reg_addr` | None | `%r1` | None | | s390x | `freg` | None | `%f0` | None | | CSKY | `reg` | None | `r0` | None | | CSKY | `freg` | None | `f0` | None | @@ -1757,23 +1721,41 @@ The tracking issue for this feature is: [#62290] "##, }, Lint { - label: "async_fn_in_trait", - description: r##"# `async_fn_in_trait` + label: "async_fn_track_caller", + description: r##"# `async_fn_track_caller` -The tracking issue for this feature is: [#91611] +The tracking issue for this feature is: [#110011] -[#91611]: https://github.com/rust-lang/rust/issues/91611 +[#110011]: https://github.com/rust-lang/rust/issues/110011 ------------------------ "##, }, Lint { - label: "async_fn_track_caller", - description: r##"# `async_fn_track_caller` + label: "async_fn_traits", + description: r##"# `async_fn_traits` -The tracking issue for this feature is: [#110011] +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. -[#110011]: https://github.com/rust-lang/rust/issues/110011 +------------------------ +"##, + }, + Lint { + label: "async_for_loop", + description: r##"# `async_for_loop` + +The tracking issue for this feature is: [#118898] + +[#118898]: https://github.com/rust-lang/rust/issues/118898 + +------------------------ +"##, + }, + Lint { + label: "async_gen_internals", + description: r##"# `async_gen_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------ "##, @@ -1819,17 +1801,6 @@ The tracking issue for this feature is: [#76314] [#76314]: https://github.com/rust-lang/rust/issues/76314 ------------------------- -"##, - }, - Lint { - label: "atomic_from_ptr", - description: r##"# `atomic_from_ptr` - -The tracking issue for this feature is: [#108652] - -[#108652]: https://github.com/rust-lang/rust/issues/108652 - ------------------------ "##, }, @@ -2017,17 +1988,6 @@ The tracking issue for this feature is: [#80996] [#80996]: https://github.com/rust-lang/rust/issues/80996 ------------------------- -"##, - }, - Lint { - label: "bound_map", - description: r##"# `bound_map` - -The tracking issue for this feature is: [#86026] - -[#86026]: https://github.com/rust-lang/rust/issues/86026 - ------------------------ "##, }, @@ -2139,6 +2099,17 @@ The tracking issue for this feature is: [#86423] [#86423]: https://github.com/rust-lang/rust/issues/86423 +------------------------ +"##, + }, + Lint { + label: "bufread_skip_until", + description: r##"# `bufread_skip_until` + +The tracking issue for this feature is: [#111735] + +[#111735]: https://github.com/rust-lang/rust/issues/111735 + ------------------------ "##, }, @@ -2172,17 +2143,6 @@ The tracking issue for this feature is: [#88345] [#88345]: https://github.com/rust-lang/rust/issues/88345 ------------------------- -"##, - }, - Lint { - label: "c_str_literals", - description: r##"# `c_str_literals` - -The tracking issue for this feature is: [#105723] - -[#105723]: https://github.com/rust-lang/rust/issues/105723 - ------------------------ "##, }, @@ -2407,6 +2367,17 @@ fn b() { } } ``` +"##, + }, + Lint { + label: "cfg_sanitizer_cfi", + description: r##"# `cfg_sanitizer_cfi` + +The tracking issue for this feature is: [#89653] + +[#89653]: https://github.com/rust-lang/rust/issues/89653 + +------------------------ "##, }, Lint { @@ -2584,8 +2555,8 @@ The tracking issue for this feature is: [#87417] ------------------------ -Allows using the `#[track_caller]` attribute on closures and generators. -Calls made to the closure or generator will have caller information +Allows using the `#[track_caller]` attribute on closures and coroutines. +Calls made to the closure or coroutine will have caller information available through `std::panic::Location::caller()`, just like using `#[track_caller]` on a function. "##, @@ -2843,43 +2814,45 @@ The tracking issue for this feature is: [#91583] "##, }, Lint { - label: "const_assert_type2", - description: r##"# `const_assert_type2` + label: "const_async_blocks", + description: r##"# `const_async_blocks` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#85368] + +[#85368]: https://github.com/rust-lang/rust/issues/85368 ------------------------ "##, }, Lint { - label: "const_assume", - description: r##"# `const_assume` + label: "const_atomic_from_ptr", + description: r##"# `const_atomic_from_ptr` -The tracking issue for this feature is: [#76972] +The tracking issue for this feature is: [#108652] -[#76972]: https://github.com/rust-lang/rust/issues/76972 +[#108652]: https://github.com/rust-lang/rust/issues/108652 ------------------------ "##, }, Lint { - label: "const_async_blocks", - description: r##"# `const_async_blocks` + label: "const_bigint_helper_methods", + description: r##"# `const_bigint_helper_methods` -The tracking issue for this feature is: [#85368] +The tracking issue for this feature is: [#85532] -[#85368]: https://github.com/rust-lang/rust/issues/85368 +[#85532]: https://github.com/rust-lang/rust/issues/85532 ------------------------ "##, }, Lint { - label: "const_bigint_helper_methods", - description: r##"# `const_bigint_helper_methods` + label: "const_binary_heap_constructor", + description: r##"# `const_binary_heap_constructor` -The tracking issue for this feature is: [#85532] +The tracking issue for this feature is: [#112353] -[#85532]: https://github.com/rust-lang/rust/issues/85532 +[#112353]: https://github.com/rust-lang/rust/issues/112353 ------------------------ "##, @@ -2954,6 +2927,17 @@ The tracking issue for this feature is: [#106003] [#106003]: https://github.com/rust-lang/rust/issues/106003 +------------------------ +"##, + }, + Lint { + label: "const_cmp", + description: r##"# `const_cmp` + +The tracking issue for this feature is: [#92391] + +[#92391]: https://github.com/rust-lang/rust/issues/92391 + ------------------------ "##, }, @@ -2987,17 +2971,6 @@ The tracking issue for this feature is: [#113219] [#113219]: https://github.com/rust-lang/rust/issues/113219 ------------------------- -"##, - }, - Lint { - label: "const_discriminant", - description: r##"# `const_discriminant` - -The tracking issue for this feature is: [#69821] - -[#69821]: https://github.com/rust-lang/rust/issues/69821 - ------------------------ "##, }, @@ -3115,21 +3088,21 @@ The tracking issue for this feature is: [#79597] "##, }, Lint { - label: "const_index_range_slice_index", - description: r##"# `const_index_range_slice_index` + label: "const_hint_assert_unchecked", + description: r##"# `const_hint_assert_unchecked` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#119131] + +[#119131]: https://github.com/rust-lang/rust/issues/119131 ------------------------ "##, }, Lint { - label: "const_inherent_unchecked_arith", - description: r##"# `const_inherent_unchecked_arith` - -The tracking issue for this feature is: [#85122] + label: "const_index_range_slice_index", + description: r##"# `const_index_range_slice_index` -[#85122]: https://github.com/rust-lang/rust/issues/85122 +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------ "##, @@ -3273,17 +3246,6 @@ The tracking issue for this feature is: [#75251] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------- -"##, - }, - Lint { - label: "const_maybe_uninit_assume_init_read", - description: r##"# `const_maybe_uninit_assume_init_read` - -The tracking issue for this feature is: [#63567] - -[#63567]: https://github.com/rust-lang/rust/issues/63567 - ------------------------ "##, }, @@ -3306,17 +3268,6 @@ The tracking issue for this feature is: [#63567] [#63567]: https://github.com/rust-lang/rust/issues/63567 ------------------------- -"##, - }, - Lint { - label: "const_maybe_uninit_zeroed", - description: r##"# `const_maybe_uninit_zeroed` - -The tracking issue for this feature is: [#91850] - -[#91850]: https://github.com/rust-lang/rust/issues/91850 - ------------------------ "##, }, @@ -3383,17 +3334,6 @@ The tracking issue for this feature is: [#76654] [#76654]: https://github.com/rust-lang/rust/issues/76654 ------------------------- -"##, - }, - Lint { - label: "const_pointer_byte_offsets", - description: r##"# `const_pointer_byte_offsets` - -The tracking issue for this feature is: [#96283] - -[#96283]: https://github.com/rust-lang/rust/issues/96283 - ------------------------ "##, }, @@ -3559,6 +3499,17 @@ The tracking issue for this feature is: [#83570] [#83570]: https://github.com/rust-lang/rust/issues/83570 +------------------------ +"##, + }, + Lint { + label: "const_slice_first_last_chunk", + description: r##"# `const_slice_first_last_chunk` + +The tracking issue for this feature is: [#111774] + +[#111774]: https://github.com/rust-lang/rust/issues/111774 + ------------------------ "##, }, @@ -3634,6 +3585,17 @@ The tracking issue for this feature is: [#101804] [#101804]: https://github.com/rust-lang/rust/issues/101804 +------------------------ +"##, + }, + Lint { + label: "const_str_from_raw_parts_mut", + description: r##"# `const_str_from_raw_parts_mut` + +The tracking issue for this feature is: [#119206] + +[#119206]: https://github.com/rust-lang/rust/issues/119206 + ------------------------ "##, }, @@ -3656,6 +3618,17 @@ The tracking issue for this feature is: [#91005] [#91005]: https://github.com/rust-lang/rust/issues/91005 +------------------------ +"##, + }, + Lint { + label: "const_strict_overflow_ops", + description: r##"# `const_strict_overflow_ops` + +The tracking issue for this feature is: [#118260] + +[#118260]: https://github.com/rust-lang/rust/issues/118260 + ------------------------ "##, }, @@ -3788,10 +3761,12 @@ This feature is internal to the Rust compiler and is not intended for general us "##, }, Lint { - label: "core_panic", - description: r##"# `core_panic` + label: "core_io_borrowed_buf", + description: r##"# `core_io_borrowed_buf` -This feature is internal to the Rust compiler and is not intended for general use. +The tracking issue for this feature is: [#117693] + +[#117693]: https://github.com/rust-lang/rust/issues/117693 ------------------------ "##, @@ -3815,88 +3790,360 @@ This feature is internal to the Rust compiler and is not intended for general us "##, }, Lint { - label: "coverage_attribute", - description: r##"# `coverage_attribute` - -The tracking issue for this feature is: [#84605] - -[#84605]: https://github.com/rust-lang/rust/issues/84605 - ---- - -The `coverage` attribute can be used to selectively disable coverage -instrumentation in an annotated function. This might be useful to: - -- Avoid instrumentation overhead in a performance critical function -- Avoid generating coverage for a function that is not meant to be executed, - but still target 100% coverage for the rest of the program. - -## Example + label: "coroutine_clone", + description: r##"# `coroutine_clone` -```rust -#![feature(coverage_attribute)] +The tracking issue for this feature is: [#95360] -// `foo()` will get coverage instrumentation (by default) -fn foo() { - // ... -} +[#95360]: https://github.com/rust-lang/rust/issues/95360 -#[coverage(off)] -fn bar() { - // ... -} -``` +------------------------ "##, }, Lint { - label: "cow_is_borrowed", - description: r##"# `cow_is_borrowed` + label: "coroutine_trait", + description: r##"# `coroutine_trait` -The tracking issue for this feature is: [#65143] +The tracking issue for this feature is: [#43122] -[#65143]: https://github.com/rust-lang/rust/issues/65143 +[#43122]: https://github.com/rust-lang/rust/issues/43122 ------------------------ "##, }, Lint { - label: "csky_target_feature", - description: r##"# `csky_target_feature` + label: "coroutines", + description: r##"# `coroutines` -The tracking issue for this feature is: [#44839] +The tracking issue for this feature is: [#43122] -[#44839]: https://github.com/rust-lang/rust/issues/44839 +[#43122]: https://github.com/rust-lang/rust/issues/43122 ------------------------ -"##, - }, - Lint { - label: "cstr_count_bytes", - description: r##"# `cstr_count_bytes` -The tracking issue for this feature is: [#114441] +The `coroutines` feature gate in Rust allows you to define coroutine or +coroutine literals. A coroutine is a "resumable function" that syntactically +resembles a closure but compiles to much different semantics in the compiler +itself. The primary feature of a coroutine is that it can be suspended during +execution to be resumed at a later date. Coroutines use the `yield` keyword to +"return", and then the caller can `resume` a coroutine to resume execution just +after the `yield` keyword. -[#114441]: https://github.com/rust-lang/rust/issues/114441 +Coroutines are an extra-unstable feature in the compiler right now. Added in +[RFC 2033] they're mostly intended right now as a information/constraint +gathering phase. The intent is that experimentation can happen on the nightly +compiler before actual stabilization. A further RFC will be required to +stabilize coroutines and will likely contain at least a few small +tweaks to the overall design. ------------------------- -"##, - }, - Lint { - label: "cursor_remaining", - description: r##"# `cursor_remaining` +[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 -The tracking issue for this feature is: [#86369] +A syntactical example of a coroutine is: -[#86369]: https://github.com/rust-lang/rust/issues/86369 +```rust +#![feature(coroutines, coroutine_trait)] ------------------------- -"##, - }, - Lint { - label: "custom_code_classes_in_docs", - description: r##"# `custom_code_classes_in_docs` +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; -The tracking issue for this feature is: [#79483] +fn main() { + let mut coroutine = || { + yield 1; + return "foo" + }; + + match Pin::new(&mut coroutine).resume(()) { + CoroutineState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut coroutine).resume(()) { + CoroutineState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } +} +``` + +Coroutines are closure-like literals which can contain a `yield` statement. The +`yield` statement takes an optional expression of a value to yield out of the +coroutine. All coroutine literals implement the `Coroutine` trait in the +`std::ops` module. The `Coroutine` trait has one main method, `resume`, which +resumes execution of the coroutine at the previous suspension point. + +An example of the control flow of coroutines is that the following example +prints all numbers in order: + +```rust +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn main() { + let mut coroutine = || { + println!("2"); + yield; + println!("4"); + }; + + println!("1"); + Pin::new(&mut coroutine).resume(()); + println!("3"); + Pin::new(&mut coroutine).resume(()); + println!("5"); +} +``` + +At this time the main intended use case of coroutines is an implementation +primitive for async/await syntax, but coroutines will likely be extended to +ergonomic implementations of iterators and other primitives in the future. +Feedback on the design and usage is always appreciated! + +### The `Coroutine` trait + +The `Coroutine` trait in `std::ops` currently looks like: + +```rust +# #![feature(arbitrary_self_types, coroutine_trait)] +# use std::ops::CoroutineState; +# use std::pin::Pin; + +pub trait Coroutine { + type Yield; + type Return; + fn resume(self: Pin<&mut Self>, resume: R) -> CoroutineState; +} +``` + +The `Coroutine::Yield` type is the type of values that can be yielded with the +`yield` statement. The `Coroutine::Return` type is the returned type of the +coroutine. This is typically the last expression in a coroutine's definition or +any value passed to `return` in a coroutine. The `resume` function is the entry +point for executing the `Coroutine` itself. + +The return value of `resume`, `CoroutineState`, looks like: + +```rust +pub enum CoroutineState { + Yielded(Y), + Complete(R), +} +``` + +The `Yielded` variant indicates that the coroutine can later be resumed. This +corresponds to a `yield` point in a coroutine. The `Complete` variant indicates +that the coroutine is complete and cannot be resumed again. Calling `resume` +after a coroutine has returned `Complete` will likely result in a panic of the +program. + +### Closure-like semantics + +The closure-like syntax for coroutines alludes to the fact that they also have +closure-like semantics. Namely: + +* When created, a coroutine executes no code. A closure literal does not + actually execute any of the closure's code on construction, and similarly a + coroutine literal does not execute any code inside the coroutine when + constructed. + +* Coroutines can capture outer variables by reference or by move, and this can + be tweaked with the `move` keyword at the beginning of the closure. Like + closures all coroutines will have an implicit environment which is inferred by + the compiler. Outer variables can be moved into a coroutine for use as the + coroutine progresses. + +* Coroutine literals produce a value with a unique type which implements the + `std::ops::Coroutine` trait. This allows actual execution of the coroutine + through the `Coroutine::resume` method as well as also naming it in return + types and such. + +* Traits like `Send` and `Sync` are automatically implemented for a `Coroutine` + depending on the captured variables of the environment. Unlike closures, + coroutines also depend on variables live across suspension points. This means + that although the ambient environment may be `Send` or `Sync`, the coroutine + itself may not be due to internal variables live across `yield` points being + not-`Send` or not-`Sync`. Note that coroutines do + not implement traits like `Copy` or `Clone` automatically. + +* Whenever a coroutine is dropped it will drop all captured environment + variables. + +### Coroutines as state machines + +In the compiler, coroutines are currently compiled as state machines. Each +`yield` expression will correspond to a different state that stores all live +variables over that suspension point. Resumption of a coroutine will dispatch on +the current state and then execute internally until a `yield` is reached, at +which point all state is saved off in the coroutine and a value is returned. + +Let's take a look at an example to see what's going on here: + +```rust +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn main() { + let ret = "foo"; + let mut coroutine = move || { + yield 1; + return ret + }; + + Pin::new(&mut coroutine).resume(()); + Pin::new(&mut coroutine).resume(()); +} +``` + +This coroutine literal will compile down to something similar to: + +```rust +#![feature(arbitrary_self_types, coroutines, coroutine_trait)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; + +fn main() { + let ret = "foo"; + let mut coroutine = { + enum __Coroutine { + Start(&'static str), + Yield1(&'static str), + Done, + } + + impl Coroutine for __Coroutine { + type Yield = i32; + type Return = &'static str; + + fn resume(mut self: Pin<&mut Self>, resume: ()) -> CoroutineState { + use std::mem; + match mem::replace(&mut *self, __Coroutine::Done) { + __Coroutine::Start(s) => { + *self = __Coroutine::Yield1(s); + CoroutineState::Yielded(1) + } + + __Coroutine::Yield1(s) => { + *self = __Coroutine::Done; + CoroutineState::Complete(s) + } + + __Coroutine::Done => { + panic!("coroutine resumed after completion") + } + } + } + } + + __Coroutine::Start(ret) + }; + + Pin::new(&mut coroutine).resume(()); + Pin::new(&mut coroutine).resume(()); +} +``` + +Notably here we can see that the compiler is generating a fresh type, +`__Coroutine` in this case. This type has a number of states (represented here +as an `enum`) corresponding to each of the conceptual states of the coroutine. +At the beginning we're closing over our outer variable `foo` and then that +variable is also live over the `yield` point, so it's stored in both states. + +When the coroutine starts it'll immediately yield 1, but it saves off its state +just before it does so indicating that it has reached the yield point. Upon +resuming again we'll execute the `return ret` which returns the `Complete` +state. + +Here we can also note that the `Done` state, if resumed, panics immediately as +it's invalid to resume a completed coroutine. It's also worth noting that this +is just a rough desugaring, not a normative specification for what the compiler +does. +"##, + }, + Lint { + label: "coverage_attribute", + description: r##"# `coverage_attribute` + +The tracking issue for this feature is: [#84605] + +[#84605]: https://github.com/rust-lang/rust/issues/84605 + +--- + +The `coverage` attribute can be used to selectively disable coverage +instrumentation in an annotated function. This might be useful to: + +- Avoid instrumentation overhead in a performance critical function +- Avoid generating coverage for a function that is not meant to be executed, + but still target 100% coverage for the rest of the program. + +## Example + +```rust +#![feature(coverage_attribute)] + +// `foo()` will get coverage instrumentation (by default) +fn foo() { + // ... +} + +#[coverage(off)] +fn bar() { + // ... +} +``` +"##, + }, + Lint { + label: "cow_is_borrowed", + description: r##"# `cow_is_borrowed` + +The tracking issue for this feature is: [#65143] + +[#65143]: https://github.com/rust-lang/rust/issues/65143 + +------------------------ +"##, + }, + Lint { + label: "csky_target_feature", + description: r##"# `csky_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "cstr_count_bytes", + description: r##"# `cstr_count_bytes` + +The tracking issue for this feature is: [#114441] + +[#114441]: https://github.com/rust-lang/rust/issues/114441 + +------------------------ +"##, + }, + Lint { + label: "cursor_remaining", + description: r##"# `cursor_remaining` + +The tracking issue for this feature is: [#86369] + +[#86369]: https://github.com/rust-lang/rust/issues/86369 + +------------------------ +"##, + }, + Lint { + label: "custom_code_classes_in_docs", + description: r##"# `custom_code_classes_in_docs` + +The tracking issue for this feature is: [#79483] [#79483]: https://github.com/rust-lang/rust/issues/79483 @@ -3967,6 +4214,17 @@ The tracking issue for this feature is: [#46316] [#46316]: https://github.com/rust-lang/rust/issues/46316 +------------------------ +"##, + }, + Lint { + label: "debug_closure_helpers", + description: r##"# `debug_closure_helpers` + +The tracking issue for this feature is: [#117729] + +[#117729]: https://github.com/rust-lang/rust/issues/117729 + ------------------------ "##, }, @@ -4059,6 +4317,83 @@ The tracking issue for this feature is: [#111996] [#111996]: https://github.com/rust-lang/rust/issues/111996 ------------------------ + +The `diagnostic_namespace` feature permits customization of compilation errors. + +## diagnostic::on_unimplemented + +With [#114452] support for `diagnostic::on_unimplemented` was added. + +When used on a trait declaration, the following options are available: + +* `message` to customize the primary error message +* `note` to add a customized note message to an error message +* `label` to customize the label part of the error message + +The attribute will hint to the compiler to use these in error messages: +```rust +// some library +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + message = "cannot insert element", + label = "cannot be put into a table", + note = "see for more information about the Table api" +)] +pub trait Element { + // ... +} +``` + +```rust,compile_fail,E0277 +# #![feature(diagnostic_namespace)] +# +# #[diagnostic::on_unimplemented( +# message = "cannot insert element", +# label = "cannot be put into a table", +# note = "see for more information about the Table api" +# )] +# pub trait Element { +# // ... +# } +# struct Table; +# impl Table { +# fn insert(&self, element: T) { +# // .. +# } +# } +# fn main() { +# let table = Table; +# let element = (); +// user code +table.insert(element); +# } +``` + +```text +error[E0277]: cannot insert element + --> src/main.rs:24:18 + | +24 | table.insert(element); + | ------ ^^^^^^^ cannot be put into a table + | | + | required by a bound introduced by this call + | + = help: the trait `Element` is not implemented for `` + = note: see for more information about the Table api +note: required by a bound in `Table::insert` + --> src/main.rs:15:18 + | +15 | fn insert(&self, element: T) { + | ^^^^^^^ required by this bound in `Table::insert` + +For more information about this error, try `rustc --explain E0277`. +``` + +See [RFC 3368] for more information. + +[#114452]: https://github.com/rust-lang/rust/pull/114452 +[RFC 3368]: https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md "##, }, Lint { @@ -4279,6 +4614,17 @@ The tracking issue for this feature is: [#34761] [#34761]: https://github.com/rust-lang/rust/issues/34761 +------------------------ +"##, + }, + Lint { + label: "duration_abs_diff", + description: r##"# `duration_abs_diff` + +The tracking issue for this feature is: [#117618] + +[#117618]: https://github.com/rust-lang/rust/issues/117618 + ------------------------ "##, }, @@ -4505,6 +4851,17 @@ The tracking issue for this feature is: [#112788] [#112788]: https://github.com/rust-lang/rust/issues/112788 +------------------------ +"##, + }, + Lint { + label: "exposed_provenance", + description: r##"# `exposed_provenance` + +The tracking issue for this feature is: [#95228] + +[#95228]: https://github.com/rust-lang/rust/issues/95228 + ------------------------ "##, }, @@ -4697,28 +5054,6 @@ The tracking issue for this feature is: [#58314] [#58314]: https://github.com/rust-lang/rust/issues/58314 ------------------------- -"##, - }, - Lint { - label: "file_create_new", - description: r##"# `file_create_new` - -The tracking issue for this feature is: [#105135] - -[#105135]: https://github.com/rust-lang/rust/issues/105135 - ------------------------- -"##, - }, - Lint { - label: "file_set_times", - description: r##"# `file_set_times` - -The tracking issue for this feature is: [#98245] - -[#98245]: https://github.com/rust-lang/rust/issues/98245 - ------------------------ "##, }, @@ -4790,6 +5125,17 @@ The tracking issue for this feature is: [#82232] [#82232]: https://github.com/rust-lang/rust/issues/82232 +------------------------ +"##, + }, + Lint { + label: "fn_delegation", + description: r##"# `fn_delegation` + +The tracking issue for this feature is: [#118212] + +[#118212]: https://github.com/rust-lang/rust/issues/118212 + ------------------------ "##, }, @@ -4860,319 +5206,58 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "fs_try_exists", - description: r##"# `fs_try_exists` - -The tracking issue for this feature is: [#83186] - -[#83186]: https://github.com/rust-lang/rust/issues/83186 - ------------------------- -"##, - }, - Lint { - label: "fundamental", - description: r##"# `fundamental` - -The tracking issue for this feature is: [#29635] - -[#29635]: https://github.com/rust-lang/rust/issues/29635 - ------------------------- -"##, - }, - Lint { - label: "future_join", - description: r##"# `future_join` - -The tracking issue for this feature is: [#91642] - -[#91642]: https://github.com/rust-lang/rust/issues/91642 - ------------------------- -"##, - }, - Lint { - label: "gen_future", - description: r##"# `gen_future` - -The tracking issue for this feature is: [#50547] - -[#50547]: https://github.com/rust-lang/rust/issues/50547 - ------------------------- -"##, - }, - Lint { - label: "generator_clone", - description: r##"# `generator_clone` - -The tracking issue for this feature is: [#95360] - -[#95360]: https://github.com/rust-lang/rust/issues/95360 - ------------------------- -"##, - }, - Lint { - label: "generator_trait", - description: r##"# `generator_trait` - -The tracking issue for this feature is: [#43122] - -[#43122]: https://github.com/rust-lang/rust/issues/43122 - ------------------------- -"##, - }, - Lint { - label: "generators", - description: r##"# `generators` - -The tracking issue for this feature is: [#43122] - -[#43122]: https://github.com/rust-lang/rust/issues/43122 - ------------------------- - -The `generators` feature gate in Rust allows you to define generator or -coroutine literals. A generator is a "resumable function" that syntactically -resembles a closure but compiles to much different semantics in the compiler -itself. The primary feature of a generator is that it can be suspended during -execution to be resumed at a later date. Generators use the `yield` keyword to -"return", and then the caller can `resume` a generator to resume execution just -after the `yield` keyword. - -Generators are an extra-unstable feature in the compiler right now. Added in -[RFC 2033] they're mostly intended right now as a information/constraint -gathering phase. The intent is that experimentation can happen on the nightly -compiler before actual stabilization. A further RFC will be required to -stabilize generators/coroutines and will likely contain at least a few small -tweaks to the overall design. - -[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 - -A syntactical example of a generator is: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let mut generator = || { - yield 1; - return "foo" - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1) => {} - _ => panic!("unexpected value from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Complete("foo") => {} - _ => panic!("unexpected value from resume"), - } -} -``` - -Generators are closure-like literals which can contain a `yield` statement. The -`yield` statement takes an optional expression of a value to yield out of the -generator. All generator literals implement the `Generator` trait in the -`std::ops` module. The `Generator` trait has one main method, `resume`, which -resumes execution of the generator at the previous suspension point. - -An example of the control flow of generators is that the following example -prints all numbers in order: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let mut generator = || { - println!("2"); - yield; - println!("4"); - }; - - println!("1"); - Pin::new(&mut generator).resume(()); - println!("3"); - Pin::new(&mut generator).resume(()); - println!("5"); -} -``` - -At this time the main intended use case of generators is an implementation -primitive for async/await syntax, but generators will likely be extended to -ergonomic implementations of iterators and other primitives in the future. -Feedback on the design and usage is always appreciated! - -### The `Generator` trait - -The `Generator` trait in `std::ops` currently looks like: - -```rust -# #![feature(arbitrary_self_types, generator_trait)] -# use std::ops::GeneratorState; -# use std::pin::Pin; - -pub trait Generator { - type Yield; - type Return; - fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState; -} -``` - -The `Generator::Yield` type is the type of values that can be yielded with the -`yield` statement. The `Generator::Return` type is the returned type of the -generator. This is typically the last expression in a generator's definition or -any value passed to `return` in a generator. The `resume` function is the entry -point for executing the `Generator` itself. - -The return value of `resume`, `GeneratorState`, looks like: - -```rust -pub enum GeneratorState { - Yielded(Y), - Complete(R), -} -``` - -The `Yielded` variant indicates that the generator can later be resumed. This -corresponds to a `yield` point in a generator. The `Complete` variant indicates -that the generator is complete and cannot be resumed again. Calling `resume` -after a generator has returned `Complete` will likely result in a panic of the -program. - -### Closure-like semantics - -The closure-like syntax for generators alludes to the fact that they also have -closure-like semantics. Namely: - -* When created, a generator executes no code. A closure literal does not - actually execute any of the closure's code on construction, and similarly a - generator literal does not execute any code inside the generator when - constructed. - -* Generators can capture outer variables by reference or by move, and this can - be tweaked with the `move` keyword at the beginning of the closure. Like - closures all generators will have an implicit environment which is inferred by - the compiler. Outer variables can be moved into a generator for use as the - generator progresses. - -* Generator literals produce a value with a unique type which implements the - `std::ops::Generator` trait. This allows actual execution of the generator - through the `Generator::resume` method as well as also naming it in return - types and such. - -* Traits like `Send` and `Sync` are automatically implemented for a `Generator` - depending on the captured variables of the environment. Unlike closures, - generators also depend on variables live across suspension points. This means - that although the ambient environment may be `Send` or `Sync`, the generator - itself may not be due to internal variables live across `yield` points being - not-`Send` or not-`Sync`. Note that generators do - not implement traits like `Copy` or `Clone` automatically. - -* Whenever a generator is dropped it will drop all captured environment - variables. - -### Generators as state machines - -In the compiler, generators are currently compiled as state machines. Each -`yield` expression will correspond to a different state that stores all live -variables over that suspension point. Resumption of a generator will dispatch on -the current state and then execute internally until a `yield` is reached, at -which point all state is saved off in the generator and a value is returned. - -Let's take a look at an example to see what's going on here: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = move || { - yield 1; - return ret - }; + label: "fs_try_exists", + description: r##"# `fs_try_exists` - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` +The tracking issue for this feature is: [#83186] -This generator literal will compile down to something similar to: +[#83186]: https://github.com/rust-lang/rust/issues/83186 -```rust -#![feature(arbitrary_self_types, generators, generator_trait)] +------------------------ +"##, + }, + Lint { + label: "fundamental", + description: r##"# `fundamental` -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; +The tracking issue for this feature is: [#29635] -fn main() { - let ret = "foo"; - let mut generator = { - enum __Generator { - Start(&'static str), - Yield1(&'static str), - Done, - } +[#29635]: https://github.com/rust-lang/rust/issues/29635 - impl Generator for __Generator { - type Yield = i32; - type Return = &'static str; +------------------------ +"##, + }, + Lint { + label: "future_join", + description: r##"# `future_join` - fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState { - use std::mem; - match mem::replace(&mut *self, __Generator::Done) { - __Generator::Start(s) => { - *self = __Generator::Yield1(s); - GeneratorState::Yielded(1) - } +The tracking issue for this feature is: [#91642] - __Generator::Yield1(s) => { - *self = __Generator::Done; - GeneratorState::Complete(s) - } +[#91642]: https://github.com/rust-lang/rust/issues/91642 - __Generator::Done => { - panic!("generator resumed after completion") - } - } - } - } +------------------------ +"##, + }, + Lint { + label: "gen_blocks", + description: r##"# `gen_blocks` - __Generator::Start(ret) - }; +The tracking issue for this feature is: [#117078] - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` +[#117078]: https://github.com/rust-lang/rust/issues/117078 -Notably here we can see that the compiler is generating a fresh type, -`__Generator` in this case. This type has a number of states (represented here -as an `enum`) corresponding to each of the conceptual states of the generator. -At the beginning we're closing over our outer variable `foo` and then that -variable is also live over the `yield` point, so it's stored in both states. +------------------------ +"##, + }, + Lint { + label: "gen_future", + description: r##"# `gen_future` -When the generator starts it'll immediately yield 1, but it saves off its state -just before it does so indicating that it has reached the yield point. Upon -resuming again we'll execute the `return ret` which returns the `Complete` -state. +The tracking issue for this feature is: [#50547] -Here we can also note that the `Done` state, if resumed, panics immediately as -it's invalid to resume a completed generator. It's also worth noting that this -is just a rough desugaring, not a normative specification for what the compiler -does. +[#50547]: https://github.com/rust-lang/rust/issues/50547 + +------------------------ "##, }, Lint { @@ -5236,6 +5321,17 @@ The tracking issue for this feature is: [#113521] [#113521]: https://github.com/rust-lang/rust/issues/113521 +------------------------ +"##, + }, + Lint { + label: "generic_nonzero", + description: r##"# `generic_nonzero` + +The tracking issue for this feature is: [#120257] + +[#120257]: https://github.com/rust-lang/rust/issues/120257 + ------------------------ "##, }, @@ -5356,6 +5452,17 @@ The tracking issue for this feature is: [#44839] [#44839]: https://github.com/rust-lang/rust/issues/44839 +------------------------ +"##, + }, + Lint { + label: "hint_assert_unchecked", + description: r##"# `hint_assert_unchecked` + +The tracking issue for this feature is: [#119131] + +[#119131]: https://github.com/rust-lang/rust/issues/119131 + ------------------------ "##, }, @@ -5652,17 +5759,6 @@ The tracking issue for this feature is: [#113744] [#113744]: https://github.com/rust-lang/rust/issues/113744 ------------------------- -"##, - }, - Lint { - label: "ip_in_core", - description: r##"# `ip_in_core` - -The tracking issue for this feature is: [#108443] - -[#108443]: https://github.com/rust-lang/rust/issues/108443 - ------------------------ "##, }, @@ -5690,6 +5786,15 @@ The tracking issue for this feature is: [#53485] Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`; add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `Iterator`. +"##, + }, + Lint { + label: "is_val_statically_known", + description: r##"# `is_val_statically_known` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ "##, }, Lint { @@ -5737,8 +5842,8 @@ The tracking issue for this feature is: [#94780] "##, }, Lint { - label: "iter_from_generator", - description: r##"# `iter_from_generator` + label: "iter_from_coroutine", + description: r##"# `iter_from_coroutine` The tracking issue for this feature is: [#43122] @@ -6047,6 +6152,40 @@ This feature has no tracking issue, and is therefore likely internal to the comp This feature is internal to the Rust compiler and is not intended for general use. ------------------------ +"##, + }, + Lint { + label: "lifetime_capture_rules_2024", + description: r##"# `lifetime_capture_rules_2024` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "link_arg_attribute", + description: r##"# `link_arg_attribute` + +The tracking issue for this feature is: [#99427] + +------ + +The `link_arg_attribute` feature allows passing arguments into the linker +from inside of the source code. Order is preserved for link attributes as +they were defined on a single extern block: + +```rust,no_run +#![feature(link_arg_attribute)] + +#[link(kind = "link-arg", name = "--start-group")] +#[link(kind = "static", name = "c")] +#[link(kind = "static", name = "gcc")] +#[link(kind = "link-arg", name = "--end-group")] +extern "C" {} +``` + +[#99427]: https://github.com/rust-lang/rust/issues/99427 "##, }, Lint { @@ -6099,6 +6238,17 @@ The tracking issue for this feature is: [#69210] [#69210]: https://github.com/rust-lang/rust/issues/69210 +------------------------ +"##, + }, + Lint { + label: "linked_list_retain", + description: r##"# `linked_list_retain` + +The tracking issue for this feature is: [#114135] + +[#114135]: https://github.com/rust-lang/rust/issues/114135 + ------------------------ "##, }, @@ -6132,6 +6282,17 @@ The tracking issue for this feature is: [#29598] [#29598]: https://github.com/rust-lang/rust/issues/29598 +------------------------ +"##, + }, + Lint { + label: "loongarch_target_feature", + description: r##"# `loongarch_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + ------------------------ "##, }, @@ -6292,6 +6453,17 @@ The tracking issue for this feature is: [#98262] [#98262]: https://github.com/rust-lang/rust/issues/98262 +------------------------ +"##, + }, + Lint { + label: "min_exhaustive_patterns", + description: r##"# `min_exhaustive_patterns` + +The tracking issue for this feature is: [#119612] + +[#119612]: https://github.com/rust-lang/rust/issues/119612 + ------------------------ "##, }, @@ -6389,17 +6561,6 @@ The tracking issue for this feature is: [#81872] [#81872]: https://github.com/rust-lang/rust/issues/81872 ------------------------- -"##, - }, - Lint { - label: "mutex_unpoison", - description: r##"# `mutex_unpoison` - -The tracking issue for this feature is: [#96469] - -[#96469]: https://github.com/rust-lang/rust/issues/96469 - ------------------------ "##, }, @@ -6407,9 +6568,9 @@ The tracking issue for this feature is: [#96469] label: "naked_functions", description: r##"# `naked_functions` -The tracking issue for this feature is: [#32408] +The tracking issue for this feature is: [#90957] -[#32408]: https://github.com/rust-lang/rust/issues/32408 +[#90957]: https://github.com/rust-lang/rust/issues/90957 ------------------------ "##, @@ -6515,6 +6676,17 @@ This serves two purposes: * For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists. * It prevents downstream crates from creating such impls. +"##, + }, + Lint { + label: "never_patterns", + description: r##"# `never_patterns` + +The tracking issue for this feature is: [#118155] + +[#118155]: https://github.com/rust-lang/rust/issues/118155 + +------------------------ "##, }, Lint { @@ -6613,6 +6785,48 @@ The tracking issue for this feature is: [#108185] [#108185]: https://github.com/rust-lang/rust/issues/108185 +------------------------ +"##, + }, + Lint { + label: "non_null_convenience", + description: r##"# `non_null_convenience` + +The tracking issue for this feature is: [#117691] + +[#117691]: https://github.com/rust-lang/rust/issues/117691 + +------------------------ +"##, + }, + Lint { + label: "non_zero_count_ones", + description: r##"# `non_zero_count_ones` + +The tracking issue for this feature is: [#120287] + +[#120287]: https://github.com/rust-lang/rust/issues/120287 + +------------------------ +"##, + }, + Lint { + label: "nonzero_from_mut", + description: r##"# `nonzero_from_mut` + +The tracking issue for this feature is: [#106290] + +[#106290]: https://github.com/rust-lang/rust/issues/106290 + +------------------------ +"##, + }, + Lint { + label: "nonzero_internals", + description: r##"# `nonzero_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -6670,12 +6884,23 @@ The tracking issue for this feature is: [#43561] "##, }, Lint { - label: "offset_of", - description: r##"# `offset_of` + label: "offset_of_enum", + description: r##"# `offset_of_enum` + +The tracking issue for this feature is: [#120141] + +[#120141]: https://github.com/rust-lang/rust/issues/120141 + +------------------------ +"##, + }, + Lint { + label: "offset_of_nested", + description: r##"# `offset_of_nested` -The tracking issue for this feature is: [#106655] +The tracking issue for this feature is: [#120140] -[#106655]: https://github.com/rust-lang/rust/issues/106655 +[#120140]: https://github.com/rust-lang/rust/issues/120140 ------------------------ "##, @@ -6697,6 +6922,17 @@ The tracking issue for this feature is: [#109737] [#109737]: https://github.com/rust-lang/rust/issues/109737 +------------------------ +"##, + }, + Lint { + label: "once_cell_try_insert", + description: r##"# `once_cell_try_insert` + +The tracking issue for this feature is: [#116693] + +[#116693]: https://github.com/rust-lang/rust/issues/116693 + ------------------------ "##, }, @@ -6752,6 +6988,17 @@ The tracking issue for this feature is: [#70086] [#70086]: https://github.com/rust-lang/rust/issues/70086 +------------------------ +"##, + }, + Lint { + label: "os_str_slice", + description: r##"# `os_str_slice` + +The tracking issue for this feature is: [#118485] + +[#118485]: https://github.com/rust-lang/rust/issues/118485 + ------------------------ "##, }, @@ -6889,149 +7136,20 @@ The tracking issue for this feature is: [#42839] label: "pin_deref_mut", description: r##"# `pin_deref_mut` -The tracking issue for this feature is: [#86918] - -[#86918]: https://github.com/rust-lang/rust/issues/86918 - ------------------------- -"##, - }, - Lint { - label: "platform_intrinsics", - description: r##"# `platform_intrinsics` - -The tracking issue for this feature is: [#27731] - -[#27731]: https://github.com/rust-lang/rust/issues/27731 - ------------------------- -"##, - }, - Lint { - label: "plugin", - description: r##"# `plugin` - -The tracking issue for this feature is: [#29597] - -[#29597]: https://github.com/rust-lang/rust/issues/29597 - - -This feature is part of "compiler plugins." It will often be used with the -`rustc_private` feature. - ------------------------- - -`rustc` can load compiler plugins, which are user-provided libraries that -extend the compiler's behavior with new lint checks, etc. - -A plugin is a dynamic library crate with a designated *registrar* function that -registers extensions with `rustc`. Other crates can load these extensions using -the crate attribute `#![plugin(...)]`. See the -`rustc_driver::plugin` documentation for more about the -mechanics of defining and loading a plugin. - -In the vast majority of cases, a plugin should *only* be used through -`#![plugin]` and not through an `extern crate` item. Linking a plugin would -pull in all of librustc_ast and librustc as dependencies of your crate. This is -generally unwanted unless you are building another plugin. - -The usual practice is to put compiler plugins in their own crate, separate from -any `macro_rules!` macros or ordinary Rust code meant to be used by consumers -of a library. - -# Lint plugins - -Plugins can extend [Rust's lint -infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with -additional checks for code style, safety, etc. Now let's write a plugin -[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs) -that warns about any item named `lintme`. - -```rust,ignore (requires-stage-2) -#![feature(rustc_private)] - -extern crate rustc_ast; - -// Load rustc as a plugin to get macros -extern crate rustc_driver; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_ast::ast; -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; - -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint_pass!(Pass => [TEST_LINT]); - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| Box::new(Pass)); -} -``` - -Then code like - -```rust,ignore (requires-plugin) -#![feature(plugin)] -#![plugin(lint_plugin_test)] - -fn lintme() { } -``` - -will produce a compiler warning: - -```txt -foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default -foo.rs:4 fn lintme() { } - ^~~~~~~~~~~~~~~ -``` - -The components of a lint plugin are: - -* one or more `declare_lint!` invocations, which define static `Lint` structs; - -* a struct holding any state needed by the lint pass (here, none); - -* a `LintPass` - implementation defining how to check each syntax element. A single - `LintPass` may call `span_lint` for several different `Lint`s, but should - register them all through the `get_lints` method. - -Lint passes are syntax traversals, but they run at a late stage of compilation -where type information is available. `rustc`'s [built-in -lints](https://github.com/rust-lang/rust/blob/master/compiler/rustc_lint_defs/src/builtin.rs) -mostly use the same infrastructure as lint plugins, and provide examples of how -to access type information. +The tracking issue for this feature is: [#86918] -Lints defined by plugins are controlled by the usual [attributes and compiler -flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g. -`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the -first argument to `declare_lint!`, with appropriate case and punctuation -conversion. +[#86918]: https://github.com/rust-lang/rust/issues/86918 -You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, -including those provided by plugins loaded by `foo.rs`. +------------------------ "##, }, Lint { - label: "pointer_byte_offsets", - description: r##"# `pointer_byte_offsets` + label: "platform_intrinsics", + description: r##"# `platform_intrinsics` -The tracking issue for this feature is: [#96283] +The tracking issue for this feature is: [#27731] -[#96283]: https://github.com/rust-lang/rust/issues/96283 +[#27731]: https://github.com/rust-lang/rust/issues/27731 ------------------------ "##, @@ -7075,17 +7193,6 @@ The tracking issue for this feature is: [#44839] [#44839]: https://github.com/rust-lang/rust/issues/44839 ------------------------- -"##, - }, - Lint { - label: "precise_pointer_size_matching", - description: r##"# `precise_pointer_size_matching` - -The tracking issue for this feature is: [#56354] - -[#56354]: https://github.com/rust-lang/rust/issues/56354 - ------------------------ "##, }, @@ -7124,6 +7231,17 @@ The tracking issue for this feature is: [#115268] [#115268]: https://github.com/rust-lang/rust/issues/115268 +------------------------ +"##, + }, + Lint { + label: "proc_macro_c_str_literals", + description: r##"# `proc_macro_c_str_literals` + +The tracking issue for this feature is: [#119750] + +[#119750]: https://github.com/rust-lang/rust/issues/119750 + ------------------------ "##, }, @@ -7248,17 +7366,6 @@ The tracking issue for this feature is: [#42524](https://github.com/rust-lang/ru This feature is internal to the Rust compiler and is not intended for general use. ------------------------- -"##, - }, - Lint { - label: "ptr_addr_eq", - description: r##"# `ptr_addr_eq` - -The tracking issue for this feature is: [#116324] - -[#116324]: https://github.com/rust-lang/rust/issues/116324 - ------------------------ "##, }, @@ -7281,17 +7388,6 @@ The tracking issue for this feature is: [#75402] [#75402]: https://github.com/rust-lang/rust/issues/75402 ------------------------- -"##, - }, - Lint { - label: "ptr_from_ref", - description: r##"# `ptr_from_ref` - -The tracking issue for this feature is: [#106116] - -[#106116]: https://github.com/rust-lang/rust/issues/106116 - ------------------------ "##, }, @@ -7365,17 +7461,6 @@ The tracking issue for this feature is: [#107792] [#107792]: https://github.com/rust-lang/rust/issues/107792 ------------------------- -"##, - }, - Lint { - label: "raw_os_nonzero", - description: r##"# `raw_os_nonzero` - -The tracking issue for this feature is: [#82363] - -[#82363]: https://github.com/rust-lang/rust/issues/82363 - ------------------------ "##, }, @@ -7502,28 +7587,6 @@ The tracking issue for this feature is: [#70142] [#70142]: https://github.com/rust-lang/rust/issues/70142 ------------------------- -"##, - }, - Lint { - label: "result_option_inspect", - description: r##"# `result_option_inspect` - -The tracking issue for this feature is: [#91345] - -[#91345]: https://github.com/rust-lang/rust/issues/91345 - ------------------------- -"##, - }, - Lint { - label: "return_position_impl_trait_in_trait", - description: r##"# `return_position_impl_trait_in_trait` - -The tracking issue for this feature is: [#91611] - -[#91611]: https://github.com/rust-lang/rust/issues/91611 - ------------------------ "##, }, @@ -7557,17 +7620,6 @@ The tracking issue for this feature is: [#93743] [#93743]: https://github.com/rust-lang/rust/issues/93743 ------------------------- -"##, - }, - Lint { - label: "round_ties_even", - description: r##"# `round_ties_even` - -The tracking issue for this feature is: [#96710] - -[#96710]: https://github.com/rust-lang/rust/issues/96710 - ------------------------ "##, }, @@ -7709,6 +7761,17 @@ The tracking issue for this feature is: [#101730] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +------------------------ +"##, + }, + Lint { + label: "seek_seek_relative", + description: r##"# `seek_seek_relative` + +The tracking issue for this feature is: [#117374] + +[#117374]: https://github.com/rust-lang/rust/issues/117374 + ------------------------ "##, }, @@ -7806,17 +7869,6 @@ The tracking issue for this feature is: [#27747] [#27747]: https://github.com/rust-lang/rust/issues/27747 ------------------------- -"##, - }, - Lint { - label: "slice_first_last_chunk", - description: r##"# `slice_first_last_chunk` - -The tracking issue for this feature is: [#111774] - -[#111774]: https://github.com/rust-lang/rust/issues/111774 - ------------------------ "##, }, @@ -7839,17 +7891,6 @@ The tracking issue for this feature is: [#89792] [#89792]: https://github.com/rust-lang/rust/issues/89792 ------------------------- -"##, - }, - Lint { - label: "slice_group_by", - description: r##"# `slice_group_by` - -The tracking issue for this feature is: [#80552] - -[#80552]: https://github.com/rust-lang/rust/issues/80552 - ------------------------ "##, }, @@ -7945,6 +7986,17 @@ The tracking issue for this feature is: [#76014] [#76014]: https://github.com/rust-lang/rust/issues/76014 +------------------------ +"##, + }, + Lint { + label: "slice_split_once", + description: r##"# `slice_split_once` + +The tracking issue for this feature is: [#112811] + +[#112811]: https://github.com/rust-lang/rust/issues/112811 + ------------------------ "##, }, @@ -8038,6 +8090,17 @@ The tracking issue for this feature is: [#96137] [#96137]: https://github.com/rust-lang/rust/issues/96137 +------------------------ +"##, + }, + Lint { + label: "split_at_checked", + description: r##"# `split_at_checked` + +The tracking issue for this feature is: [#119128] + +[#119128]: https://github.com/rust-lang/rust/issues/119128 + ------------------------ "##, }, @@ -8174,6 +8237,28 @@ The tracking issue for this feature is: [#15701] [#15701]: https://github.com/rust-lang/rust/issues/15701 +------------------------ +"##, + }, + Lint { + label: "str_from_raw_parts", + description: r##"# `str_from_raw_parts` + +The tracking issue for this feature is: [#119206] + +[#119206]: https://github.com/rust-lang/rust/issues/119206 + +------------------------ +"##, + }, + Lint { + label: "str_from_utf16_endian", + description: r##"# `str_from_utf16_endian` + +The tracking issue for this feature is: [#116258] + +[#116258]: https://github.com/rust-lang/rust/issues/116258 + ------------------------ "##, }, @@ -8183,6 +8268,17 @@ The tracking issue for this feature is: [#15701] This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "str_lines_remainder", + description: r##"# `str_lines_remainder` + +The tracking issue for this feature is: [#77998] + +[#77998]: https://github.com/rust-lang/rust/issues/77998 + ------------------------ "##, }, @@ -8216,6 +8312,17 @@ The tracking issue for this feature is: [#77998] [#77998]: https://github.com/rust-lang/rust/issues/77998 +------------------------ +"##, + }, + Lint { + label: "strict_overflow_ops", + description: r##"# `strict_overflow_ops` + +The tracking issue for this feature is: [#118260] + +[#118260]: https://github.com/rust-lang/rust/issues/118260 + ------------------------ "##, }, @@ -8265,6 +8372,44 @@ The tracking issue for this feature is: [#87121] [#87121]: https://github.com/rust-lang/rust/issues/87121 ------------------------ + +This feature permits pattern matching `String` to `&str` through [its `Deref` implementation]. + +```rust +#![feature(string_deref_patterns)] + +pub enum Value { + String(String), + Number(u32), +} + +pub fn is_it_the_answer(value: Value) -> bool { + match value { + Value::String("42") => true, + Value::Number(42) => true, + _ => false, + } +} +``` + +Without this feature other constructs such as match guards have to be used. + +```rust +# pub enum Value { +# String(String), +# Number(u32), +# } +# +pub fn is_it_the_answer(value: Value) -> bool { + match value { + Value::String(s) if s == "42" => true, + Value::Number(42) => true, + _ => false, + } +} +``` + +[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String "##, }, Lint { @@ -8526,15 +8671,6 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured However, the optimizer can still modify a testcase in an undesirable manner even when using either of the above. -"##, - }, - Lint { - label: "test_2018_feature", - description: r##"# `test_2018_feature` - -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. - ------------------------- "##, }, Lint { @@ -8850,6 +8986,15 @@ The tracking issue for this feature is: [#48214] [#48214]: https://github.com/rust-lang/rust/issues/48214 +------------------------ +"##, + }, + Lint { + label: "trusted_fused", + description: r##"# `trusted_fused` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -9050,17 +9195,6 @@ fn main () { }; } ``` -"##, - }, - Lint { - label: "type_name_of_val", - description: r##"# `type_name_of_val` - -The tracking issue for this feature is: [#66359] - -[#66359]: https://github.com/rust-lang/rust/issues/66359 - ------------------------- "##, }, Lint { @@ -9122,6 +9256,28 @@ The tracking issue for this feature is: [#85122] [#85122]: https://github.com/rust-lang/rust/issues/85122 +------------------------ +"##, + }, + Lint { + label: "unchecked_neg", + description: r##"# `unchecked_neg` + +The tracking issue for this feature is: [#85122] + +[#85122]: https://github.com/rust-lang/rust/issues/85122 + +------------------------ +"##, + }, + Lint { + label: "unchecked_shifts", + description: r##"# `unchecked_shifts` + +The tracking issue for this feature is: [#85122] + +[#85122]: https://github.com/rust-lang/rust/issues/85122 + ------------------------ "##, }, @@ -9630,9 +9786,9 @@ The tracking issue for this feature is: [#81944] label: "waker_getters", description: r##"# `waker_getters` -The tracking issue for this feature is: [#87021] +The tracking issue for this feature is: [#96992] -[#87021]: https://github.com/rust-lang/rust/issues/87021 +[#96992]: https://github.com/rust-lang/rust/issues/96992 ------------------------ "##, @@ -9712,7 +9868,9 @@ This feature is internal to the Rust compiler and is not intended for general us label: "windows_process_exit_code_from", description: r##"# `windows_process_exit_code_from` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#111688] + +[#111688]: https://github.com/rust-lang/rust/issues/111688 ------------------------ "##, @@ -10008,7 +10166,7 @@ table: description: r##"Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category."##, }, Lint { - label: "clippy::blocks_in_if_conditions", + label: "clippy::blocks_in_conditions", description: r##"Checks for `if` conditions that use blocks containing an expression, statements or conditions that use closures with blocks."##, }, @@ -10315,7 +10473,8 @@ with `#[rustfmt::skip]`."##, Lint { label: "clippy::deprecated_semver", description: r##"Checks for `#[deprecated]` annotations with a `since` -field that is not a valid semantic version."##, +field that is not a valid semantic version. Also allows TBD to signal +future deprecation."##, }, Lint { label: "clippy::deref_addrof", @@ -10442,6 +10601,11 @@ differing by an underscore."##, label: "clippy::duration_subsec", description: r##"Checks for calculation of subsecond microseconds or milliseconds from other `Duration` methods."##, + }, + Lint { + label: "clippy::eager_transmute", + description: r##"Checks for integer validity checks, followed by a transmute that is (incorrectly) evaluated +eagerly (e.g. using `bool::then_some`)."##, }, Lint { label: "clippy::else_if_without_else", @@ -10460,9 +10624,13 @@ As of this writing, the `never_type` is still a nightly-only experimental API. Therefore, this lint is only triggered if the `never_type` is enabled."##, }, + Lint { + label: "clippy::empty_enum_variants_with_brackets", + description: r##"Finds enum variants without fields that are declared with empty brackets."##, + }, Lint { label: "clippy::empty_line_after_doc_comments", - description: r##"Checks for empty lines after documenation comments."##, + description: r##"Checks for empty lines after documentation comments."##, }, Lint { label: "clippy::empty_line_after_outer_attr", @@ -10726,7 +10894,7 @@ multithreaded executors are likely to be used for running these Futures."##, Lint { label: "clippy::get_first", description: r##"Checks for usage of `x.get(0)` instead of -`x.first()`."##, +`x.first()` or `x.front()`."##, }, Lint { label: "clippy::get_last_with_len", @@ -10777,6 +10945,13 @@ and the *else* part."##, label: "clippy::ignored_unit_patterns", description: r##"Checks for usage of `_` in patterns of type `()`."##, }, + Lint { + label: "clippy::impl_hash_borrow_with_str_and_bytes", + description: r##"This lint is concerned with the semantics of `Borrow` and `Hash` for a +type that implements all three of `Hash`, `Borrow` and `Borrow<[u8]>` +as it is impossible to satisfy the semantics of Borrow and `Hash` for +both `Borrow` and `Borrow<[u8]>`."##, + }, Lint { label: "clippy::impl_trait_in_params", description: r##"Lints when `impl Trait` is being used in a function's parameters."##, @@ -10819,6 +10994,11 @@ because `Deref` is a supertrait of `DerefMut`)"##, description: r##"Looks for floating-point expressions that can be expressed using built-in methods to improve accuracy at the cost of performance."##, + }, + Lint { + label: "clippy::incompatible_msrv", + description: r##"This lint checks that no function newer than the defined MSRV (minimum +supported rust version) is used in the crate."##, }, Lint { label: "clippy::inconsistent_digit_grouping", @@ -10852,6 +11032,11 @@ following table: |----------|----------|------------|-------| |`>` / `<=`|`\\|` / `^`|`x \\| 2 > 3`|`x > 3`| |`<` / `>=`|`\\|` / `^`|`x ^ 1 < 4` |`x < 4`|"##, + }, + Lint { + label: "clippy::ineffective_open_options", + description: r##"Checks if both `.write(true)` and `.append(true)` methods are called +on a same `OpenOptions`."##, }, Lint { label: "clippy::inefficient_to_string", @@ -10867,6 +11052,11 @@ or tuple struct where a `let` will suffice."##, label: "clippy::infinite_iter", description: r##"Checks for iteration that is guaranteed to be infinite."##, }, + Lint { + label: "clippy::infinite_loop", + description: r##"Checks for infinite loops in a function where the return type is not `!` +and lint accordingly."##, + }, Lint { label: "clippy::inherent_to_string", description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`."##, @@ -10961,6 +11151,16 @@ create a `Vec`."##, label: "clippy::iter_count", description: r##"Checks for the use of `.iter().count()`."##, }, + Lint { + label: "clippy::iter_filter_is_ok", + description: r##"Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call. +This lint will require additional changes to the follow-up calls as it appects the type."##, + }, + Lint { + label: "clippy::iter_filter_is_some", + description: r##"Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call. +This lint will require additional changes to the follow-up calls as it appects the type."##, + }, Lint { label: "clippy::iter_kv_map", description: r##"Checks for iterating a map (`HashMap` or `BTreeMap`) and @@ -10997,6 +11197,10 @@ ignoring either the keys or values."##, description: r##"Looks for iterator combinator calls such as `.take(x)` or `.skip(x)` where `x` is greater than the amount of items that an iterator will produce."##, }, + Lint { + label: "clippy::iter_over_hash_type", + description: r##"This is a restriction lint which prevents the use of hash types (i.e., `HashSet` and `HashMap`) in for loops."##, + }, Lint { label: "clippy::iter_overeager_cloned", description: r##"Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed."##, @@ -11021,6 +11225,10 @@ where `x` is greater than the amount of items that an iterator will produce."##, label: "clippy::iterator_step_by_zero", description: r##"Checks for calling `.step_by(0)` on iterators which panics."##, }, + Lint { + label: "clippy::join_absolute_paths", + description: r##"Checks for calls to `Path::join` that start with a path separator (`\\\\` or `/`)."##, + }, Lint { label: "clippy::just_underscores_and_digits", description: r##"Checks if you have variables whose name consists of just @@ -11121,6 +11329,14 @@ when `lines` has type `std::io::Lines`."##, label: "clippy::linkedlist", description: r##"Checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`)."##, + }, + Lint { + label: "clippy::lint_groups_priority", + description: r##"Checks for lint groups with the same priority as lints in the `Cargo.toml` +[`[lints]` table](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section). + +This lint will be removed once [cargo#12918](https://github.com/rust-lang/cargo/issues/12918) +is resolved."##, }, Lint { label: "clippy::little_endian_bytes", @@ -11192,7 +11408,8 @@ where only the `Some` or `Ok` variant of the iterator element is used."##, Lint { label: "clippy::manual_is_ascii_check", description: r##"Suggests to use dedicated built-in methods, -`is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range"##, +`is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding +ascii range"##, }, Lint { label: "clippy::manual_is_finite", @@ -11204,6 +11421,7 @@ where only the `Some` or `Ok` variant of the iterator element is used."##, description: r##"Checks for manual `is_infinite` reimplementations (i.e., `x == ::INFINITY || x == ::NEG_INFINITY`)."##, }, + Lint { label: "clippy::manual_is_variant_and", description: r##""## }, Lint { label: "clippy::manual_let_else", description: r##"Warn of cases where `let...else` could be used"##, @@ -11400,7 +11618,9 @@ and take drastic actions like `panic!`."##, Lint { label: "clippy::maybe_misused_cfg", description: r##"Checks for `#[cfg(features = ...)]` and suggests to replace it with -`#[cfg(feature = ...)]`."##, +`#[cfg(feature = ...)]`. + +It also checks if `cfg(test)` was misspelled."##, }, Lint { label: "clippy::mem_forget", @@ -11478,7 +11698,10 @@ is greater than the largest index used to index into the slice."##, Lint { label: "clippy::missing_enforced_import_renames", description: r##"Checks for imports that do not rename the item as specified -in the `enforce-import-renames` config option."##, +in the `enforced-import-renames` config option. + +Note: Even though this lint is warn-by-default, it will only trigger if +import renames are defined in the `clippy.toml` file."##, }, Lint { label: "clippy::missing_errors_doc", @@ -11866,6 +12089,10 @@ character escapes in C."##, taken to satisfy a bound and suggests to dereference the other argument instead"##, }, + Lint { + label: "clippy::option_as_ref_cloned", + description: r##"Checks for usage of `.as_ref().cloned()` and `.as_mut().cloned()` on `Option`s"##, + }, Lint { label: "clippy::option_as_ref_deref", description: r##"Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str)."##, @@ -11877,7 +12104,8 @@ suggests usage of the `env!` macro."##, }, Lint { label: "clippy::option_filter_map", - description: r##"Checks for indirect collection of populated `Option`"##, + description: r##"Checks for iterators of `Option`s using `.filter(Option::is_some).map(Option::unwrap)` that may +be replaced with a `.flatten()` call."##, }, Lint { label: "clippy::option_if_let_else", @@ -11887,6 +12115,10 @@ idiomatically done with `Option::map_or` (if the else bit is a pure expression) or `Option::map_or_else` (if the else bit is an impure expression)."##, }, + Lint { + label: "clippy::option_map_or_err_ok", + description: r##"Checks for usage of `_.map_or(Err(_), Ok)`."##, + }, Lint { label: "clippy::option_map_or_none", description: r##"Checks for usage of `_.map_or(None, _)`."##, @@ -12058,6 +12290,11 @@ namely `*const T` to `*const U` and `*mut T` to `*mut U`."##, label: "clippy::pub_enum_variant_names", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { + label: "clippy::pub_underscore_fields", + description: r##"Checks whether any field of the struct is prefixed with an `_` (underscore) and also marked +`pub` (public)"##, + }, Lint { label: "clippy::pub_use", description: r##"Restricts the usage of `pub use ...`"## }, Lint { label: "clippy::pub_with_shorthand", @@ -12135,7 +12372,7 @@ This is typically done indirectly with the `write!` macro or with `to_string()`. }, Lint { label: "clippy::redundant_as_str", - description: r##"Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself."##, + description: r##"Checks for usage of `as_str()` on a `String` chained with a method available on the `String` itself."##, }, Lint { label: "clippy::redundant_async_block", @@ -12153,8 +12390,8 @@ value that is going to be dropped without further use."##, Lint { label: "clippy::redundant_closure", description: r##"Checks for closures which just call another function where -the function can be called directly. `unsafe` functions or calls where types -get adjusted are ignored."##, +the function can be called directly. `unsafe` functions, calls where types +get adjusted or where the callee is marked `#[track_caller]` are ignored."##, }, Lint { label: "clippy::redundant_closure_call", @@ -12198,7 +12435,7 @@ could be used."##, Lint { label: "clippy::redundant_pattern_matching", description: r##"Lint for redundant pattern matching over `Result`, `Option`, -`std::task::Poll` or `std::net::IpAddr`"##, +`std::task::Poll`, `std::net::IpAddr` or `bool`s"##, }, Lint { label: "clippy::redundant_pub_crate", @@ -12244,6 +12481,10 @@ do not change the type."##, The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))"##, }, + Lint { + label: "clippy::repeat_vec_with_capacity", + description: r##"Looks for patterns such as `vec![Vec::with_capacity(x); n]` or `iter::repeat(Vec::with_capacity(x))`."##, + }, Lint { label: "clippy::replace_consts", description: r##"Nothing. This lint has been deprecated."##, @@ -12256,6 +12497,11 @@ they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://gi label: "clippy::rest_pat_in_fully_bound_structs", description: r##"Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched."##, }, + Lint { + label: "clippy::result_filter_map", + description: r##"Checks for iterators of `Result`s using `.filter(Result::is_ok).map(Result::unwrap)` that may +be replaced with a `.flatten()` call."##, + }, Lint { label: "clippy::result_large_err", description: r##"Checks for functions that return `Result` with an unusually large @@ -12348,7 +12594,7 @@ see the `unseparated_literal_suffix` lint."##, }, Lint { label: "clippy::serde_api_misuse", - description: r##"Checks for mis-uses of the serde API."##, + description: r##"Checks for misuses of the serde API."##, }, Lint { label: "clippy::shadow_reuse", @@ -12485,6 +12731,12 @@ use an unstable sort than a stable sort."##, label: "clippy::std_instead_of_core", description: r##"Finds items imported through `std` when available through `core`."##, }, + Lint { + label: "clippy::str_split_at_newline", + description: r##"Checks for usages of `str.trim().split(\ +)` and `str.trim().split(\\ +)`."##, + }, Lint { label: "clippy::str_to_string", description: r##"This lint checks for `.to_string()` method calls on values of type `&str`."##, @@ -12535,6 +12787,11 @@ and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instea label: "clippy::struct_excessive_bools", description: r##"Checks for excessive use of bools in structs."##, + }, + Lint { + label: "clippy::struct_field_names", + description: r##"Detects struct fields that are prefixed or suffixed +by the same characters or the name of the struct itself."##, }, Lint { label: "clippy::suboptimal_flops", @@ -12574,6 +12831,11 @@ is followed immediately by a newline or the `else` seems to be missing."##, label: "clippy::suspicious_op_assign_impl", description: r##"Lints for suspicious operations in impls of OpAssign, e.g. subtracting elements in an AddAssign impl."##, + }, + Lint { + label: "clippy::suspicious_open_options", + description: r##"Checks for the suspicious use of `OpenOptions::create()` +without an explicit `OpenOptions::truncate()`."##, }, Lint { label: "clippy::suspicious_operation_groupings", @@ -12613,12 +12875,21 @@ but there is a space between the unary and its operand."##, label: "clippy::temporary_assignment", description: r##"Checks for construction of a structure or tuple just to assign a value in it."##, + }, + Lint { + label: "clippy::test_attr_in_doctest", + description: r##"Checks for `#[test]` in doctests unless they are marked with +either `ignore`, `no_run` or `compile_fail`."##, }, Lint { label: "clippy::tests_outside_test_module", description: r##"Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module (marked with `#[cfg(test)]`)."##, }, + Lint { + label: "clippy::thread_local_initializer_can_be_made_const", + description: r##"Suggests to use `const` in `thread_local!` macro if possible."##, + }, Lint { label: "clippy::to_digit_is_some", description: r##"Checks for `.to_digit(..).is_some()` on `char`s."##, @@ -12629,6 +12900,10 @@ assign a value in it."##, applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) in a macro that does formatting."##, }, + Lint { + label: "clippy::to_string_trait_impl", + description: r##"Checks for direct implementations of `ToString`."##, + }, Lint { label: "clippy::todo", description: r##"Checks for usage of `todo!`."## }, Lint { label: "clippy::too_many_arguments", @@ -12742,7 +13017,12 @@ declarations above a certain complexity threshold."##, }, Lint { label: "clippy::unchecked_duration_subtraction", - description: r##"Lints subtraction between an [`Instant`] and a [`Duration`]."##, + description: r##"Lints subtraction between an `Instant` and a `Duration`."##, + }, + Lint { + label: "clippy::unconditional_recursion", + description: r##"Checks that there isn't an infinite recursion in `PartialEq` trait +implementation."##, }, Lint { label: "clippy::undocumented_unsafe_blocks", @@ -12778,6 +13058,11 @@ that is not equal to its label: "clippy::unimplemented", description: r##"Checks for usage of `unimplemented!`."##, }, + Lint { + label: "clippy::uninhabited_references", + description: r##"It detects references to uninhabited types, such as `!` and +warns when those are either dereferenced or returned from a function."##, + }, Lint { label: "clippy::uninit_assumed_init", description: r##"Checks for `MaybeUninit::uninit().assume_init()`."##, @@ -12821,6 +13106,11 @@ as returning a large `T` directly may be detrimental to performance."##, label: "clippy::unnecessary_cast", description: r##"Checks for casts to the same type, casts of int literals to integer types, casts of float literals to float types and casts between raw pointers without changing type or constness."##, + }, + Lint { + label: "clippy::unnecessary_fallible_conversions", + description: r##"Checks for calls to `TryInto::try_into` and `TryFrom::try_from` when their infallible counterparts +could be used."##, }, Lint { label: "clippy::unnecessary_filter_map", @@ -12864,7 +13154,8 @@ simpler code: }, Lint { label: "clippy::unnecessary_map_on_constructor", - description: r##"Suggest removing the use of a may (or map_err) method when an Option or Result is being construted."##, + description: r##"Suggests removing the use of a `map()` (or `map_err()`) method when an `Option` or `Result` +is being constructed."##, }, Lint { label: "clippy::unnecessary_mut_passed", @@ -12880,6 +13171,10 @@ sub-expression."##, label: "clippy::unnecessary_owned_empty_strings", description: r##"Detects cases of owned empty strings being passed as an argument to a function expecting `&str`"##, }, + Lint { + label: "clippy::unnecessary_result_map_or_else", + description: r##"Checks for usage of `.map_or_else()` map closure for `Result` type."##, + }, Lint { label: "clippy::unnecessary_safety_comment", description: r##"Checks for `// SAFETY: ` comments on safe code."##, @@ -12986,6 +13281,10 @@ types have different ABI, size or alignment."##, label: "clippy::unused_collect", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { + label: "clippy::unused_enumerate_index", + description: r##"Checks for uses of the `enumerate` method where the index is unused (`_`)"##, + }, Lint { label: "clippy::unused_format_specs", description: r##"Detects [formatting parameters] that have no effect on the output of @@ -13130,8 +13429,8 @@ to `trailing_zeros`"##, description: r##"Checks for usage of File::read_to_end and File::read_to_string."##, }, Lint { - label: "clippy::vtable_address_comparisons", - description: r##"Checks for comparisons with an address of a trait vtable."##, + label: "clippy::waker_clone_wake", + description: r##"Checks for usage of `waker.clone().wake()`"##, }, Lint { label: "clippy::while_immutable_condition", @@ -13251,7 +13550,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::complexity", - description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, + description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::implied_bounds_in_impls, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_filter_map, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, }, children: &[ "clippy::bind_instead_of_map", @@ -13281,6 +13580,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::flat_map_identity", "clippy::get_last_with_len", "clippy::identity_op", + "clippy::implied_bounds_in_impls", "clippy::inspect_for_each", "clippy::int_plus_one", "clippy::iter_count", @@ -13337,6 +13637,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::redundant_slicing", "clippy::repeat_once", "clippy::reserve_after_initialization", + "clippy::result_filter_map", "clippy::result_map_unit_fn", "clippy::search_is_some", "clippy::seek_from_current", @@ -13383,7 +13684,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::correctness", - description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::read_zero_byte_vec, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::vtable_address_comparisons, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, + description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::eager_transmute, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::ifs_same_cond, clippy::impl_hash_borrow_with_str_and_bytes, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::lint_groups_priority, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, }, children: &[ "clippy::absurd_extreme_comparisons", @@ -13395,13 +13696,14 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::deprecated_semver", "clippy::derive_ord_xor_partial_ord", "clippy::derived_hash_with_manual_eq", + "clippy::eager_transmute", "clippy::enum_clike_unportable_variant", "clippy::eq_op", "clippy::erasing_op", "clippy::fn_address_comparisons", "clippy::if_let_mutex", - "clippy::if_same_then_else", "clippy::ifs_same_cond", + "clippy::impl_hash_borrow_with_str_and_bytes", "clippy::impossible_comparisons", "clippy::ineffective_bit_mask", "clippy::infinite_iter", @@ -13414,6 +13716,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::iter_skip_zero", "clippy::iterator_step_by_zero", "clippy::let_underscore_lock", + "clippy::lint_groups_priority", "clippy::match_str_case_mismatch", "clippy::mem_replace_with_uninit", "clippy::min_max", @@ -13431,7 +13734,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::panicking_unwrap", "clippy::possible_missing_comma", "clippy::read_line_without_trim", - "clippy::read_zero_byte_vec", "clippy::recursive_format_impl", "clippy::redundant_comparisons", "clippy::redundant_locals", @@ -13451,7 +13753,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unused_io_amount", "clippy::useless_attribute", "clippy::vec_resize_to_zero", - "clippy::vtable_address_comparisons", "clippy::while_immutable_condition", "clippy::wrong_transmute", "clippy::zst_offset", @@ -13484,7 +13785,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::nursery", - description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::implied_bounds_in_impls, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, + description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::read_zero_byte_vec, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::uninhabited_references, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, }, children: &[ "clippy::as_ptr_cast_mut", @@ -13499,7 +13800,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::equatable_if_let", "clippy::fallible_impl_from", "clippy::future_not_send", - "clippy::implied_bounds_in_impls", "clippy::imprecise_flops", "clippy::iter_on_empty_collections", "clippy::iter_on_single_items", @@ -13515,6 +13815,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::option_if_let_else", "clippy::or_fun_call", "clippy::path_buf_push_overwrite", + "clippy::read_zero_byte_vec", "clippy::readonly_write_lock", "clippy::redundant_clone", "clippy::redundant_pub_crate", @@ -13529,6 +13830,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::trivial_regex", "clippy::tuple_array_conversions", "clippy::type_repetition_in_bounds", + "clippy::uninhabited_references", "clippy::unnecessary_struct_initialization", "clippy::unused_peekable", "clippy::unused_rounding", @@ -13539,7 +13841,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::pedantic", - description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, + description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_filter_is_ok, clippy::iter_filter_is_some, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_is_variant_and, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_as_ref_cloned, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::pub_underscore_fields, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::str_split_at_newline, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::struct_field_names, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, }, children: &[ "clippy::bool_to_int_with_if", @@ -13579,6 +13881,8 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::into_iter_without_iter", "clippy::invalid_upcast_comparisons", "clippy::items_after_statements", + "clippy::iter_filter_is_ok", + "clippy::iter_filter_is_some", "clippy::iter_not_returning_iterator", "clippy::iter_without_into_iter", "clippy::large_digit_groups", @@ -13589,6 +13893,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::macro_use_imports", "clippy::manual_assert", "clippy::manual_instant_elapsed", + "clippy::manual_is_variant_and", "clippy::manual_let_else", "clippy::manual_ok_or", "clippy::manual_string_new", @@ -13615,9 +13920,11 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::needless_raw_string_hashes", "clippy::no_effect_underscore_binding", "clippy::no_mangle_with_rust_abi", + "clippy::option_as_ref_cloned", "clippy::option_option", "clippy::ptr_as_ptr", "clippy::ptr_cast_constness", + "clippy::pub_underscore_fields", "clippy::range_minus_one", "clippy::range_plus_one", "clippy::redundant_closure_for_method_calls", @@ -13631,8 +13938,10 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::similar_names", "clippy::single_match_else", "clippy::stable_sort_primitive", + "clippy::str_split_at_newline", "clippy::string_add_assign", "clippy::struct_excessive_bools", + "clippy::struct_field_names", "clippy::too_many_lines", "clippy::transmute_ptr_to_ptr", "clippy::trivially_copy_pass_by_ref", @@ -13656,7 +13965,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::perf", - description: r##"lint group for: clippy::box_collection, clippy::box_default, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_nth, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_spin_loop, clippy::redundant_allocation, clippy::result_large_err, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push"##, + description: r##"lint group for: clippy::box_collection, clippy::box_default, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_nth, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_spin_loop, clippy::redundant_allocation, clippy::result_large_err, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::thread_local_initializer_can_be_made_const, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push, clippy::waker_clone_wake"##, }, children: &[ "clippy::box_collection", @@ -13683,16 +13992,18 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::result_large_err", "clippy::single_char_pattern", "clippy::slow_vector_initialization", + "clippy::thread_local_initializer_can_be_made_const", "clippy::to_string_in_format_args", "clippy::unnecessary_to_owned", "clippy::useless_vec", "clippy::vec_init_then_push", + "clippy::waker_clone_wake", ], }, LintGroup { lint: Lint { label: "clippy::restriction", - description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_enforced_import_renames, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, + description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_enum_variants_with_brackets, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::infinite_loop, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::iter_over_hash_type, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, }, children: &[ "clippy::absolute_paths", @@ -13714,6 +14025,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::disallowed_script_idents", "clippy::else_if_without_else", "clippy::empty_drop", + "clippy::empty_enum_variants_with_brackets", "clippy::empty_structs_with_brackets", "clippy::error_impl_error", "clippy::exhaustive_enums", @@ -13731,9 +14043,11 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::impl_trait_in_params", "clippy::implicit_return", "clippy::indexing_slicing", + "clippy::infinite_loop", "clippy::inline_asm_x86_att_syntax", "clippy::inline_asm_x86_intel_syntax", "clippy::integer_division", + "clippy::iter_over_hash_type", "clippy::large_include_file", "clippy::let_underscore_must_use", "clippy::let_underscore_untyped", @@ -13745,7 +14059,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::missing_assert_message", "clippy::missing_asserts_for_indexing", "clippy::missing_docs_in_private_items", - "clippy::missing_enforced_import_renames", "clippy::missing_inline_in_public_items", "clippy::missing_trait_methods", "clippy::mixed_read_write_in_expression", @@ -13810,12 +14123,12 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::style", - description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_if_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, + description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::if_same_then_else, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_enforced_import_renames, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_err_ok, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::to_string_trait_impl, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fallible_conversions, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_enumerate_index, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, }, children: &[ "clippy::assertions_on_constants", "clippy::assign_op_pattern", - "clippy::blocks_in_if_conditions", + "clippy::blocks_in_conditions", "clippy::bool_assert_comparison", "clippy::borrow_interior_mutable_const", "clippy::builtin_type_shadow", @@ -13848,6 +14161,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::from_over_into", "clippy::from_str_radix_10", "clippy::get_first", + "clippy::if_same_then_else", "clippy::implicit_saturating_add", "clippy::implicit_saturating_sub", "clippy::inconsistent_digit_grouping", @@ -13886,6 +14200,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::match_result_ok", "clippy::mem_replace_option_with_none", "clippy::mem_replace_with_default", + "clippy::missing_enforced_import_renames", "clippy::missing_safety_doc", "clippy::mixed_case_hex_literals", "clippy::module_inception", @@ -13908,6 +14223,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::obfuscated_if_else", "clippy::ok_expect", "clippy::op_ref", + "clippy::option_map_or_err_ok", "clippy::option_map_or_none", "clippy::partialeq_to_none", "clippy::print_literal", @@ -13932,13 +14248,16 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::string_extend_chars", "clippy::tabs_in_doc_comments", "clippy::to_digit_is_some", + "clippy::to_string_trait_impl", "clippy::toplevel_ref_arg", "clippy::trim_split_whitespace", + "clippy::unnecessary_fallible_conversions", "clippy::unnecessary_fold", "clippy::unnecessary_lazy_evaluations", "clippy::unnecessary_mut_passed", "clippy::unnecessary_owned_empty_strings", "clippy::unsafe_removed_from_name", + "clippy::unused_enumerate_index", "clippy::unused_unit", "clippy::unusual_byte_groupings", "clippy::unwrap_or_default", @@ -13954,7 +14273,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::suspicious", - description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::iter_out_of_bounds, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::type_id_on_box"##, + description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::incompatible_msrv, clippy::ineffective_open_options, clippy::iter_out_of_bounds, clippy::join_absolute_paths, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::repeat_vec_with_capacity, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_open_options, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::test_attr_in_doctest, clippy::type_id_on_box, clippy::unconditional_recursion, clippy::unnecessary_result_map_or_else"##, }, children: &[ "clippy::almost_complete_range", @@ -13976,7 +14295,10 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::forget_non_drop", "clippy::four_forward_slashes", "clippy::from_raw_with_void_ptr", + "clippy::incompatible_msrv", + "clippy::ineffective_open_options", "clippy::iter_out_of_bounds", + "clippy::join_absolute_paths", "clippy::let_underscore_future", "clippy::lines_filter_map_ok", "clippy::maybe_misused_cfg", @@ -13993,6 +14315,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::permissions_set_readonly_false", "clippy::print_in_format_impl", "clippy::rc_clone_in_vec_init", + "clippy::repeat_vec_with_capacity", "clippy::single_range_in_vec_init", "clippy::size_of_ref", "clippy::suspicious_arithmetic_impl", @@ -14002,10 +14325,14 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::suspicious_else_formatting", "clippy::suspicious_map", "clippy::suspicious_op_assign_impl", + "clippy::suspicious_open_options", "clippy::suspicious_to_owned", "clippy::suspicious_unary_op_formatting", "clippy::swap_ptr_to_ref", + "clippy::test_attr_in_doctest", "clippy::type_id_on_box", + "clippy::unconditional_recursion", + "clippy::unnecessary_result_map_or_else", ], }, ]; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs index 9363bdfa14b2a..0b5ad7060e043 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs @@ -35,7 +35,7 @@ pub fn pick_token(mut tokens: TokenAtOffset) -> Option /// Converts the mod path struct into its ast representation. pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { - let _p = profile::span("mod_path_to_ast"); + let _p = tracing::span!(tracing::Level::INFO, "mod_path_to_ast").entered(); let mut segments = Vec::new(); let mut is_abs = false; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index b834f517d491d..cb3f01f345825 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -208,7 +208,8 @@ impl ImportAssets { prefer_no_std: bool, prefer_prelude: bool, ) -> impl Iterator { - let _p = profile::span("import_assets::search_for_imports"); + let _p = + tracing::span!(tracing::Level::INFO, "import_assets::search_for_imports").entered(); self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude) } @@ -219,7 +220,8 @@ impl ImportAssets { prefer_no_std: bool, prefer_prelude: bool, ) -> impl Iterator { - let _p = profile::span("import_assets::search_for_relative_paths"); + let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for_relative_paths") + .entered(); self.search_for(sema, None, prefer_no_std, prefer_prelude) } @@ -260,7 +262,7 @@ impl ImportAssets { prefer_no_std: bool, prefer_prelude: bool, ) -> impl Iterator { - let _p = profile::span("import_assets::search_for"); + let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for").entered(); let scope = match sema.scope(&self.candidate_node) { Some(it) => it, @@ -305,7 +307,7 @@ impl ImportAssets { } fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet { - let _p = profile::span("import_assets::scope_definitions"); + let _p = tracing::span!(tracing::Level::INFO, "import_assets::scope_definitions").entered(); let mut scope_definitions = FxHashSet::default(); if let Some(scope) = sema.scope(&self.candidate_node) { scope.process_all_names(&mut |_, scope_def| { @@ -323,7 +325,8 @@ fn path_applicable_imports( mod_path: impl Fn(ItemInNs) -> Option + Copy, scope_filter: impl Fn(ItemInNs) -> bool + Copy, ) -> FxHashSet { - let _p = profile::span("import_assets::path_applicable_imports"); + let _p = + tracing::span!(tracing::Level::INFO, "import_assets::path_applicable_imports").entered(); match &path_candidate.qualifier { None => { @@ -357,7 +360,7 @@ fn path_applicable_imports( path_candidate.name.clone(), AssocSearchMode::Include, ) - .filter_map(|item| import_for_item(sema.db, mod_path, &qualifier, item, scope_filter)) + .filter_map(|item| import_for_item(sema.db, mod_path, qualifier, item, scope_filter)) .take(DEFAULT_QUERY_SEARCH_LIMIT.inner()) .collect(), } @@ -370,7 +373,7 @@ fn import_for_item( original_item: ItemInNs, scope_filter: impl Fn(ItemInNs) -> bool, ) -> Option { - let _p = profile::span("import_assets::import_for_item"); + let _p = tracing::span!(tracing::Level::INFO, "import_assets::import_for_item").entered(); let [first_segment, ..] = unresolved_qualifier else { return None }; let item_as_assoc = item_as_assoc(db, original_item); @@ -504,7 +507,8 @@ fn trait_applicable_items( mod_path: impl Fn(ItemInNs) -> Option, scope_filter: impl Fn(hir::Trait) -> bool, ) -> FxHashSet { - let _p = profile::span("import_assets::trait_applicable_items"); + let _p = + tracing::span!(tracing::Level::INFO, "import_assets::trait_applicable_items").entered(); let db = sema.db; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index a0cfd3836ddf0..f29f91eea84f5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -9,14 +9,15 @@ use syntax::{ algo, ast::{ self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, - PathSegmentKind, UseTree, + PathSegmentKind, }, ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, }; use crate::{ imports::merge_imports::{ - common_prefix, eq_attrs, eq_visibility, try_merge_imports, use_tree_path_cmp, MergeBehavior, + common_prefix, eq_attrs, eq_visibility, try_merge_imports, use_tree_cmp, MergeBehavior, + NormalizationStyle, }, RootDatabase, }; @@ -26,7 +27,8 @@ pub use hir::PrefixKind; /// How imports should be grouped into use statements. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ImportGranularity { - /// Do not change the granularity of any imports and preserve the original structure written by the developer. + /// Do not change the granularity of any imports and preserve the original structure written + /// by the developer. Preserve, /// Merge imports from the same crate into a single use statement. Crate, @@ -34,6 +36,18 @@ pub enum ImportGranularity { Module, /// Flatten imports so that each has its own use statement. Item, + /// Merge all imports into a single use statement as long as they have the same visibility + /// and attributes. + One, +} + +impl From for NormalizationStyle { + fn from(granularity: ImportGranularity) -> Self { + match granularity { + ImportGranularity::One => NormalizationStyle::One, + _ => NormalizationStyle::Default, + } + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -167,7 +181,7 @@ pub fn insert_use_as_alias(scope: &ImportScope, path: ast::Path, cfg: &InsertUse .tree() .syntax() .descendants() - .find_map(UseTree::cast) + .find_map(ast::UseTree::cast) .expect("Failed to make ast node `Rename`"); let alias = node.rename(); @@ -180,10 +194,11 @@ fn insert_use_with_alias_option( cfg: &InsertUseConfig, alias: Option, ) { - let _p = profile::span("insert_use"); + let _p = tracing::span!(tracing::Level::INFO, "insert_use").entered(); let mut mb = match cfg.granularity { ImportGranularity::Crate => Some(MergeBehavior::Crate), ImportGranularity::Module => Some(MergeBehavior::Module), + ImportGranularity::One => Some(MergeBehavior::One), ImportGranularity::Item | ImportGranularity::Preserve => None, }; if !cfg.enforce_granularity { @@ -195,11 +210,16 @@ fn insert_use_with_alias_option( ImportGranularityGuess::ModuleOrItem => mb.and(Some(MergeBehavior::Module)), ImportGranularityGuess::Crate => Some(MergeBehavior::Crate), ImportGranularityGuess::CrateOrModule => mb.or(Some(MergeBehavior::Crate)), + ImportGranularityGuess::One => Some(MergeBehavior::One), }; } - let use_item = - make::use_(None, make::use_tree(path.clone(), None, alias, false)).clone_for_update(); + let mut use_tree = make::use_tree(path.clone(), None, alias, false); + if mb == Some(MergeBehavior::One) && use_tree.path().is_some() { + use_tree = use_tree.clone_for_update(); + use_tree.wrap_in_tree_list(); + } + let use_item = make::use_(None, use_tree).clone_for_update(); // merge into existing imports if possible if let Some(mb) = mb { @@ -216,7 +236,7 @@ fn insert_use_with_alias_option( // either we weren't allowed to merge or there is no import that fits the merge conditions // so look for the place we have to insert to - insert_use_(scope, &path, cfg.group, use_item); + insert_use_(scope, use_item, cfg.group); } pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option> { @@ -248,15 +268,18 @@ enum ImportGroup { ThisCrate, ThisModule, SuperModule, + One, } impl ImportGroup { - fn new(path: &ast::Path) -> ImportGroup { - let default = ImportGroup::ExternCrate; + fn new(use_tree: &ast::UseTree) -> ImportGroup { + if use_tree.path().is_none() && use_tree.use_tree_list().is_some() { + return ImportGroup::One; + } - let first_segment = match path.first_segment() { - Some(it) => it, - None => return default, + let Some(first_segment) = use_tree.path().as_ref().and_then(ast::Path::first_segment) + else { + return ImportGroup::ExternCrate; }; let kind = first_segment.kind().unwrap_or(PathSegmentKind::SelfKw); @@ -284,6 +307,7 @@ enum ImportGranularityGuess { ModuleOrItem, Crate, CrateOrModule, + One, } fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { @@ -303,12 +327,24 @@ fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { } .filter_map(use_stmt); let mut res = ImportGranularityGuess::Unknown; - let (mut prev, mut prev_vis, mut prev_attrs) = match use_stmts.next() { - Some(it) => it, - None => return res, - }; + let Some((mut prev, mut prev_vis, mut prev_attrs)) = use_stmts.next() else { return res }; + + let is_tree_one_style = + |use_tree: &ast::UseTree| use_tree.path().is_none() && use_tree.use_tree_list().is_some(); + let mut seen_one_style_groups = Vec::new(); + loop { - if let Some(use_tree_list) = prev.use_tree_list() { + if is_tree_one_style(&prev) { + if res != ImportGranularityGuess::One { + if res != ImportGranularityGuess::Unknown { + // This scope has a mix of one-style and other style imports. + break ImportGranularityGuess::Unknown; + } + + res = ImportGranularityGuess::One; + seen_one_style_groups.push((prev_vis.clone(), prev_attrs.clone())); + } + } else if let Some(use_tree_list) = prev.use_tree_list() { if use_tree_list.use_trees().any(|tree| tree.use_tree_list().is_some()) { // Nested tree lists can only occur in crate style, or with no proper style being enforced in the file. break ImportGranularityGuess::Crate; @@ -318,11 +354,22 @@ fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { } } - let (curr, curr_vis, curr_attrs) = match use_stmts.next() { - Some(it) => it, - None => break res, - }; - if eq_visibility(prev_vis, curr_vis.clone()) && eq_attrs(prev_attrs, curr_attrs.clone()) { + let Some((curr, curr_vis, curr_attrs)) = use_stmts.next() else { break res }; + if is_tree_one_style(&curr) { + if res != ImportGranularityGuess::One + || seen_one_style_groups.iter().any(|(prev_vis, prev_attrs)| { + eq_visibility(prev_vis.clone(), curr_vis.clone()) + && eq_attrs(prev_attrs.clone(), curr_attrs.clone()) + }) + { + // This scope has either a mix of one-style and other style imports or + // multiple one-style imports with the same visibility and attributes. + break ImportGranularityGuess::Unknown; + } + seen_one_style_groups.push((curr_vis.clone(), curr_attrs.clone())); + } else if eq_visibility(prev_vis, curr_vis.clone()) + && eq_attrs(prev_attrs, curr_attrs.clone()) + { if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) { if let Some((prev_prefix, _)) = common_prefix(&prev_path, &curr_path) { if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() { @@ -350,40 +397,33 @@ fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { } } -fn insert_use_( - scope: &ImportScope, - insert_path: &ast::Path, - group_imports: bool, - use_item: ast::Use, -) { +fn insert_use_(scope: &ImportScope, use_item: ast::Use, group_imports: bool) { let scope_syntax = scope.as_syntax_node(); - let group = ImportGroup::new(insert_path); + let insert_use_tree = + use_item.use_tree().expect("`use_item` should have a use tree for `insert_path`"); + let group = ImportGroup::new(&insert_use_tree); let path_node_iter = scope_syntax .children() .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node))) .flat_map(|(use_, node)| { let tree = use_.use_tree()?; - let path = tree.path()?; - let has_tl = tree.use_tree_list().is_some(); - Some((path, has_tl, node)) + Some((tree, node)) }); if group_imports { - // Iterator that discards anything thats not in the required grouping + // Iterator that discards anything that's not in the required grouping // This implementation allows the user to rearrange their import groups as this only takes the first group that fits let group_iter = path_node_iter .clone() - .skip_while(|(path, ..)| ImportGroup::new(path) != group) - .take_while(|(path, ..)| ImportGroup::new(path) == group); + .skip_while(|(use_tree, ..)| ImportGroup::new(use_tree) != group) + .take_while(|(use_tree, ..)| ImportGroup::new(use_tree) == group); // track the last element we iterated over, if this is still None after the iteration then that means we never iterated in the first place let mut last = None; // find the element that would come directly after our new import - let post_insert: Option<(_, _, SyntaxNode)> = group_iter + let post_insert: Option<(_, SyntaxNode)> = group_iter .inspect(|(.., node)| last = Some(node.clone())) - .find(|&(ref path, has_tl, _)| { - use_tree_path_cmp(insert_path, false, path, has_tl) != Ordering::Greater - }); + .find(|(use_tree, _)| use_tree_cmp(&insert_use_tree, use_tree) != Ordering::Greater); if let Some((.., node)) = post_insert { cov_mark::hit!(insert_group); @@ -402,7 +442,7 @@ fn insert_use_( // find the group that comes after where we want to insert let post_group = path_node_iter .inspect(|(.., node)| last = Some(node.clone())) - .find(|(p, ..)| ImportGroup::new(p) > group); + .find(|(use_tree, ..)| ImportGroup::new(use_tree) > group); if let Some((.., node)) = post_group { cov_mark::hit!(insert_group_new_group); ted::insert(ted::Position::before(&node), use_item.syntax()); @@ -420,7 +460,7 @@ fn insert_use_( } } else { // There exists a group, so append to the end of it - if let Some((_, _, node)) = path_node_iter.last() { + if let Some((_, node)) = path_node_iter.last() { cov_mark::hit!(insert_no_grouping_last); ted::insert(ted::Position::after(node), use_item.syntax()); return; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index a3abce8964247..6b0fecae26758 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -137,6 +137,16 @@ fn insert_start_indent() { use std::bar::B; use std::bar::C;", ); + check_none( + "std::bar::r#AA", + r" + use std::bar::B; + use std::bar::C;", + r" + use std::bar::r#AA; + use std::bar::B; + use std::bar::C;", + ); } #[test] @@ -173,7 +183,21 @@ fn insert_middle_indent() { use std::bar::EE; use std::bar::F; use std::bar::G;", - ) + ); + check_none( + "std::bar::r#EE", + r" + use std::bar::A; + use std::bar::D; + use std::bar::F; + use std::bar::G;", + r" + use std::bar::A; + use std::bar::D; + use std::bar::r#EE; + use std::bar::F; + use std::bar::G;", + ); } #[test] @@ -210,7 +234,21 @@ fn insert_end_indent() { use std::bar::F; use std::bar::G; use std::bar::ZZ;", - ) + ); + check_none( + "std::bar::r#ZZ", + r" + use std::bar::A; + use std::bar::D; + use std::bar::F; + use std::bar::G;", + r" + use std::bar::A; + use std::bar::D; + use std::bar::F; + use std::bar::G; + use std::bar::r#ZZ;", + ); } #[test] @@ -228,7 +266,21 @@ use std::bar::EE; use std::bar::{D, Z}; // example of weird imports due to user use std::bar::F; use std::bar::G;", - ) + ); + check_none( + "std::bar::r#EE", + r" +use std::bar::A; +use std::bar::{D, Z}; // example of weird imports due to user +use std::bar::F; +use std::bar::G;", + r" +use std::bar::A; +use std::bar::r#EE; +use std::bar::{D, Z}; // example of weird imports due to user +use std::bar::F; +use std::bar::G;", + ); } #[test] @@ -567,7 +619,9 @@ fn main() {}"#, #[test] fn merge_groups() { - check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};") + check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};"); + check_one("std::io", r"use {std::fmt};", r"use {std::{fmt, io}};"); + check_one("std::io", r"use std::fmt;", r"use {std::{fmt, io}};"); } #[test] @@ -577,12 +631,18 @@ fn merge_groups_last() { r"use std::fmt::{Result, Display};", r"use std::fmt::{Result, Display}; use std::io;", - ) + ); + check_one( + "std::io", + r"use {std::fmt::{Result, Display}};", + r"use {std::{fmt::{Display, Result}, io}};", + ); } #[test] fn merge_last_into_self() { check_module("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); + check_one("foo::bar::baz", r"use {foo::bar};", r"use {foo::bar::{self, baz}};"); } #[test] @@ -590,13 +650,32 @@ fn merge_groups_full() { check_crate( "std::io", r"use std::fmt::{Result, Display};", - r"use std::{fmt::{Result, Display}, io};", - ) + r"use std::{fmt::{Display, Result}, io};", + ); + check_one( + "std::io", + r"use {std::fmt::{Result, Display}};", + r"use {std::{fmt::{Display, Result}, io}};", + ); } #[test] fn merge_groups_long_full() { - check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Qux, Baz};") + check_crate( + "std::foo::bar::Baz", + r"use std::foo::bar::Qux;", + r"use std::foo::bar::{Baz, Qux};", + ); + check_crate( + "std::foo::bar::r#Baz", + r"use std::foo::bar::Qux;", + r"use std::foo::bar::{r#Baz, Qux};", + ); + check_one( + "std::foo::bar::Baz", + r"use {std::foo::bar::Qux};", + r"use {std::foo::bar::{Baz, Qux}};", + ); } #[test] @@ -604,7 +683,7 @@ fn merge_groups_long_last() { check_module( "std::foo::bar::Baz", r"use std::foo::bar::Qux;", - r"use std::foo::bar::{Qux, Baz};", + r"use std::foo::bar::{Baz, Qux};", ) } @@ -613,8 +692,18 @@ fn merge_groups_long_full_list() { check_crate( "std::foo::bar::Baz", r"use std::foo::bar::{Qux, Quux};", - r"use std::foo::bar::{Qux, Quux, Baz};", - ) + r"use std::foo::bar::{Baz, Quux, Qux};", + ); + check_crate( + "std::foo::bar::r#Baz", + r"use std::foo::bar::{Qux, Quux};", + r"use std::foo::bar::{r#Baz, Quux, Qux};", + ); + check_one( + "std::foo::bar::Baz", + r"use {std::foo::bar::{Qux, Quux}};", + r"use {std::foo::bar::{Baz, Quux, Qux}};", + ); } #[test] @@ -622,7 +711,7 @@ fn merge_groups_long_last_list() { check_module( "std::foo::bar::Baz", r"use std::foo::bar::{Qux, Quux};", - r"use std::foo::bar::{Qux, Quux, Baz};", + r"use std::foo::bar::{Baz, Quux, Qux};", ) } @@ -631,8 +720,18 @@ fn merge_groups_long_full_nested() { check_crate( "std::foo::bar::Baz", r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}, Baz};", - ) + r"use std::foo::bar::{quux::{Fez, Fizz}, Baz, Qux};", + ); + check_crate( + "std::foo::bar::r#Baz", + r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", + r"use std::foo::bar::{quux::{Fez, Fizz}, r#Baz, Qux};", + ); + check_one( + "std::foo::bar::Baz", + r"use {std::foo::bar::{Qux, quux::{Fez, Fizz}}};", + r"use {std::foo::bar::{quux::{Fez, Fizz}, Baz, Qux}};", + ); } #[test] @@ -650,8 +749,13 @@ fn merge_groups_full_nested_deep() { check_crate( "std::foo::bar::quux::Baz", r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz, Baz}};", - ) + r"use std::foo::bar::{quux::{Baz, Fez, Fizz}, Qux};", + ); + check_one( + "std::foo::bar::quux::Baz", + r"use {std::foo::bar::{Qux, quux::{Fez, Fizz}}};", + r"use {std::foo::bar::{quux::{Baz, Fez, Fizz}, Qux}};", + ); } #[test] @@ -659,7 +763,7 @@ fn merge_groups_full_nested_long() { check_crate( "std::foo::bar::Baz", r"use std::{foo::bar::Qux};", - r"use std::{foo::bar::{Qux, Baz}};", + r"use std::foo::bar::{Baz, Qux};", ); } @@ -668,7 +772,12 @@ fn merge_groups_last_nested_long() { check_crate( "std::foo::bar::Baz", r"use std::{foo::bar::Qux};", - r"use std::{foo::bar::{Qux, Baz}};", + r"use std::foo::bar::{Baz, Qux};", + ); + check_one( + "std::foo::bar::Baz", + r"use {std::{foo::bar::Qux}};", + r"use {std::foo::bar::{Baz, Qux}};", ); } @@ -679,7 +788,13 @@ fn merge_groups_skip_pub() { r"pub use std::fmt::{Result, Display};", r"pub use std::fmt::{Result, Display}; use std::io;", - ) + ); + check_one( + "std::io", + r"pub use {std::fmt::{Result, Display}};", + r"pub use {std::fmt::{Result, Display}}; +use {std::io};", + ); } #[test] @@ -689,7 +804,13 @@ fn merge_groups_skip_pub_crate() { r"pub(crate) use std::fmt::{Result, Display};", r"pub(crate) use std::fmt::{Result, Display}; use std::io;", - ) + ); + check_one( + "std::io", + r"pub(crate) use {std::fmt::{Result, Display}};", + r"pub(crate) use {std::fmt::{Result, Display}}; +use {std::io};", + ); } #[test] @@ -703,7 +824,17 @@ fn merge_groups_skip_attributed() { #[cfg(feature = "gated")] use std::fmt::{Result, Display}; use std::io; "#, - ) + ); + check_one( + "std::io", + r#" +#[cfg(feature = "gated")] use {std::fmt::{Result, Display}}; +"#, + r#" +#[cfg(feature = "gated")] use {std::fmt::{Result, Display}}; +use {std::io}; +"#, + ); } #[test] @@ -733,7 +864,7 @@ fn merge_mod_into_glob() { check_with_config( "token::TokenKind", r"use token::TokenKind::*;", - r"use token::TokenKind::{*, self};", + r"use token::TokenKind::{self, *};", &InsertUseConfig { granularity: ImportGranularity::Crate, enforce_granularity: true, @@ -742,7 +873,6 @@ fn merge_mod_into_glob() { skip_glob_imports: false, }, ) - // FIXME: have it emit `use token::TokenKind::{self, *}`? } #[test] @@ -750,7 +880,7 @@ fn merge_self_glob() { check_with_config( "self", r"use self::*;", - r"use self::{*, self};", + r"use self::{self, *};", &InsertUseConfig { granularity: ImportGranularity::Crate, enforce_granularity: true, @@ -759,7 +889,6 @@ fn merge_self_glob() { skip_glob_imports: false, }, ) - // FIXME: have it emit `use {self, *}`? } #[test] @@ -769,7 +898,7 @@ fn merge_glob() { r" use syntax::{SyntaxKind::*};", r" -use syntax::{SyntaxKind::{*, self}};", +use syntax::SyntaxKind::{self, *};", ) } @@ -778,7 +907,7 @@ fn merge_glob_nested() { check_crate( "foo::bar::quux::Fez", r"use foo::bar::{Baz, quux::*};", - r"use foo::bar::{Baz, quux::{*, Fez}};", + r"use foo::bar::{quux::{Fez, *}, Baz};", ) } @@ -787,7 +916,7 @@ fn merge_nested_considers_first_segments() { check_crate( "hir_ty::display::write_bounds_like_dyn_trait", r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", - r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", + r"use hir_ty::{autoderef, display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter}, method_resolution};", ); } @@ -867,6 +996,7 @@ fn guess_single() { check_guess(r"use foo::{baz::{qux, quux}, bar};", ImportGranularityGuess::Crate); check_guess(r"use foo::bar;", ImportGranularityGuess::Unknown); check_guess(r"use foo::bar::{baz, qux};", ImportGranularityGuess::CrateOrModule); + check_guess(r"use {foo::bar};", ImportGranularityGuess::One); } #[test] @@ -958,6 +1088,19 @@ use foo::{baz::{qux, quux}, bar}; ); } +#[test] +fn guess_one() { + check_guess( + r" +use { + frob::bar::baz, + foo::{baz::{qux, quux}, bar} +}; +", + ImportGranularityGuess::One, + ); +} + #[test] fn guess_skips_differing_vis() { check_guess( @@ -969,6 +1112,28 @@ pub use foo::bar::qux; ); } +#[test] +fn guess_one_differing_vis() { + check_guess( + r" +use {foo::bar::baz}; +pub use {foo::bar::qux}; +", + ImportGranularityGuess::One, + ); +} + +#[test] +fn guess_skips_multiple_one_style_same_vis() { + check_guess( + r" +use {foo::bar::baz}; +use {foo::bar::qux}; +", + ImportGranularityGuess::Unknown, + ); +} + #[test] fn guess_skips_differing_attrs() { check_guess( @@ -981,6 +1146,31 @@ pub use foo::bar::qux; ); } +#[test] +fn guess_one_differing_attrs() { + check_guess( + r" +pub use {foo::bar::baz}; +#[doc(hidden)] +pub use {foo::bar::qux}; +", + ImportGranularityGuess::One, + ); +} + +#[test] +fn guess_skips_multiple_one_style_same_attrs() { + check_guess( + r" +#[doc(hidden)] +use {foo::bar::baz}; +#[doc(hidden)] +use {foo::bar::qux}; +", + ImportGranularityGuess::Unknown, + ); +} + #[test] fn guess_grouping_matters() { check_guess( @@ -1021,7 +1211,7 @@ fn insert_with_renamed_import_complex_use() { use self::foo::{self, Foo as _, Bar}; "#, r#" -use self::foo::{self, Foo, Bar}; +use self::foo::{self, Bar, Foo}; "#, &InsertUseConfig { granularity: ImportGranularity::Crate, @@ -1098,6 +1288,10 @@ fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item) } +fn check_one(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { + check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::One) +} + fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { let use0 = ast::SourceFile::parse(ra_fixture0) .tree() diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index ff84e9ffaeec7..b153aafa0e179 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -2,9 +2,16 @@ use std::cmp::Ordering; use itertools::{EitherOrBoth, Itertools}; +use parser::T; +use stdx::is_upper_snake_case; use syntax::{ - ast::{self, AstNode, HasAttrs, HasVisibility, PathSegmentKind}, - ted, + algo, + ast::{ + self, edit_in_place::Removable, make, AstNode, HasAttrs, HasName, HasVisibility, + PathSegmentKind, + }, + ted::{self, Position}, + Direction, SyntaxElement, }; use crate::syntax_helpers::node_ext::vis_eq; @@ -16,12 +23,15 @@ pub enum MergeBehavior { Crate, /// Merge imports from the same module into a single use statement. Module, + /// Merge all imports into a single use statement as long as they have the same visibility + /// and attributes. + One, } impl MergeBehavior { fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool { match self { - MergeBehavior::Crate => true, + MergeBehavior::Crate | MergeBehavior::One => true, // only simple single segment paths are allowed MergeBehavior::Module => { tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1) @@ -50,6 +60,10 @@ pub fn try_merge_imports( let lhs_tree = lhs.use_tree()?; let rhs_tree = rhs.use_tree()?; try_merge_trees_mut(&lhs_tree, &rhs_tree, merge_behavior)?; + + // Ignore `None` result because normalization should not affect the merge result. + try_normalize_use_tree_mut(&lhs_tree, merge_behavior.into()); + Some(lhs) } @@ -63,25 +77,34 @@ pub fn try_merge_trees( let lhs = lhs.clone_subtree().clone_for_update(); let rhs = rhs.clone_subtree().clone_for_update(); try_merge_trees_mut(&lhs, &rhs, merge)?; + + // Ignore `None` result because normalization should not affect the merge result. + try_normalize_use_tree_mut(&lhs, merge.into()); + Some(lhs) } fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { - let lhs_path = lhs.path()?; - let rhs_path = rhs.path()?; - - let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; - if !(lhs.is_simple_path() - && rhs.is_simple_path() - && lhs_path == lhs_prefix - && rhs_path == rhs_prefix) - { - lhs.split_prefix(&lhs_prefix); - rhs.split_prefix(&rhs_prefix); + if merge == MergeBehavior::One { + lhs.wrap_in_tree_list(); + rhs.wrap_in_tree_list(); } else { - ted::replace(lhs.syntax(), rhs.syntax()); - // we can safely return here, in this case `recursive_merge` doesn't do anything - return Some(()); + let lhs_path = lhs.path()?; + let rhs_path = rhs.path()?; + + let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; + if !(lhs.is_simple_path() + && rhs.is_simple_path() + && lhs_path == lhs_prefix + && rhs_path == rhs_prefix) + { + lhs.split_prefix(&lhs_prefix); + rhs.split_prefix(&rhs_prefix); + } else { + ted::replace(lhs.syntax(), rhs.syntax()); + // we can safely return here, in this case `recursive_merge` doesn't do anything + return Some(()); + } } recursive_merge(lhs, rhs, merge) } @@ -97,20 +120,19 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) // same as a `filter` op). .map(|tree| merge.is_tree_allowed(&tree).then_some(tree)) .collect::>()?; - use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path())); + // Sorts the use trees similar to rustfmt's algorithm for ordering imports + // (see `use_tree_cmp` doc). + use_trees.sort_unstable_by(use_tree_cmp); for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) { if !merge.is_tree_allowed(&rhs_t) { return None; } - let rhs_path = rhs_t.path(); - match use_trees - .binary_search_by(|lhs_t| path_cmp_bin_search(lhs_t.path(), rhs_path.as_ref())) - { + match use_trees.binary_search_by(|lhs_t| use_tree_cmp_bin_search(lhs_t, &rhs_t)) { Ok(idx) => { let lhs_t = &mut use_trees[idx]; let lhs_path = lhs_t.path()?; - let rhs_path = rhs_path?; + let rhs_path = rhs_t.path()?; let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; if lhs_prefix == lhs_path && rhs_prefix == rhs_path { let tree_is_self = |tree: &ast::UseTree| { @@ -159,8 +181,11 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) { return None } - Err(idx) => { - use_trees.insert(idx, rhs_t.clone()); + Err(insert_idx) => { + use_trees.insert(insert_idx, rhs_t.clone()); + // We simply add the use tree to the end of tree list. Ordering of use trees + // and imports is done by the `try_normalize_*` functions. The sorted `use_trees` + // vec is only used for binary search. lhs.get_or_create_use_tree_list().add_use_tree(rhs_t); } } @@ -168,6 +193,295 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) Some(()) } +/// Style to follow when normalizing a use tree. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum NormalizationStyle { + /// Merges all descendant use tree lists with only one child use tree into their parent use tree. + /// + /// Examples: + /// - `foo::{bar::{Qux}}` -> `foo::bar::Qux` + /// - `foo::{bar::{self}}` -> `foo::bar` + /// - `{foo::bar}` -> `foo::bar` + Default, + /// Same as default but wraps the root use tree in a use tree list. + /// + /// Examples: + /// - `foo::{bar::{Qux}}` -> `{foo::bar::Qux}` + /// - `foo::{bar::{self}}` -> `{foo::bar}` + /// - `{foo::bar}` -> `{foo::bar}` + One, +} + +impl From for NormalizationStyle { + fn from(mb: MergeBehavior) -> Self { + match mb { + MergeBehavior::One => NormalizationStyle::One, + _ => NormalizationStyle::Default, + } + } +} + +/// Normalizes a use item by: +/// - Ordering all use trees +/// - Merging use trees with common prefixes +/// - Removing redundant braces based on the specified normalization style +/// (see [`NormalizationStyle`] doc) +/// +/// Examples: +/// +/// Using the "Default" normalization style +/// +/// - `foo::{bar::Qux, bar::{self}}` -> `foo::bar::{self, Qux}` +/// - `foo::bar::{self}` -> `foo::bar` +/// - `{foo::bar}` -> `foo::bar` +/// +/// Using the "One" normalization style +/// +/// - `foo::{bar::Qux, bar::{self}}` -> `{foo::bar::{self, Qux}}` +/// - `foo::bar::{self}` -> `{foo::bar}` +/// - `foo::bar` -> `{foo::bar}` +pub fn try_normalize_import(use_item: &ast::Use, style: NormalizationStyle) -> Option { + let use_item = use_item.clone_subtree().clone_for_update(); + try_normalize_use_tree_mut(&use_item.use_tree()?, style)?; + Some(use_item) +} + +/// Normalizes a use tree (see [`try_normalize_import`] doc). +pub fn try_normalize_use_tree( + use_tree: &ast::UseTree, + style: NormalizationStyle, +) -> Option { + let use_tree = use_tree.clone_subtree().clone_for_update(); + try_normalize_use_tree_mut(&use_tree, style)?; + Some(use_tree) +} + +pub fn try_normalize_use_tree_mut( + use_tree: &ast::UseTree, + style: NormalizationStyle, +) -> Option<()> { + if style == NormalizationStyle::One { + let mut modified = false; + modified |= use_tree.wrap_in_tree_list().is_some(); + modified |= recursive_normalize(use_tree, style).is_some(); + if !modified { + // Either the use tree was already normalized or its semantically empty. + return None; + } + } else { + recursive_normalize(use_tree, NormalizationStyle::Default)?; + } + Some(()) +} + +/// Recursively normalizes a use tree and its subtrees (if any). +fn recursive_normalize(use_tree: &ast::UseTree, style: NormalizationStyle) -> Option<()> { + let use_tree_list = use_tree.use_tree_list()?; + let merge_subtree_into_parent_tree = |single_subtree: &ast::UseTree| { + let merged_path = match (use_tree.path(), single_subtree.path()) { + (None, None) => None, + (Some(outer), None) => Some(outer), + (None, Some(inner)) if path_is_self(&inner) => None, + (None, Some(inner)) => Some(inner), + (Some(outer), Some(inner)) if path_is_self(&inner) => Some(outer), + (Some(outer), Some(inner)) => Some(make::path_concat(outer, inner).clone_for_update()), + }; + if merged_path.is_some() + || single_subtree.use_tree_list().is_some() + || single_subtree.star_token().is_some() + { + ted::remove_all_iter(use_tree.syntax().children_with_tokens()); + if let Some(path) = merged_path { + ted::insert_raw(Position::first_child_of(use_tree.syntax()), path.syntax()); + if single_subtree.use_tree_list().is_some() || single_subtree.star_token().is_some() + { + ted::insert_raw( + Position::last_child_of(use_tree.syntax()), + make::token(T![::]), + ); + } + } + if let Some(inner_use_tree_list) = single_subtree.use_tree_list() { + ted::insert_raw( + Position::last_child_of(use_tree.syntax()), + inner_use_tree_list.syntax(), + ); + } else if single_subtree.star_token().is_some() { + ted::insert_raw(Position::last_child_of(use_tree.syntax()), make::token(T![*])); + } else if let Some(rename) = single_subtree.rename() { + ted::insert_raw( + Position::last_child_of(use_tree.syntax()), + make::tokens::single_space(), + ); + ted::insert_raw(Position::last_child_of(use_tree.syntax()), rename.syntax()); + } + Some(()) + } else { + // Bail on semantically empty use trees. + None + } + }; + let one_style_tree_list = |subtree: &ast::UseTree| match ( + subtree.path().is_none() && subtree.star_token().is_none() && subtree.rename().is_none(), + subtree.use_tree_list(), + ) { + (true, tree_list) => tree_list, + _ => None, + }; + let add_element_to_list = |elem: SyntaxElement, elements: &mut Vec| { + if !elements.is_empty() { + elements.push(make::token(T![,]).into()); + elements.push(make::tokens::single_space().into()); + } + elements.push(elem); + }; + if let Some((single_subtree,)) = use_tree_list.use_trees().collect_tuple() { + if style == NormalizationStyle::One { + // Only normalize descendant subtrees if the normalization style is "one". + recursive_normalize(&single_subtree, NormalizationStyle::Default)?; + } else { + // Otherwise, merge the single subtree into it's parent (if possible) + // and then normalize the result. + merge_subtree_into_parent_tree(&single_subtree)?; + recursive_normalize(use_tree, style); + } + } else { + // Tracks whether any changes have been made to the use tree. + let mut modified = false; + + // Recursively un-nests (if necessary) and then normalizes each subtree in the tree list. + for subtree in use_tree_list.use_trees() { + if let Some(one_tree_list) = one_style_tree_list(&subtree) { + let mut elements = Vec::new(); + let mut one_tree_list_iter = one_tree_list.use_trees(); + let mut prev_skipped = Vec::new(); + loop { + let mut prev_skipped_iter = prev_skipped.into_iter(); + let mut curr_skipped = Vec::new(); + + while let Some(sub_sub_tree) = + one_tree_list_iter.next().or(prev_skipped_iter.next()) + { + if let Some(sub_one_tree_list) = one_style_tree_list(&sub_sub_tree) { + curr_skipped.extend(sub_one_tree_list.use_trees()); + } else { + modified |= + recursive_normalize(&sub_sub_tree, NormalizationStyle::Default) + .is_some(); + add_element_to_list( + sub_sub_tree.syntax().clone().into(), + &mut elements, + ); + } + } + + if curr_skipped.is_empty() { + // Un-nesting is complete. + break; + } + prev_skipped = curr_skipped; + } + + // Either removes the subtree (if its semantically empty) or replaces it with + // the un-nested elements. + if elements.is_empty() { + subtree.remove(); + } else { + ted::replace_with_many(subtree.syntax(), elements); + } + modified = true; + } else { + modified |= recursive_normalize(&subtree, NormalizationStyle::Default).is_some(); + } + } + + // Merge all merge-able subtrees. + let mut tree_list_iter = use_tree_list.use_trees(); + let mut anchor = tree_list_iter.next()?; + let mut prev_skipped = Vec::new(); + loop { + let mut has_merged = false; + let mut prev_skipped_iter = prev_skipped.into_iter(); + let mut next_anchor = None; + let mut curr_skipped = Vec::new(); + + while let Some(candidate) = tree_list_iter.next().or(prev_skipped_iter.next()) { + let result = try_merge_trees_mut(&anchor, &candidate, MergeBehavior::Crate); + if result.is_some() { + // Remove merged subtree. + candidate.remove(); + has_merged = true; + } else if next_anchor.is_none() { + next_anchor = Some(candidate); + } else { + curr_skipped.push(candidate); + } + } + + if has_merged { + // Normalize the merge result. + recursive_normalize(&anchor, NormalizationStyle::Default); + modified = true; + } + + let (Some(next_anchor), true) = (next_anchor, !curr_skipped.is_empty()) else { + // Merging is complete. + break; + }; + + // Try to merge the remaining subtrees in the next iteration. + anchor = next_anchor; + prev_skipped = curr_skipped; + } + + let mut subtrees: Vec<_> = use_tree_list.use_trees().collect(); + // Merge the remaining subtree into its parent, if its only one and + // the normalization style is not "one". + if subtrees.len() == 1 && style != NormalizationStyle::One { + modified |= merge_subtree_into_parent_tree(&subtrees[0]).is_some(); + } + // Order the remaining subtrees (if necessary). + if subtrees.len() > 1 { + let mut did_sort = false; + subtrees.sort_unstable_by(|a, b| { + let order = use_tree_cmp_bin_search(a, b); + if !did_sort && order == Ordering::Less { + did_sort = true; + } + order + }); + if did_sort { + let start = use_tree_list + .l_curly_token() + .and_then(|l_curly| algo::non_trivia_sibling(l_curly.into(), Direction::Next)) + .filter(|it| it.kind() != T!['}']); + let end = use_tree_list + .r_curly_token() + .and_then(|r_curly| algo::non_trivia_sibling(r_curly.into(), Direction::Prev)) + .filter(|it| it.kind() != T!['{']); + if let Some((start, end)) = start.zip(end) { + // Attempt to insert elements while preserving preceding and trailing trivia. + let mut elements = Vec::new(); + for subtree in subtrees { + add_element_to_list(subtree.syntax().clone().into(), &mut elements); + } + ted::replace_all(start..=end, elements); + } else { + let new_use_tree_list = make::use_tree_list(subtrees).clone_for_update(); + ted::replace(use_tree_list.syntax(), new_use_tree_list.syntax()); + } + modified = true; + } + } + + if !modified { + // Either the use tree was already normalized or its semantically empty. + return None; + } + } + Some(()) +} + /// Traverses both paths until they differ, returning the common prefix of both. pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> { let mut res = None; @@ -190,89 +504,177 @@ pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast } } -/// Orders paths in the following way: -/// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers -// FIXME: rustfmt sorts lowercase idents before uppercase, in general we want to have the same ordering rustfmt has -// which is `self` and `super` first, then identifier imports with lowercase ones first, then glob imports and at last list imports. -// Example foo::{self, foo, baz, Baz, Qux, *, {Bar}} -fn path_cmp_for_sort(a: Option, b: Option) -> Ordering { - match (a, b) { - (None, None) => Ordering::Equal, - (None, Some(_)) => Ordering::Less, - (Some(_), None) => Ordering::Greater, - (Some(ref a), Some(ref b)) => match (path_is_self(a), path_is_self(b)) { +/// Use tree comparison func for binary searching for merging. +fn use_tree_cmp_bin_search(lhs: &ast::UseTree, rhs: &ast::UseTree) -> Ordering { + let lhs_is_simple_path = lhs.is_simple_path() && lhs.rename().is_none(); + let rhs_is_simple_path = rhs.is_simple_path() && rhs.rename().is_none(); + match ( + lhs.path().as_ref().and_then(ast::Path::first_segment), + rhs.path().as_ref().and_then(ast::Path::first_segment), + ) { + (None, None) => match (lhs_is_simple_path, rhs_is_simple_path) { (true, true) => Ordering::Equal, (true, false) => Ordering::Less, (false, true) => Ordering::Greater, - (false, false) => path_cmp_short(a, b), + (false, false) => use_tree_cmp_by_tree_list_glob_or_alias(lhs, rhs, false), }, + (Some(_), None) if !rhs_is_simple_path => Ordering::Less, + (Some(_), None) => Ordering::Greater, + (None, Some(_)) if !lhs_is_simple_path => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(a), Some(b)) => path_segment_cmp(&a, &b), } } -/// Path comparison func for binary searching for merging. -fn path_cmp_bin_search(lhs: Option, rhs: Option<&ast::Path>) -> Ordering { - match (lhs.as_ref().and_then(ast::Path::first_segment), rhs.and_then(ast::Path::first_segment)) - { - (None, None) => Ordering::Equal, - (None, Some(_)) => Ordering::Less, +/// Orders use trees following `rustfmt`'s algorithm for ordering imports, which is `self`, `super` +/// and `crate` first, then identifier imports with lowercase ones first and upper snake case +/// (e.g. UPPER_SNAKE_CASE) ones last, then glob imports, and at last list imports. +/// +/// Example: `foo::{self, baz, foo, Baz, Qux, FOO_BAZ, *, {Bar}}` +/// Ref: . +pub(super) fn use_tree_cmp(a: &ast::UseTree, b: &ast::UseTree) -> Ordering { + let a_is_simple_path = a.is_simple_path() && a.rename().is_none(); + let b_is_simple_path = b.is_simple_path() && b.rename().is_none(); + match (a.path(), b.path()) { + (None, None) => match (a_is_simple_path, b_is_simple_path) { + (true, true) => Ordering::Equal, + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + (false, false) => use_tree_cmp_by_tree_list_glob_or_alias(a, b, true), + }, + (Some(_), None) if !b_is_simple_path => Ordering::Less, (Some(_), None) => Ordering::Greater, - (Some(ref a), Some(ref b)) => path_segment_cmp(a, b), + (None, Some(_)) if !a_is_simple_path => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(a_path), Some(b_path)) => { + // cmp_by would be useful for us here but that is currently unstable + // cmp doesn't work due the lifetimes on text's return type + a_path + .segments() + .zip_longest(b_path.segments()) + .find_map(|zipped| match zipped { + EitherOrBoth::Both(a_segment, b_segment) => { + match path_segment_cmp(&a_segment, &b_segment) { + Ordering::Equal => None, + ord => Some(ord), + } + } + EitherOrBoth::Left(_) if b_is_simple_path => Some(Ordering::Greater), + EitherOrBoth::Left(_) => Some(Ordering::Less), + EitherOrBoth::Right(_) if a_is_simple_path => Some(Ordering::Less), + EitherOrBoth::Right(_) => Some(Ordering::Greater), + }) + .unwrap_or_else(|| use_tree_cmp_by_tree_list_glob_or_alias(a, b, true)) + } } } -/// Short circuiting comparison, if both paths are equal until one of them ends they are considered -/// equal -fn path_cmp_short(a: &ast::Path, b: &ast::Path) -> Ordering { - let a = a.segments(); - let b = b.segments(); - // cmp_by would be useful for us here but that is currently unstable - // cmp doesn't work due the lifetimes on text's return type - a.zip(b) - .find_map(|(a, b)| match path_segment_cmp(&a, &b) { - Ordering::Equal => None, - ord => Some(ord), - }) - .unwrap_or(Ordering::Equal) +fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { + match (a.kind(), b.kind()) { + (None, None) => Ordering::Equal, + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + // self + (Some(PathSegmentKind::SelfKw), Some(PathSegmentKind::SelfKw)) => Ordering::Equal, + (Some(PathSegmentKind::SelfKw), _) => Ordering::Less, + (_, Some(PathSegmentKind::SelfKw)) => Ordering::Greater, + // super + (Some(PathSegmentKind::SuperKw), Some(PathSegmentKind::SuperKw)) => Ordering::Equal, + (Some(PathSegmentKind::SuperKw), _) => Ordering::Less, + (_, Some(PathSegmentKind::SuperKw)) => Ordering::Greater, + // crate + (Some(PathSegmentKind::CrateKw), Some(PathSegmentKind::CrateKw)) => Ordering::Equal, + (Some(PathSegmentKind::CrateKw), _) => Ordering::Less, + (_, Some(PathSegmentKind::CrateKw)) => Ordering::Greater, + // identifiers (everything else is treated as an identifier). + _ => { + match ( + a.name_ref().as_ref().map(ast::NameRef::text), + b.name_ref().as_ref().map(ast::NameRef::text), + ) { + (None, None) => Ordering::Equal, + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(a_name), Some(b_name)) => { + // snake_case < CamelCase < UPPER_SNAKE_CASE + let a_text = a_name.as_str().trim_start_matches("r#"); + let b_text = b_name.as_str().trim_start_matches("r#"); + if a_text.starts_with(char::is_lowercase) + && b_text.starts_with(char::is_uppercase) + { + return Ordering::Less; + } + if a_text.starts_with(char::is_uppercase) + && b_text.starts_with(char::is_lowercase) + { + return Ordering::Greater; + } + if !is_upper_snake_case(a_text) && is_upper_snake_case(b_text) { + return Ordering::Less; + } + if is_upper_snake_case(a_text) && !is_upper_snake_case(b_text) { + return Ordering::Greater; + } + a_text.cmp(b_text) + } + } + } + } } -/// Compares two paths, if one ends earlier than the other the has_tl parameters decide which is -/// greater as a path that has a tree list should be greater, while one that just ends without -/// a tree list should be considered less. -pub(super) fn use_tree_path_cmp( - a: &ast::Path, - a_has_tl: bool, - b: &ast::Path, - b_has_tl: bool, +/// Orders for use trees with equal paths (see `use_tree_cmp` for details about use tree ordering). +/// +/// If the `strict` parameter is set to true and both trees have tree lists, the tree lists are +/// ordered by calling `use_tree_cmp` on their "sub-tree" pairs until either the tie is broken +/// or tree list equality is confirmed, otherwise (i.e. if either `strict` is false or at least +/// one of the trees does *not* have tree list), this potentially recursive step is skipped, +/// and only the presence of a glob pattern or an alias is used to determine the ordering. +fn use_tree_cmp_by_tree_list_glob_or_alias( + a: &ast::UseTree, + b: &ast::UseTree, + strict: bool, ) -> Ordering { - let a_segments = a.segments(); - let b_segments = b.segments(); - // cmp_by would be useful for us here but that is currently unstable - // cmp doesn't work due the lifetimes on text's return type - a_segments - .zip_longest(b_segments) - .find_map(|zipped| match zipped { - EitherOrBoth::Both(ref a, ref b) => match path_segment_cmp(a, b) { - Ordering::Equal => None, - ord => Some(ord), - }, - EitherOrBoth::Left(_) if !b_has_tl => Some(Ordering::Greater), - EitherOrBoth::Left(_) => Some(Ordering::Less), - EitherOrBoth::Right(_) if !a_has_tl => Some(Ordering::Less), - EitherOrBoth::Right(_) => Some(Ordering::Greater), - }) - .unwrap_or(Ordering::Equal) -} + let cmp_by_glob_or_alias = || match (a.star_token().is_some(), b.star_token().is_some()) { + (true, false) => Ordering::Greater, + (false, true) => Ordering::Less, + _ => match (a.rename(), b.rename()) { + (None, None) => Ordering::Equal, + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(a_rename), Some(b_rename)) => a_rename + .name() + .as_ref() + .map(ast::Name::text) + .as_ref() + .map_or("_", |a_name| a_name.as_str().trim_start_matches("r#")) + .cmp( + b_rename + .name() + .as_ref() + .map(ast::Name::text) + .as_ref() + .map_or("_", |b_name| b_name.as_str().trim_start_matches("r#")), + ), + }, + }; -fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { - let a = a.kind().and_then(|kind| match kind { - PathSegmentKind::Name(name_ref) => Some(name_ref), - _ => None, - }); - let b = b.kind().and_then(|kind| match kind { - PathSegmentKind::Name(name_ref) => Some(name_ref), - _ => None, - }); - a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text)) + match (a.use_tree_list(), b.use_tree_list()) { + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(a_list), Some(b_list)) if strict => a_list + .use_trees() + .zip_longest(b_list.use_trees()) + .find_map(|zipped| match zipped { + EitherOrBoth::Both(a_tree, b_tree) => match use_tree_cmp(&a_tree, &b_tree) { + Ordering::Equal => None, + ord => Some(ord), + }, + EitherOrBoth::Left(_) => Some(Ordering::Greater), + EitherOrBoth::Right(_) => Some(Ordering::Less), + }) + .unwrap_or_else(cmp_by_glob_or_alias), + _ => cmp_by_glob_or_alias(), + } } pub fn eq_visibility(vis0: Option, vis1: Option) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs index 432f1d745d205..1b6f650768b9e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs @@ -20,14 +20,9 @@ pub fn items_with_name<'a>( name: NameToImport, assoc_item_search: AssocSearchMode, ) -> impl Iterator + 'a { - let _p = profile::span("items_with_name").detail(|| { - format!( - "Name: {}, crate: {:?}, assoc items: {:?}", - name.text(), - assoc_item_search, - krate.display_name(sema.db).map(|name| name.to_string()), - ) - }); + let krate_name = krate.display_name(sema.db).map(|name| name.to_string()); + let _p = tracing::span!(tracing::Level::INFO, "items_with_name", name = name.text(), assoc_item_search = ?assoc_item_search, crate = ?krate_name) + .entered(); let prefix = matches!(name, NameToImport::Prefix(..)); let (local_query, external_query) = match name { @@ -77,7 +72,7 @@ fn find_items<'a>( local_query: symbol_index::Query, external_query: import_map::Query, ) -> impl Iterator + 'a { - let _p = profile::span("find_items"); + let _p = tracing::span!(tracing::Level::INFO, "find_items").entered(); let db = sema.db; // NOTE: `external_query` includes `assoc_item_search`, so we don't need to diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index eae23e9548240..2881748dd477e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -9,6 +9,7 @@ mod apply_change; pub mod active_parameter; pub mod assists; pub mod defs; +pub mod documentation; pub mod famous_defs; pub mod helpers; pub mod items_locator; @@ -22,7 +23,6 @@ pub mod symbol_index; pub mod traits; pub mod ty_filter; pub mod use_trivial_constructor; -pub mod documentation; pub mod imports { pub mod import_assets; @@ -35,10 +35,10 @@ pub mod generated { } pub mod syntax_helpers { - pub mod node_ext; - pub mod insert_whitespace_into_node; pub mod format_string; pub mod format_string_exprs; + pub mod insert_whitespace_into_node; + pub mod node_ext; pub use parser::LexedStr; } @@ -99,21 +99,21 @@ impl fmt::Debug for RootDatabase { impl Upcast for RootDatabase { #[inline] fn upcast(&self) -> &(dyn ExpandDatabase + 'static) { - &*self + self } } impl Upcast for RootDatabase { #[inline] fn upcast(&self) -> &(dyn DefDatabase + 'static) { - &*self + self } } impl Upcast for RootDatabase { #[inline] fn upcast(&self) -> &(dyn HirDatabase + 'static) { - &*self + self } } @@ -217,15 +217,11 @@ impl RootDatabase { hir_db::FileItemTreeQuery hir_db::CrateDefMapQueryQuery hir_db::BlockDefMapQuery - hir_db::StructDataQuery hir_db::StructDataWithDiagnosticsQuery - hir_db::UnionDataQuery hir_db::UnionDataWithDiagnosticsQuery hir_db::EnumDataQuery - hir_db::EnumDataWithDiagnosticsQuery - hir_db::ImplDataQuery + hir_db::EnumVariantDataWithDiagnosticsQuery hir_db::ImplDataWithDiagnosticsQuery - hir_db::TraitDataQuery hir_db::TraitDataWithDiagnosticsQuery hir_db::TraitAliasDataQuery hir_db::TypeAliasDataQuery @@ -239,9 +235,7 @@ impl RootDatabase { hir_db::BodyQuery hir_db::ExprScopesQuery hir_db::GenericParamsQuery - hir_db::VariantsAttrsQuery hir_db::FieldsAttrsQuery - hir_db::VariantsAttrsSourceMapQuery hir_db::FieldsAttrsSourceMapQuery hir_db::AttrsQuery hir_db::CrateLangItemsQuery @@ -283,7 +277,7 @@ impl RootDatabase { // hir_db::InternImplTraitIdQuery // hir_db::InternTypeOrConstParamIdQuery // hir_db::InternClosureQuery - // hir_db::InternGeneratorQuery + // hir_db::InternCoroutineQuery hir_db::AssociatedTyDataQuery hir_db::TraitDatumQuery hir_db::StructDatumQuery @@ -420,6 +414,6 @@ impl SnippetCap { #[cfg(test)] mod tests { - mod sourcegen_lints; mod line_index; + mod sourcegen_lints; } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 47bcaae259b41..3862acc2af4da 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -381,7 +381,7 @@ impl Ctx<'_> { true, ) .ok()?; - let ast_ty = make::ty(&ty_str).clone_for_update(); + let ast_ty = make::ty(ty_str).clone_for_update(); if let Some(adt) = ty.as_adt() { if let ast::Type::PathType(path_ty) = &ast_ty { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index f694f7160dea4..032b8338ab85d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -71,14 +71,17 @@ impl Definition { &self, sema: &Semantics<'_, RootDatabase>, new_name: &str, + rename_external: bool, ) -> Result { // self.krate() returns None if // self is a built-in attr, built-in type or tool module. // it is not allowed for these defs to be renamed. // cases where self.krate() is None is handled below. if let Some(krate) = self.krate(sema.db) { - if !krate.origin(sema.db).is_local() { - bail!("Cannot rename a non-local definition.") + // Can we not rename non-local items? + // Then bail if non-local + if !rename_external && !krate.origin(sema.db).is_local() { + bail!("Cannot rename a non-local definition as the config for it is disabled") } } @@ -104,7 +107,7 @@ impl Definition { /// renamed and extern crate names will report its range, though a rename will introduce /// an alias instead. pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option { - let syn_ctx_is_root = |(range, ctx): (_, SyntaxContextId)| ctx.is_root().then(|| range); + let syn_ctx_is_root = |(range, ctx): (_, SyntaxContextId)| ctx.is_root().then_some(range); let res = match self { Definition::Macro(mac) => { let src = mac.source(sema.db)?; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index e2b20ef92fc43..006d8882c11e0 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -134,6 +134,7 @@ pub enum ReferenceCategory { // FIXME: Some day should be able to search in doc comments. Would probably // need to switch from enum to bitflags then? // DocComment + Test, } /// Generally, `search_scope` returns files that might contain references for the element. @@ -273,7 +274,7 @@ impl IntoIterator for SearchScope { impl Definition { fn search_scope(&self, db: &RootDatabase) -> SearchScope { - let _p = profile::span("search_scope"); + let _p = tracing::span!(tracing::Level::INFO, "search_scope").entered(); if let Definition::BuiltinType(_) = self { return SearchScope::crate_graph(db); @@ -303,14 +304,18 @@ impl Definition { DefWithBody::InTypeConst(_) => return SearchScope::empty(), }; return match def { - Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)), + Some(def) => SearchScope::file_range( + def.as_ref().original_file_range_with_macro_call_body(db), + ), None => SearchScope::single_file(file_id), }; } if let Definition::SelfType(impl_) = self { return match impl_.source(db).map(|src| src.syntax().cloned()) { - Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)), + Some(def) => SearchScope::file_range( + def.as_ref().original_file_range_with_macro_call_body(db), + ), None => SearchScope::single_file(file_id), }; } @@ -327,7 +332,9 @@ impl Definition { hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), }; return match def { - Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)), + Some(def) => SearchScope::file_range( + def.as_ref().original_file_range_with_macro_call_body(db), + ), None => SearchScope::single_file(file_id), }; } @@ -435,7 +442,7 @@ impl<'a> FindUsages<'a> { } pub fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) { - let _p = profile::span("FindUsages:search"); + let _p = tracing::span!(tracing::Level::INFO, "FindUsages:search").entered(); let sema = self.sema; let search_scope = { @@ -536,14 +543,12 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the items name for offset in match_indices(&text, finder, search_range) { - tree.token_at_offset(offset).into_iter().for_each(|token| { + tree.token_at_offset(offset).for_each(|token| { let Some(str_token) = ast::String::cast(token.clone()) else { return }; if let Some((range, nameres)) = sema.check_for_format_args_template(token, offset) { - if self.found_format_args_ref(file_id, range, str_token, nameres, sink) { - return; - } + if self.found_format_args_ref(file_id, range, str_token, nameres, sink) {} } }); @@ -745,7 +750,7 @@ impl<'a> FindUsages<'a> { let reference = FileReference { range, name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(&def, name_ref), + category: ReferenceCategory::new(self.sema, &def, name_ref), }; sink(file_id, reference) } @@ -761,7 +766,7 @@ impl<'a> FindUsages<'a> { let reference = FileReference { range, name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(&def, name_ref), + category: ReferenceCategory::new(self.sema, &def, name_ref), }; sink(file_id, reference) } @@ -771,7 +776,7 @@ impl<'a> FindUsages<'a> { let reference = FileReference { range, name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(&def, name_ref), + category: ReferenceCategory::new(self.sema, &def, name_ref), }; sink(file_id, reference) } else { @@ -785,10 +790,10 @@ impl<'a> FindUsages<'a> { let local = Definition::Local(local); let access = match self.def { Definition::Field(_) if field == self.def => { - ReferenceCategory::new(&field, name_ref) + ReferenceCategory::new(self.sema, &field, name_ref) } Definition::Local(_) if local == self.def => { - ReferenceCategory::new(&local, name_ref) + ReferenceCategory::new(self.sema, &local, name_ref) } _ => return false, }; @@ -873,7 +878,15 @@ fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option Option { + fn new( + sema: &Semantics<'_, RootDatabase>, + def: &Definition, + r: &ast::NameRef, + ) -> Option { + if is_name_ref_in_test(sema, r) { + return Some(ReferenceCategory::Test); + } + // Only Locals and Fields have accesses for now. if !matches!(def, Definition::Local(_) | Definition::Field(_)) { return is_name_ref_in_import(r).then_some(ReferenceCategory::Import); @@ -912,3 +925,10 @@ fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool { .and_then(|it| it.parent_path().top_path().syntax().parent()) .map_or(false, |it| it.kind() == SyntaxKind::USE_TREE) } + +fn is_name_ref_in_test(sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameRef) -> bool { + name_ref.syntax().ancestors().any(|node| match ast::Fn::cast(node) { + Some(it) => sema.to_def(&it).map_or(false, |func| func.is_test(sema.db)), + None => false, + }) +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index c2e95ca860cab..92c09089e1f13 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -124,7 +124,7 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast Arc { - let _p = profile::span("library_symbols"); + let _p = tracing::span!(tracing::Level::INFO, "library_symbols").entered(); let mut symbol_collector = SymbolCollector::new(db.upcast()); @@ -142,14 +142,14 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar } fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc { - let _p = profile::span("module_symbols"); + let _p = tracing::span!(tracing::Level::INFO, "module_symbols").entered(); let symbols = SymbolCollector::collect_module(db.upcast(), module); Arc::new(SymbolIndex::new(symbols)) } pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc]> { - let _p = profile::span("crate_symbols"); + let _p = tracing::span!(tracing::Level::INFO, "crate_symbols").entered(); krate.modules(db.upcast()).into_iter().map(|module| db.module_symbols(module)).collect() } @@ -200,7 +200,7 @@ impl std::ops::Deref for Snap { // | VS Code | kbd:[Ctrl+T] // |=== pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { - let _p = profile::span("world_symbols").detail(|| query.query.clone()); + let _p = tracing::span!(tracing::Level::INFO, "world_symbols", query = ?query.query).entered(); let indices: Vec<_> = if query.libs { db.library_roots() @@ -320,7 +320,7 @@ impl Query { indices: &'sym [Arc], cb: impl FnMut(&'sym FileSymbol), ) { - let _p = profile::span("symbol_index::Query::search"); + let _p = tracing::span!(tracing::Level::INFO, "symbol_index::Query::search").entered(); let mut op = fst::map::OpBuilder::new(); match self.mode { SearchMode::Exact => { @@ -329,7 +329,7 @@ impl Query { for index in indices.iter() { op = op.add(index.map.search(&automaton)); } - self.search_maps(&indices, op.union(), cb) + self.search_maps(indices, op.union(), cb) } SearchMode::Fuzzy => { let automaton = fst::automaton::Subsequence::new(&self.lowercased); @@ -337,7 +337,7 @@ impl Query { for index in indices.iter() { op = op.add(index.map.search(&automaton)); } - self.search_maps(&indices, op.union(), cb) + self.search_maps(indices, op.union(), cb) } SearchMode::Prefix => { let automaton = fst::automaton::Str::new(&self.lowercased).starts_with(); @@ -345,7 +345,7 @@ impl Query { for index in indices.iter() { op = op.add(index.map.search(&automaton)); } - self.search_maps(&indices, op.union(), cb) + self.search_maps(indices, op.union(), cb) } } } @@ -383,10 +383,10 @@ impl Query { } fn matches_assoc_mode(&self, is_trait_assoc_item: bool) -> bool { - match (is_trait_assoc_item, self.assoc_mode) { - (true, AssocSearchMode::Exclude) | (false, AssocSearchMode::AssocItemsOnly) => false, - _ => true, - } + !matches!( + (is_trait_assoc_item, self.assoc_mode), + (true, AssocSearchMode::Exclude) | (false, AssocSearchMode::AssocItemsOnly) + ) } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml index 3ed48457a2842..69768041389ac 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml @@ -16,6 +16,7 @@ cov-mark = "2.0.0-pre.1" either.workspace = true itertools.workspace = true serde_json.workspace = true +tracing.workspace = true once_cell = "1.17.0" # local deps @@ -39,4 +40,4 @@ sourcegen.workspace = true in-rust-tree = [] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index 4910054038821..c25b0a7bf7d5a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -17,7 +17,7 @@ pub(crate) fn break_outside_of_loop( ctx, DiagnosticCode::RustcHardError("E0268"), message, - d.expr.clone().map(|it| it.into()), + d.expr.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index e1e5db91c54ce..05fb1c29b3137 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -13,7 +13,7 @@ pub(crate) fn expected_function( ctx, DiagnosticCode::RustcHardError("E0618"), format!("expected function, found {}", d.found.display(ctx.sema.db)), - d.call.clone().map(|it| it.into()), + d.call.map(|it| it.into()), ) .experimental() } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs index 3b2e15a17887b..9f754f9c6fcaa 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -31,7 +31,7 @@ pub(crate) fn inactive_code( let res = Diagnostic::new( DiagnosticCode::Ra("inactive-code", Severity::WeakWarning), message, - ctx.sema.diagnostics_display_range(d.node.clone()), + ctx.sema.diagnostics_display_range(d.node), ) .with_unused(true); Some(res) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs index 4afb4db03bda5..3b4d400912fc0 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs @@ -9,8 +9,8 @@ pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentI Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0210"), - format!("cannot define inherent `impl` for foreign type"), - InFile::new(d.file_id, d.impl_.clone().into()), + "cannot define inherent `impl` for foreign type".to_string(), + InFile::new(d.file_id, d.impl_.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 0f12e814ba39d..f5a6aa11979dc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -27,7 +27,7 @@ pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas "{} `{}` should have {} name, e.g. `{}`", d.ident_type, d.ident_text, d.expected_case, d.suggested_text ), - InFile::new(d.file, d.ident.clone().into()), + InFile::new(d.file, d.ident.into()), ) .with_fixes(fixes(ctx, d)) } @@ -43,7 +43,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option, d: &hir::InvalidDeriveTarget, ) -> Diagnostic { - let display_range = ctx.sema.diagnostics_display_range(d.node.clone()); + let display_range = ctx.sema.diagnostics_display_range(d.node); Diagnostic::new( DiagnosticCode::RustcHardError("E0774"), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index 099de4528d468..fc5c715981f50 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -20,7 +20,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic { // Use more accurate position if available. let display_range = - ctx.resolve_precise_location(&d.node.clone().map(|it| it.syntax_node_ptr()), d.name); + ctx.resolve_precise_location(&d.node.map(|it| it.syntax_node_ptr()), d.name); Diagnostic::new( DiagnosticCode::Ra("macro-def-error", Severity::Error), d.message.clone(), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs index 6202d15853967..0e47fff6f93bb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs @@ -7,7 +7,7 @@ pub(crate) fn malformed_derive( ctx: &DiagnosticsContext<'_>, d: &hir::MalformedDerive, ) -> Diagnostic { - let display_range = ctx.sema.diagnostics_display_range(d.node.clone()); + let display_range = ctx.sema.diagnostics_display_range(d.node); Diagnostic::new( DiagnosticCode::RustcHardError("E0777"), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index 8296018022cb2..66ebf593505d2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -3,7 +3,7 @@ use hir::InFile; use ide_db::base_db::FileRange; use syntax::{ ast::{self, HasArgList}, - AstNode, SyntaxNodePtr, + AstNode, AstPtr, }; use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -24,7 +24,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count( Diagnostic::new( DiagnosticCode::RustcHardError("E0023"), message, - invalid_args_range(ctx, d.expr_or_pat.clone().map(Into::into), d.expected, d.found), + invalid_args_range(ctx, d.expr_or_pat, d.expected, d.found), ) } @@ -40,17 +40,17 @@ pub(crate) fn mismatched_arg_count( Diagnostic::new( DiagnosticCode::RustcHardError("E0107"), message, - invalid_args_range(ctx, d.call_expr.clone().map(Into::into), d.expected, d.found), + invalid_args_range(ctx, d.call_expr.map(AstPtr::wrap_left), d.expected, d.found), ) } fn invalid_args_range( ctx: &DiagnosticsContext<'_>, - source: InFile, + source: InFile>>, expected: usize, found: usize, ) -> FileRange { - adjusted_display_range::>(ctx, source, &|expr| { + adjusted_display_range(ctx, source, &|expr| { let (text_range, r_paren_token, expected_arg) = match expr { Either::Left(ast::Expr::CallExpr(call)) => { let arg_list = call.arg_list()?; @@ -68,7 +68,7 @@ fn invalid_args_range( arg_list.args().nth(expected).map(|it| it.syntax().text_range()), ) } - Either::Right(pat) => { + Either::Right(ast::Pat::TupleStructPat(pat)) => { let r_paren = pat.r_paren_token()?; let l_paren = pat.l_paren_token()?; ( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index cb38bc54d7d61..37ac912f06423 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -37,9 +37,8 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField let ptr = InFile::new( d.file, d.field_list_parent_path - .clone() .map(SyntaxNodePtr::from) - .unwrap_or_else(|| d.field_list_parent.clone().into()), + .unwrap_or_else(|| d.field_list_parent.into()), ); Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr) @@ -87,7 +86,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option { - let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent); + let missing_fields = ctx.sema.record_literal_missing_fields(field_list_parent); let mut locals = FxHashMap::default(); ctx.sema.scope(field_list_parent.syntax())?.process_all_names(&mut |name, def| { @@ -99,7 +98,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option make::ext::expr_todo(), crate::ExprFillDefaultMode::Default => { - get_default_constructor(ctx, d, ty).unwrap_or_else(|| make::ext::expr_todo()) + get_default_constructor(ctx, d, ty).unwrap_or_else(make::ext::expr_todo) } }; @@ -151,7 +150,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option { - let missing_fields = ctx.sema.record_pattern_missing_fields(&field_list_parent); + let missing_fields = ctx.sema.record_pattern_missing_fields(field_list_parent); let old_field_list = field_list_parent.record_pat_field_list()?; let new_field_list = old_field_list.clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index ef6a273ed8e65..cb6d568442d30 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -11,7 +11,7 @@ pub(crate) fn missing_match_arms( ctx, DiagnosticCode::RustcHardError("E0004"), format!("missing match arm: {}", d.uncovered_patterns), - d.scrutinee_expr.clone().map(Into::into), + d.scrutinee_expr.map(Into::into), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index f93a35cf181c2..1b29e0a374601 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -15,7 +15,7 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf ctx, DiagnosticCode::RustcHardError("E0133"), "this operation is unsafe and requires an unsafe function or block", - d.expr.clone().map(|it| it.into()), + d.expr.map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 886aefeb575fb..fa9a6577fcf35 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -9,7 +9,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf ctx, DiagnosticCode::RustcHardError("E0507"), format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db)), - d.span.clone(), + d.span, ) .experimental() // spans are broken, and I'm not sure how precise we can detect copy types } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 1875111492c62..773a075f8f59e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -37,7 +37,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno "cannot mutate immutable variable `{}`", d.local.name(ctx.sema.db).display(ctx.sema.db) ), - d.span.clone(), + d.span, ) .with_fixes(fixes) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index 0abcbffe72b6b..8d77e566edc9c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -13,7 +13,7 @@ use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; // // This diagnostic is triggered if created structure does not have field provided in record. pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { - let node = d.field.clone().map(Into::into); + let node = d.field.map(Into::into); if d.private { // FIXME: quickfix to add required visibility Diagnostic::new_with_syntax_node_ptr( @@ -128,6 +128,36 @@ fn missing_record_expr_field_fixes( mod tests { use crate::tests::{check_diagnostics, check_fix, check_no_fix}; + #[test] + fn dont_work_for_field_with_disabled_cfg() { + check_diagnostics( + r#" +struct Test { + #[cfg(feature = "hello")] + test: u32, + other: u32 +} + +fn main() { + let a = Test { + #[cfg(feature = "hello")] + test: 1, + other: 1 + }; + + let Test { + #[cfg(feature = "hello")] + test, + mut other, + .. + } = a; + + other += 1; +} +"#, + ); + } + #[test] fn no_such_field_diagnostics() { check_diagnostics( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs index a828b8b4fd292..f6ed0d7226a79 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs @@ -26,7 +26,7 @@ pub(crate) fn private_assoc_item( }, name, ), - d.expr_or_pat.clone().map(Into::into), + d.expr_or_pat.map(Into::into), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs index 553defcf9905c..3179a632e26b5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs @@ -13,7 +13,7 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) d.field.name(ctx.sema.db).display(ctx.sema.db), d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db) ), - d.expr.clone().map(|it| it.into()), + d.expr.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index 258ac6cd82338..72896b891bdc7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -19,7 +19,7 @@ pub(crate) fn replace_filter_map_next_with_find_map( ctx, DiagnosticCode::Clippy("filter_map_next"), "replace filter_map(..).next() with find_map(..)", - InFile::new(d.file, d.next_expr.clone().into()), + InFile::new(d.file, d.next_expr.into()), ) .with_fixes(fixes(ctx, d)) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs index 251a645292ed5..6be2c54e6030e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -19,7 +19,7 @@ pub(crate) fn trait_impl_incorrect_safety( }, adjusted_display_range::( ctx, - InFile { file_id: d.file_id, value: d.impl_.syntax_node_ptr() }, + InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { if d.should_be_safe { Some(match (impl_.unsafe_token(), impl_.impl_token()) { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 56188cddf0b2e..58d1b7f31d2fe 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -25,7 +25,7 @@ pub(crate) fn trait_impl_missing_assoc_item( format!("not all trait items implemented, missing: {missing}"), adjusted_display_range::( ctx, - InFile { file_id: d.file_id, value: d.impl_.syntax_node_ptr() }, + InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| impl_.trait_().map(|t| t.syntax().text_range()), ), ) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs index 159d87d269de0..d36813381e436 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs @@ -12,8 +12,9 @@ pub(crate) fn trait_impl_orphan( Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0117"), - format!("only traits defined in the current crate can be implemented for arbitrary types"), - InFile::new(d.file_id, d.impl_.clone().into()), + "only traits defined in the current crate can be implemented for arbitrary types" + .to_string(), + InFile::new(d.file_id, d.impl_.into()), ) // Not yet checked for false positives .experimental() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index 6ecfd55ea0245..f58fcd1f7e2b2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -1,4 +1,4 @@ -use hir::{db::ExpandDatabase, Const, Function, HasSource, HirDisplay, TypeAlias}; +use hir::{db::ExpandDatabase, HasSource, HirDisplay}; use ide_db::{ assists::{Assist, AssistId, AssistKind}, label::Label, @@ -25,7 +25,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item { hir::AssocItem::Function(id) => { - let function = Function::from(id); + let function = id; ( format!("`fn {}`", redundant_assoc_item_name), function @@ -36,7 +36,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ) } hir::AssocItem::Const(id) => { - let constant = Const::from(id); + let constant = id; ( format!("`const {}`", redundant_assoc_item_name), constant @@ -47,7 +47,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ) } hir::AssocItem::TypeAlias(id) => { - let type_alias = TypeAlias::from(id); + let type_alias = id; ( format!("`type {}`", redundant_assoc_item_name), type_alias @@ -94,7 +94,8 @@ fn quickfix_for_redundant_assoc_item( let where_to_insert = hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted(db).range; - Some(builder.insert(where_to_insert.end(), redundant_item_def)) + builder.insert(where_to_insert.end(), redundant_item_def); + Some(()) }; let file_id = d.file_id.file_id()?; let mut source_change_builder = SourceChangeBuilder::new(file_id); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 70beb9468938c..750189beecb1d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,3 +1,4 @@ +use either::Either; use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type}; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use syntax::{ @@ -13,33 +14,24 @@ use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, Dia // This diagnostic is triggered when the type of an expression or pattern does not match // the expected type. pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic { - let display_range = match &d.expr_or_pat.value { - expr if ast::Expr::can_cast(expr.kind()) => adjusted_display_range::( - ctx, - InFile { file_id: d.expr_or_pat.file_id, value: expr.syntax_node_ptr() }, - &|expr| { - let salient_token_range = match expr { - ast::Expr::IfExpr(it) => it.if_token()?.text_range(), - ast::Expr::LoopExpr(it) => it.loop_token()?.text_range(), - ast::Expr::ForExpr(it) => it.for_token()?.text_range(), - ast::Expr::WhileExpr(it) => it.while_token()?.text_range(), - ast::Expr::BlockExpr(it) => it.stmt_list()?.r_curly_token()?.text_range(), - ast::Expr::MatchExpr(it) => it.match_token()?.text_range(), - ast::Expr::MethodCallExpr(it) => it.name_ref()?.ident_token()?.text_range(), - ast::Expr::FieldExpr(it) => it.name_ref()?.ident_token()?.text_range(), - ast::Expr::AwaitExpr(it) => it.await_token()?.text_range(), - _ => return None, - }; - - cov_mark::hit!(type_mismatch_range_adjustment); - Some(salient_token_range) - }, - ), - pat => ctx.sema.diagnostics_display_range(InFile { - file_id: d.expr_or_pat.file_id, - value: pat.syntax_node_ptr(), - }), - }; + let display_range = adjusted_display_range(ctx, d.expr_or_pat, &|node| { + let Either::Left(expr) = node else { return None }; + let salient_token_range = match expr { + ast::Expr::IfExpr(it) => it.if_token()?.text_range(), + ast::Expr::LoopExpr(it) => it.loop_token()?.text_range(), + ast::Expr::ForExpr(it) => it.for_token()?.text_range(), + ast::Expr::WhileExpr(it) => it.while_token()?.text_range(), + ast::Expr::BlockExpr(it) => it.stmt_list()?.r_curly_token()?.text_range(), + ast::Expr::MatchExpr(it) => it.match_token()?.text_range(), + ast::Expr::MethodCallExpr(it) => it.name_ref()?.ident_token()?.text_range(), + ast::Expr::FieldExpr(it) => it.name_ref()?.ident_token()?.text_range(), + ast::Expr::AwaitExpr(it) => it.await_token()?.text_range(), + _ => return None, + }; + + cov_mark::hit!(type_mismatch_range_adjustment); + Some(salient_token_range) + }); let mut diag = Diagnostic::new( DiagnosticCode::RustcHardError("E0308"), format!( @@ -59,8 +51,8 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option> { let mut fixes = Vec::new(); - if let Some(expr_ptr) = d.expr_or_pat.value.clone().cast::() { - let expr_ptr = &InFile { file_id: d.expr_or_pat.file_id, value: expr_ptr.clone() }; + if let Some(expr_ptr) = d.expr_or_pat.value.cast::() { + let expr_ptr = &InFile { file_id: d.expr_or_pat.file_id, value: expr_ptr }; add_reference(ctx, d, expr_ptr, &mut fixes); add_missing_ok_or_some(ctx, d, expr_ptr, &mut fixes); remove_semicolon(ctx, d, expr_ptr, &mut fixes); @@ -80,7 +72,7 @@ fn add_reference( expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { - let range = ctx.sema.diagnostics_display_range(expr_ptr.clone().map(|it| it.into())); + let range = ctx.sema.diagnostics_display_range((*expr_ptr).map(|it| it.into())); let (_, mutability) = d.expected.as_reference()?; let actual_with_ref = Type::reference(&d.actual, mutability); @@ -182,7 +174,7 @@ fn str_ref_to_owned( let expr = expr_ptr.value.to_node(&root); let expr_range = expr.syntax().text_range(); - let to_owned = format!(".to_owned()"); + let to_owned = ".to_owned()".to_string(); let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned); let source_change = diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index a740e332bbddf..6441343ebacdc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -13,7 +13,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // // This diagnostic is triggered when an underscore expression is used in an invalid position. pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Diagnostic { - let display_range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())); + let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); let (message, fixes) = if d.expected.is_unknown() { ("`_` expressions may only appear on the left-hand side of an assignment".to_owned(), None) } else { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs index 495ea748776d1..a6a0fdc655fb2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs @@ -10,7 +10,7 @@ pub(crate) fn undeclared_label( ctx, DiagnosticCode::RustcHardError("undeclared-label"), format!("use of undeclared label `{}`", name.display(ctx.sema.db)), - d.node.clone().map(|it| it.into()), + d.node.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs index bcce72a7d0103..996b6eda59cf6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs @@ -11,6 +11,6 @@ pub(crate) fn unimplemented_builtin_macro( ctx, DiagnosticCode::Ra("unimplemented-builtin-macro", Severity::WeakWarning), "unimplemented built-in macro".to_string(), - d.node.clone(), + d.node, ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs index 1c5d6cd0909f8..3601041fc735b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs @@ -10,7 +10,7 @@ pub(crate) fn unreachable_label( ctx, DiagnosticCode::RustcHardError("E0767"), format!("use of unreachable label `{}`", name.display(ctx.sema.db)), - d.node.clone().map(|it| it.into()), + d.node.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs index 551021c55a98e..614057ab52bfd 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs @@ -11,7 +11,7 @@ pub(crate) fn unresolved_assoc_item( ctx, DiagnosticCode::RustcHardError("E0599"), "no such associated item", - d.expr_or_pat.clone().map(Into::into), + d.expr_or_pat.map(Into::into), ) .experimental() } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs index f8265b63275fc..4cd73d46d5f1f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs @@ -11,7 +11,7 @@ pub(crate) fn unresolved_extern_crate( ctx, DiagnosticCode::RustcHardError("unresolved-extern-crate"), "unresolved extern crate", - d.decl.clone().map(|it| it.into()), + d.decl.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 321459412182f..0e7a5720d4d25 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -8,7 +8,7 @@ use ide_db::{ use syntax::{ast, AstNode, AstPtr}; use text_edit::TextEdit; -use crate::{adjusted_display_range_new, Diagnostic, DiagnosticCode, DiagnosticsContext}; +use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-field // @@ -29,7 +29,7 @@ pub(crate) fn unresolved_field( d.name.display(ctx.sema.db), d.receiver.display(ctx.sema.db) ), - adjusted_display_range_new(ctx, d.expr, &|expr| { + adjusted_display_range(ctx, d.expr, &|expr| { Some( match expr { ast::Expr::MethodCallExpr(it) => it.name_ref(), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs index 6b8026c034199..67c7e76a3bc11 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs @@ -12,7 +12,7 @@ pub(crate) fn unresolved_import( ctx, DiagnosticCode::RustcHardError("E0432"), "unresolved import", - d.decl.clone().map(|it| it.into()), + d.decl.map(|it| it.into()), ) // This currently results in false positives in the following cases: // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 41fb67290852c..9f8fee67f31c1 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -11,7 +11,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{adjusted_display_range_new, Diagnostic, DiagnosticCode, DiagnosticsContext}; +use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-method // @@ -34,7 +34,7 @@ pub(crate) fn unresolved_method( d.name.display(ctx.sema.db), d.receiver.display(ctx.sema.db) ), - adjusted_display_range_new(ctx, d.expr, &|expr| { + adjusted_display_range(ctx, d.expr, &|expr| { Some( match expr { ast::Expr::MethodCallExpr(it) => it.name_ref(), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs index 4d7d425bab34a..1604decf9073a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs @@ -26,7 +26,7 @@ pub(crate) fn unresolved_module( ) } }, - d.decl.clone().map(|it| it.into()), + d.decl.map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index c7ad09e7ebdd9..5ad7069e317a9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -44,30 +44,30 @@ mod handlers { pub(crate) mod private_assoc_item; pub(crate) mod private_field; pub(crate) mod replace_filter_map_next_with_find_map; - pub(crate) mod trait_impl_orphan; pub(crate) mod trait_impl_incorrect_safety; pub(crate) mod trait_impl_missing_assoc_item; + pub(crate) mod trait_impl_orphan; pub(crate) mod trait_impl_redundant_assoc_item; - pub(crate) mod typed_hole; pub(crate) mod type_mismatch; + pub(crate) mod typed_hole; + pub(crate) mod undeclared_label; pub(crate) mod unimplemented_builtin_macro; + pub(crate) mod unreachable_label; pub(crate) mod unresolved_assoc_item; pub(crate) mod unresolved_extern_crate; pub(crate) mod unresolved_field; - pub(crate) mod unresolved_method; pub(crate) mod unresolved_import; pub(crate) mod unresolved_macro_call; + pub(crate) mod unresolved_method; pub(crate) mod unresolved_module; pub(crate) mod unresolved_proc_macro; - pub(crate) mod undeclared_label; - pub(crate) mod unreachable_label; pub(crate) mod unused_variables; // The handlers below are unusual, the implement the diagnostics as well. pub(crate) mod field_shorthand; - pub(crate) mod useless_braces; - pub(crate) mod unlinked_file; pub(crate) mod json_is_not_rust; + pub(crate) mod unlinked_file; + pub(crate) mod useless_braces; } #[cfg(test)] @@ -89,7 +89,6 @@ use ide_db::{ use once_cell::sync::Lazy; use stdx::never; use syntax::{ - algo::find_node_at_range, ast::{self, AstNode}, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange, }; @@ -174,7 +173,7 @@ impl Diagnostic { node: InFile, ) -> Diagnostic { let file_id = node.file_id; - Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node.clone())) + Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node)) .with_main_node(node.map(|x| x.to_node(&ctx.sema.parse_or_expand(file_id)))) } @@ -281,7 +280,7 @@ impl DiagnosticsContext<'_> { } } })() - .unwrap_or_else(|| sema.diagnostics_display_range(node.clone())) + .unwrap_or_else(|| sema.diagnostics_display_range(*node)) } } @@ -293,7 +292,7 @@ pub fn diagnostics( resolve: &AssistResolveStrategy, file_id: FileId, ) -> Vec { - let _p = profile::span("diagnostics"); + let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered(); let sema = Semantics::new(db); let parse = db.parse(file_id); let mut res = Vec::new(); @@ -448,8 +447,8 @@ fn handle_lint_attributes( diagnostics_of_range: &mut FxHashMap, &mut Diagnostic>, ) { let file_id = sema.hir_file_for(root); - let mut preorder = root.preorder(); - while let Some(ev) = preorder.next() { + let preorder = root.preorder(); + for ev in preorder { match ev { syntax::WalkEvent::Enter(node) => { for attr in node.children().filter_map(ast::Attr::cast) { @@ -571,24 +570,6 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { } fn adjusted_display_range( - ctx: &DiagnosticsContext<'_>, - diag_ptr: InFile, - adj: &dyn Fn(N) -> Option, -) -> FileRange { - let FileRange { file_id, range } = ctx.sema.diagnostics_display_range(diag_ptr); - - let source_file = ctx.sema.db.parse(file_id); - FileRange { - file_id, - range: find_node_at_range::(&source_file.syntax_node(), range) - .filter(|it| it.syntax().text_range() == range) - .and_then(adj) - .unwrap_or(range), - } -} - -// FIXME Replace the one above with this one? -fn adjusted_display_range_new( ctx: &DiagnosticsContext<'_>, diag_ptr: InFile>, adj: &dyn Fn(N) -> Option, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 742db32564de3..f394a491b5124 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -173,7 +173,7 @@ fn minicore_smoke_test() { fn check(minicore: MiniCore) { let source = minicore.source_code(); let mut config = DiagnosticsConfig::test_sample(); - // This should be ignored since we conditionaly remove code which creates single item use with braces + // This should be ignored since we conditionally remove code which creates single item use with braces config.disabled.insert("unused_braces".to_string()); check_diagnostics_with_config(config, &source); } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs index 503754afe7c26..4d6809efbe199 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs @@ -35,7 +35,9 @@ pub(crate) fn stmt(s: &str) -> Result { parse.tree().syntax().descendants().skip(2).find_map(ast::Stmt::cast).ok_or(())?; if !s.ends_with(';') && node.to_string().ends_with(';') { node = node.clone_for_update(); - node.syntax().last_token().map(|it| it.detach()); + if let Some(it) = node.syntax().last_token() { + it.detach() + } } if node.to_string() != s { return Err(()); diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index d756e7a63eb9b..b5bf510aeed48 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -69,11 +69,11 @@ // // foo($a, $b) ==>> ($a).foo($b) // ``` +mod fragments; mod from_comment; mod matching; mod nester; mod parsing; -mod fragments; mod replacing; mod resolving; mod search; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index 0312a0f11ebd8..060897a685299 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -310,6 +310,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { Ok(()) } + #[allow(clippy::only_used_in_recursion)] fn check_constraint( &self, constraint: &Constraint, @@ -320,7 +321,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { kind.matches(code)?; } Constraint::Not(sub) => { - if self.check_constraint(&*sub, code).is_ok() { + if self.check_constraint(sub, code).is_ok() { fail_match!("Constraint {:?} failed for '{}'", constraint, code.text()); } } @@ -764,12 +765,7 @@ impl Iterator for PatternIterator { type Item = SyntaxElement; fn next(&mut self) -> Option { - for element in &mut self.iter { - if !element.kind().is_trivia() { - return Some(element); - } - } - None + self.iter.find(|element| !element.kind().is_trivia()) } } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index ca76d0a87b99b..8d2d796122a2d 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -56,7 +56,7 @@ impl MatchFinder<'_> { matches_out: &mut Vec, ) { if let Some(resolved_path) = pick_path_for_usages(pattern) { - let definition: Definition = resolved_path.resolution.clone().into(); + let definition: Definition = resolved_path.resolution.into(); for file_range in self.find_usages(usage_cache, definition).file_ranges() { for node_to_match in self.find_nodes_to_match(resolved_path, file_range) { if !is_search_permitted_ancestors(&node_to_match) { diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs b/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs index 0cadf125fecae..a090b60413eb9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs @@ -14,7 +14,7 @@ pub(super) fn find_all_methods( ) -> Vec<(TextRange, Option)> { let sema = Semantics::new(db); let source_file = sema.parse(file_id); - source_file.syntax().descendants().filter_map(|it| method_range(it)).collect() + source_file.syntax().descendants().filter_map(method_range).collect() } fn method_range(item: SyntaxNode) -> Option<(TextRange, Option)> { diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index 4b0ecb9cf9089..f22198571912d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -64,13 +64,12 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin // * path-based links: `../../module/struct.MyStruct.html` // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) { - return (None, target, title); - } - if let Some(target) = rewrite_url_link(db, definition, target) { - return (Some(LinkType::Inline), target, title.to_string()); + (None, target, title) + } else if let Some(target) = rewrite_url_link(db, definition, target) { + (Some(LinkType::Inline), target, title.to_string()) + } else { + (None, target.to_string(), title.to_string()) } - - (None, target.to_string(), title.to_string()) } }); let mut out = String::new(); @@ -352,8 +351,12 @@ fn get_doc_links( web_url = join_url(web_url, &file); local_url = join_url(local_url, &file); - web_url.as_mut().map(|url| url.set_fragment(frag.as_deref())); - local_url.as_mut().map(|url| url.set_fragment(frag.as_deref())); + if let Some(url) = web_url.as_mut() { + url.set_fragment(frag.as_deref()) + } + if let Some(url) = local_url.as_mut() { + url.set_fragment(frag.as_deref()) + } DocumentationLinks { web_url: web_url.map(|it| it.into()), @@ -369,16 +372,21 @@ fn rewrite_intra_doc_link( ) -> Option<(String, String)> { let (link, ns) = parse_intra_doc_link(target); + let (link, anchor) = match link.split_once('#') { + Some((new_link, anchor)) => (new_link, Some(anchor)), + None => (link, None), + }; + let resolved = resolve_doc_path_for_def(db, def, link, ns)?; let mut url = get_doc_base_urls(db, resolved, None, None).0?; - let (_, file, frag) = filename_and_frag_for_def(db, resolved)?; + let (_, file, _) = filename_and_frag_for_def(db, resolved)?; if let Some(path) = mod_path_of_def(db, resolved) { url = url.join(&path).ok()?; } url = url.join(&file).ok()?; - url.set_fragment(frag.as_deref()); + url.set_fragment(anchor); Some((url.into(), strip_prefixes_suffixes(title).to_string())) } diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index e1f5ccc228b7d..3bb0fc606411a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -130,10 +130,10 @@ fn external_docs_doc_builtin_type() { //- /main.rs crate:foo let x: u3$02 = 0; "#, - Some(&OsStr::new("/home/user/project")), + Some(OsStr::new("/home/user/project")), Some(expect![[r#"https://doc.rust-lang.org/nightly/core/primitive.u32.html"#]]), Some(expect![[r#"file:///sysroot/share/doc/rust/html/core/primitive.u32.html"#]]), - Some(&OsStr::new("/sysroot")), + Some(OsStr::new("/sysroot")), ); } @@ -146,10 +146,10 @@ use foo$0::Foo; //- /lib.rs crate:foo pub struct Foo; "#, - Some(&OsStr::new("/home/user/project")), + Some(OsStr::new("/home/user/project")), Some(expect![[r#"https://docs.rs/foo/*/foo/index.html"#]]), Some(expect![[r#"file:///home/user/project/doc/foo/index.html"#]]), - Some(&OsStr::new("/sysroot")), + Some(OsStr::new("/sysroot")), ); } @@ -160,10 +160,10 @@ fn external_docs_doc_url_std_crate() { //- /main.rs crate:std use self$0; "#, - Some(&OsStr::new("/home/user/project")), + Some(OsStr::new("/home/user/project")), Some(expect!["https://doc.rust-lang.org/stable/std/index.html"]), Some(expect!["file:///sysroot/share/doc/rust/html/std/index.html"]), - Some(&OsStr::new("/sysroot")), + Some(OsStr::new("/sysroot")), ); } @@ -174,10 +174,10 @@ fn external_docs_doc_url_struct() { //- /main.rs crate:foo pub struct Fo$0o; "#, - Some(&OsStr::new("/home/user/project")), + Some(OsStr::new("/home/user/project")), Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]), Some(expect![[r#"file:///home/user/project/doc/foo/struct.Foo.html"#]]), - Some(&OsStr::new("/sysroot")), + Some(OsStr::new("/sysroot")), ); } @@ -188,10 +188,10 @@ fn external_docs_doc_url_windows_backslash_path() { //- /main.rs crate:foo pub struct Fo$0o; "#, - Some(&OsStr::new(r"C:\Users\user\project")), + Some(OsStr::new(r"C:\Users\user\project")), Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]), Some(expect![[r#"file:///C:/Users/user/project/doc/foo/struct.Foo.html"#]]), - Some(&OsStr::new("/sysroot")), + Some(OsStr::new("/sysroot")), ); } @@ -202,10 +202,10 @@ fn external_docs_doc_url_windows_slash_path() { //- /main.rs crate:foo pub struct Fo$0o; "#, - Some(&OsStr::new(r"C:/Users/user/project")), + Some(OsStr::new(r"C:/Users/user/project")), Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]), Some(expect![[r#"file:///C:/Users/user/project/doc/foo/struct.Foo.html"#]]), - Some(&OsStr::new("/sysroot")), + Some(OsStr::new("/sysroot")), ); } @@ -664,3 +664,29 @@ pub struct $0Foo; expect![["[`foo`]"]], ); } + +#[test] +fn rewrite_intra_doc_link() { + check_rewrite( + r#" + //- minicore: eq, derive + //- /main.rs crate:foo + //! $0[PartialEq] + fn main() {} + "#, + expect!["[PartialEq](https://doc.rust-lang.org/stable/core/cmp/trait.PartialEq.html)"], + ); +} + +#[test] +fn rewrite_intra_doc_link_with_anchor() { + check_rewrite( + r#" + //- minicore: eq, derive + //- /main.rs crate:foo + //! $0[PartialEq#derivable] + fn main() {} + "#, + expect!["[PartialEq#derivable](https://doc.rust-lang.org/stable/core/cmp/trait.PartialEq.html#derivable)"], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs index 46ee671defbc0..14c2655f84d24 100644 --- a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs +++ b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs @@ -27,7 +27,7 @@ pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet { .iter() .map(|crate_id| &crate_graph[crate_id]) .filter(|&data| !matches!(data.origin, CrateOrigin::Local { .. })) - .map(|data| crate_info(data)) + .map(crate_info) .collect() } diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs index c694d95d537ff..2bc0721123178 100755 --- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs +++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs @@ -271,13 +271,13 @@ fn fold_range_for_where_clause(where_clause: ast::WhereClause) -> Option Option { - if let Some(_) = fold_kind(match_arm.expr()?.syntax().kind()) { - return None; - } - if match_arm.expr()?.syntax().text().contains_char('\n') { - return Some(match_arm.expr()?.syntax().text_range()); + if fold_kind(match_arm.expr()?.syntax().kind()).is_some() { + None + } else if match_arm.expr()?.syntax().text().contains_char('\n') { + Some(match_arm.expr()?.syntax().text_range()) + } else { + None } - None } #[cfg(test)] @@ -494,7 +494,7 @@ fn main() { 2, 3, ], - strustS => StructS { + structS => StructS { a: 31, }, } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index d64295bdd6907..4fed1f9158ce2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -226,6 +226,7 @@ mod tests { .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) .sorted_by_key(cmp) .collect::>(); + assert_eq!(expected, navs); } @@ -236,6 +237,60 @@ mod tests { assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } + #[test] + fn goto_def_in_included_file() { + check( + r#" +//- minicore:include +//- /main.rs + +include!("a.rs"); + +fn main() { + foo(); +} + +//- /a.rs +fn func_in_include() { + //^^^^^^^^^^^^^^^ +} + +fn foo() { + func_in_include$0(); +} +"#, + ); + } + + #[test] + fn goto_def_in_included_file_nested() { + check( + r#" +//- minicore:include +//- /main.rs + +macro_rules! passthrough { + ($($tt:tt)*) => { $($tt)* } +} + +passthrough!(include!("a.rs")); + +fn main() { + foo(); +} + +//- /a.rs +fn func_in_include() { + //^^^^^^^^^^^^^^^ +} + +fn foo() { + func_in_include$0(); +} +"#, + ); + } + #[test] fn goto_def_if_items_same_name() { check( diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 3aed007f3ea55..979ca4575d067 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -15,10 +15,10 @@ use syntax::{ ast::{self, HasLoopBody}, match_ast, AstNode, SyntaxKind::{self, IDENT, INT_NUMBER}, - SyntaxNode, SyntaxToken, TextRange, T, + SyntaxToken, TextRange, T, }; -use crate::{navigation_target::ToNav, references, NavigationTarget, TryToNav}; +use crate::{navigation_target::ToNav, NavigationTarget, TryToNav}; #[derive(PartialEq, Eq, Hash)] pub struct HighlightedRange { @@ -55,7 +55,7 @@ pub(crate) fn highlight_related( config: HighlightRelatedConfig, pos @ FilePosition { offset, file_id }: FilePosition, ) -> Option> { - let _p = profile::span("highlight_related"); + let _p = tracing::span!(tracing::Level::INFO, "highlight_related").entered(); let syntax = sema.parse(file_id).syntax().clone(); let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { @@ -81,7 +81,7 @@ pub(crate) fn highlight_related( } T![|] if config.closure_captures => highlight_closure_captures(sema, token, file_id), T![move] if config.closure_captures => highlight_closure_captures(sema, token, file_id), - _ if config.references => highlight_references(sema, &syntax, token, pos), + _ if config.references => highlight_references(sema, token, pos), _ => None, } } @@ -129,7 +129,6 @@ fn highlight_closure_captures( fn highlight_references( sema: &Semantics<'_, RootDatabase>, - node: &SyntaxNode, token: SyntaxToken, FilePosition { file_id, offset }: FilePosition, ) -> Option> { @@ -239,7 +238,7 @@ fn highlight_references( continue; } let hl_range = nav.focus_range.map(|range| { - let category = references::decl_mutability(&def, node, range) + let category = matches!(def, Definition::Local(l) if l.is_mut(sema.db)) .then_some(ReferenceCategory::Write); HighlightedRange { range, category } }); @@ -476,8 +475,7 @@ fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSe sema.descend_into_macros(DescendPreference::None, token) .into_iter() .filter_map(|token| IdentClass::classify_token(sema, &token)) - .map(IdentClass::definitions_no_ops) - .flatten() + .flat_map(IdentClass::definitions_no_ops) .collect() } @@ -521,6 +519,7 @@ mod tests { ReferenceCategory::Read => "read", ReferenceCategory::Write => "write", ReferenceCategory::Import => "import", + ReferenceCategory::Test => "test", } .to_string() }), diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 5ad119ace89db..19b181ae3b61e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -3,10 +3,10 @@ mod render; #[cfg(test)] mod tests; -use std::iter; +use std::{iter, ops::Not}; use either::Either; -use hir::{db::DefDatabase, DescendPreference, HasSource, LangItem, Semantics}; +use hir::{db::DefDatabase, DescendPreference, HasCrate, HasSource, LangItem, Semantics}; use ide_db::{ base_db::FileRange, defs::{Definition, IdentClass, NameRefClass, OperatorClass}, @@ -15,7 +15,7 @@ use ide_db::{ FxIndexSet, RootDatabase, }; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T}; +use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T}; use crate::{ doc_links::token_as_doc_comment, @@ -64,7 +64,7 @@ pub enum HoverAction { } impl HoverAction { - fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Self { + fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Option { let targets = targets .into_iter() .filter_map(|it| { @@ -77,8 +77,8 @@ impl HoverAction { nav: it.try_to_nav(db)?.call_site(), }) }) - .collect(); - HoverAction::GoToType(targets) + .collect::>(); + targets.is_empty().not().then_some(HoverAction::GoToType(targets)) } } @@ -120,6 +120,7 @@ pub(crate) fn hover( Some(res) } +#[allow(clippy::field_reassign_with_default)] fn hover_simple( sema: &Semantics<'_, RootDatabase>, FilePosition { file_id, offset }: FilePosition, @@ -268,6 +269,64 @@ fn hover_simple( let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?; render::closure_expr(sema, config, c) }) + }) + // tokens + .or_else(|| { + let mut res = HoverResult::default(); + match_ast! { + match original_token { + ast::String(string) => { + res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?)); + }, + ast::ByteString(string) => { + res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?)); + }, + ast::CString(string) => { + let val = string.value()?; + res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?)); + }, + ast::Char(char) => { + let mut res = HoverResult::default(); + res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?)); + }, + ast::Byte(byte) => { + res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?)); + }, + ast::FloatNumber(num) => { + res.markup = if num.suffix() == Some("f32") { + match num.value_f32() { + Ok(num) => { + Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits())) + }, + Err(e) => { + Markup::fenced_block_text(format_args!("{e}")) + }, + } + } else { + match num.value() { + Ok(num) => { + Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits())) + }, + Err(e) => { + Markup::fenced_block_text(format_args!("{e}")) + }, + } + }; + }, + ast::IntNumber(num) => { + res.markup = match num.value() { + Ok(num) => { + Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0b{num:b})")) + }, + Err(e) => { + Markup::fenced_block_text(format_args!("{e}")) + }, + }; + }, + _ => return None + } + } + Some(res) }); result.map(|mut res: HoverResult| { @@ -307,25 +366,44 @@ fn hover_ranged( }) } +// FIXME: Why is this pub(crate)? pub(crate) fn hover_for_definition( sema: &Semantics<'_, RootDatabase>, file_id: FileId, - definition: Definition, + def: Definition, scope_node: &SyntaxNode, config: &HoverConfig, ) -> Option { - let famous_defs = match &definition { + let famous_defs = match &def { Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())), _ => None, }; - render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| { + + let db = sema.db; + let def_ty = match def { + Definition::Local(it) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), + Definition::Field(field) => Some(field.ty(db)), + Definition::TupleField(it) => Some(it.ty(db)), + Definition::Function(it) => Some(it.ty(db)), + Definition::Adt(it) => Some(it.ty(db)), + Definition::Const(it) => Some(it.ty(db)), + Definition::Static(it) => Some(it.ty(db)), + Definition::TypeAlias(it) => Some(it.ty(db)), + Definition::BuiltinType(it) => Some(it.ty(db)), + _ => None, + }; + let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default(); + + render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, config).map(|markup| { HoverResult { - markup: render::process_markup(sema.db, definition, &markup, config), + markup: render::process_markup(sema.db, def, &markup, config), actions: [ - show_implementations_action(sema.db, definition), - show_fn_references_action(sema.db, definition), - runnable_action(sema, definition, file_id), - goto_type_action_for_def(sema.db, definition), + show_implementations_action(sema.db, def), + show_fn_references_action(sema.db, def), + runnable_action(sema, def, file_id), + goto_type_action_for_def(sema.db, def, ¬able_traits), ] .into_iter() .flatten() @@ -334,6 +412,32 @@ pub(crate) fn hover_for_definition( }) } +fn notable_traits( + db: &RootDatabase, + ty: &hir::Type, +) -> Vec<(hir::Trait, Vec<(Option, hir::Name)>)> { + db.notable_traits_in_deps(ty.krate(db).into()) + .iter() + .flat_map(|it| &**it) + .filter_map(move |&trait_| { + let trait_ = trait_.into(); + ty.impls_trait(db, trait_, &[]).then(|| { + ( + trait_, + trait_ + .items(db) + .into_iter() + .filter_map(hir::AssocItem::as_type_alias) + .map(|alias| { + (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db)) + }) + .collect::>(), + ) + }) + }) + .collect::>() +} + fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option { fn to_action(nav_target: NavigationTarget) -> HoverAction { HoverAction::Implementation(FilePosition { @@ -388,7 +492,11 @@ fn runnable_action( } } -fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option { +fn goto_type_action_for_def( + db: &RootDatabase, + def: Definition, + notable_traits: &[(hir::Trait, Vec<(Option, hir::Name)>)], +) -> Option { let mut targets: Vec = Vec::new(); let mut push_new_def = |item: hir::ModuleDef| { if !targets.contains(&item) { @@ -396,6 +504,13 @@ fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option Option it.ty(db), Definition::Field(field) => field.ty(db), Definition::Function(function) => function.ret_type(db), - _ => return None, + _ => return HoverAction::goto_type_from_targets(db, targets), }; walk_and_push_ty(db, &ty, &mut push_new_def); } - Some(HoverAction::goto_type_from_targets(db, targets)) + HoverAction::goto_type_from_targets(db, targets) } fn walk_and_push_ty( @@ -472,7 +587,9 @@ fn dedupe_or_merge_hover_actions(actions: Vec) -> Vec } if !go_to_type_targets.is_empty() { - deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect())); + deduped_actions.push(HoverAction::GoToType( + go_to_type_targets.into_iter().sorted_by(|a, b| a.mod_path.cmp(&b.mod_path)).collect(), + )); } deduped_actions diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index ee2f15c5a6af9..45386df2b266e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -1,7 +1,10 @@ //! Logic for rendering the different hover messages +use std::{mem, ops::Not}; + use either::Either; use hir::{ - Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Semantics, TypeInfo, + Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name, + Semantics, Trait, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -22,7 +25,7 @@ use syntax::{ use crate::{ doc_links::{remove_links, rewrite_links}, - hover::walk_and_push_ty, + hover::{notable_traits, walk_and_push_ty}, HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, }; @@ -114,7 +117,9 @@ pub(super) fn try_expr( }; walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def); walk_and_push_ty(sema.db, &body_ty, &mut push_new_def); - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } let inner_ty = inner_ty.display(sema.db).to_string(); let body_ty = body_ty.display(sema.db).to_string(); @@ -123,7 +128,7 @@ pub(super) fn try_expr( let l = "Propagated as: ".len() - " Type: ".len(); let static_text_len_diff = l as isize - s.len() as isize; let tpad = static_text_len_diff.max(0) as usize; - let ppad = static_text_len_diff.min(0).abs() as usize; + let ppad = static_text_len_diff.min(0).unsigned_abs(); res.markup = format!( "```text\n{} Type: {:>pad0$}\nPropagated as: {:>pad1$}\n```\n", @@ -192,7 +197,9 @@ pub(super) fn deref_expr( ) .into() }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } Some(res) } @@ -299,7 +306,9 @@ pub(super) fn struct_rest_pat( Markup::fenced_block(&s) }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } res } @@ -333,7 +342,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option>, + notable_traits: &[(Trait, Vec<(Option, Name)>)], config: &HoverConfig, ) -> Option { let mod_path = definition_mod_path(db, &def); let label = def.label(db)?; let docs = def.docs(db, famous_defs); - let value = match def { Definition::Variant(it) => { if !it.parent_enum(db).is_data_carrying(db) { @@ -462,14 +471,55 @@ pub(super) fn definition( _ => None, }; - let label = match (value, layout_info) { - (Some(value), Some(layout_info)) => format!("{label} = {value}{layout_info}"), - (Some(value), None) => format!("{label} = {value}"), - (None, Some(layout_info)) => format!("{label}{layout_info}"), - (None, None) => label, - }; + let mut desc = String::new(); + if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits) { + desc.push_str(¬able_traits); + desc.push('\n'); + } + if let Some(layout_info) = layout_info { + desc.push_str(&layout_info); + desc.push('\n'); + } + desc.push_str(&label); + if let Some(value) = value { + desc.push_str(" = "); + desc.push_str(&value); + } - markup(docs.map(Into::into), label, mod_path) + markup(docs.map(Into::into), desc, mod_path) +} + +fn render_notable_trait_comment( + db: &RootDatabase, + notable_traits: &[(Trait, Vec<(Option, Name)>)], +) -> Option { + let mut desc = String::new(); + let mut needs_impl_header = true; + for (trait_, assoc_types) in notable_traits { + desc.push_str(if mem::take(&mut needs_impl_header) { + " // Implements notable traits: " + } else { + ", " + }); + format_to!(desc, "{}", trait_.name(db).display(db),); + if !assoc_types.is_empty() { + desc.push('<'); + format_to!( + desc, + "{}", + assoc_types.iter().format_with(", ", |(ty, name), f| { + f(&name.display(db))?; + f(&" = ")?; + match ty { + Some(ty) => f(&ty.display(db)), + None => f(&"?"), + } + }) + ); + desc.push('>'); + } + } + desc.is_empty().not().then_some(desc) } fn type_info( @@ -480,6 +530,7 @@ fn type_info( if let Some(res) = closure_ty(sema, config, &ty) { return Some(res); }; + let db = sema.db; let TypeInfo { original, adjusted } = ty; let mut res = HoverResult::default(); let mut targets: Vec = Vec::new(); @@ -488,15 +539,49 @@ fn type_info( targets.push(item); } }; - walk_and_push_ty(sema.db, &original, &mut push_new_def); + walk_and_push_ty(db, &original, &mut push_new_def); res.markup = if let Some(adjusted_ty) = adjusted { - walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); - let original = original.display(sema.db).to_string(); - let adjusted = adjusted_ty.display(sema.db).to_string(); + walk_and_push_ty(db, &adjusted_ty, &mut push_new_def); + + let notable = { + let mut desc = String::new(); + let mut needs_impl_header = true; + for (trait_, assoc_types) in notable_traits(db, &original) { + desc.push_str(if mem::take(&mut needs_impl_header) { + "Implements Notable Traits: " + } else { + ", " + }); + format_to!(desc, "{}", trait_.name(db).display(db),); + if !assoc_types.is_empty() { + desc.push('<'); + format_to!( + desc, + "{}", + assoc_types.into_iter().format_with(", ", |(ty, name), f| { + f(&name.display(db))?; + f(&" = ")?; + match ty { + Some(ty) => f(&ty.display(db)), + None => f(&"?"), + } + }) + ); + desc.push('>'); + } + } + if !desc.is_empty() { + desc.push('\n'); + } + desc + }; + + let original = original.display(db).to_string(); + let adjusted = adjusted_ty.display(db).to_string(); let static_text_diff_len = "Coerced to: ".len() - "Type: ".len(); format!( - "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n```\n", + "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n{notable}```\n", original, adjusted, apad = static_text_diff_len + adjusted.len().max(original.len()), @@ -504,9 +589,16 @@ fn type_info( ) .into() } else { - Markup::fenced_block(&original.display(sema.db)) + let mut desc = match render_notable_trait_comment(db, ¬able_traits(db, &original)) { + Some(desc) => desc + "\n", + None => String::new(), + }; + format_to!(desc, "{}", original.display(db)); + Markup::fenced_block(&desc) }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(db, targets) { + res.actions.push(actions); + } Some(res) } @@ -543,7 +635,7 @@ fn closure_ty( }); let adjusted = if let Some(adjusted_ty) = adjusted { - walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); + walk_and_push_ty(sema.db, adjusted_ty, &mut push_new_def); format!( "\nCoerced to: {}", adjusted_ty.display(sema.db).with_closure_style(hir::ClosureStyle::ImplFn) @@ -558,6 +650,9 @@ fn closure_ty( { format_to!(markup, "{layout}"); } + if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) { + push_new_def(hir::Trait::from(trait_).into()) + } format_to!( markup, "\n{}\n```{adjusted}\n\n## Captures\n{}", @@ -566,7 +661,9 @@ fn closure_ty( ); let mut res = HoverResult::default(); - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } res.markup = markup.into(); Some(res) } @@ -617,8 +714,6 @@ fn render_memory_layout( offset: impl FnOnce(&Layout) -> Option, tag: impl FnOnce(&Layout) -> Option, ) -> Option { - // field - let config = config?; let layout = layout().ok()?; @@ -722,7 +817,9 @@ fn keyword_hints( KeywordHint { description, keyword_mod, - actions: vec![HoverAction::goto_type_from_targets(sema.db, targets)], + actions: HoverAction::goto_type_from_targets(sema.db, targets) + .into_iter() + .collect(), } } _ => KeywordHint { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index d5ec336fc7ed7..9f4427090e9e8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -157,7 +157,8 @@ fn foo() { *local* ```rust - let local: i32 // size = 4, align = 4 + // size = 4, align = 4 + let local: i32 ``` "#]], ); @@ -399,6 +400,20 @@ fn main() { description: "struct S", }, }, + HoverGotoTypeData { + mod_path: "core::ops::function::FnOnce", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 631..866, + focus_range: 692..698, + name: "FnOnce", + kind: Trait, + container_name: "function", + description: "pub trait FnOnce\nwhere\n Args: Tuple,", + }, + }, ], ), ] @@ -433,7 +448,8 @@ fn main() { *iter* ```rust - let mut iter: Iter>, impl Fn(&mut u32, &u32, &mut u32) -> Option, u32>> // size = 8, align = 4 + // size = 8, align = 4 + let mut iter: Iter>, impl Fn(&mut u32, &u32, &mut u32) -> Option, u32>> ``` "#]], ); @@ -449,16 +465,16 @@ pub fn foo() -> u32 { 1 } fn main() { let foo_test = fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo() -> u32 - ``` - "#]], + ```rust + pub fn foo() -> u32 + ``` + "#]], ); // Use literal `crate` in path @@ -493,16 +509,16 @@ mod m { pub fn foo() -> super::X { super::X } } fn main() { m::f$0oo(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test::m - ``` + ```rust + test::m + ``` - ```rust - pub fn foo() -> super::X - ``` - "#]], + ```rust + pub fn foo() -> super::X + ``` + "#]], ); } @@ -557,18 +573,18 @@ pub fn foo<'a, T: AsRef>(b: &'a T) -> &'a str { } fn main() { let foo_test = fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo<'a, T>(b: &'a T) -> &'a str - where - T: AsRef, - ``` - "#]], + ```rust + pub fn foo<'a, T>(b: &'a T) -> &'a str + where + T: AsRef, + ``` + "#]], ); } @@ -581,16 +597,16 @@ pub fn foo$0(a: u32, b: u32) -> u32 {} fn main() { } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo(a: u32, b: u32) -> u32 - ``` - "#]], + ```rust + pub fn foo(a: u32, b: u32) -> u32 + ``` + "#]], ); } @@ -608,27 +624,27 @@ pub fn foo$0(_: &Path) {} fn main() { } "#, - expect![[r##" - *foo* + expect![[r#" + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo(_: &Path) - ``` + ```rust + pub fn foo(_: &Path) + ``` - --- + --- - # Example + # Example - ``` - # use std::path::Path; - # - foo(Path::new("hello, world!")) - ``` - "##]], + ``` + # use std::path::Path; + # + foo(Path::new("hello, world!")) + ``` + "#]], ); } @@ -641,21 +657,21 @@ pub fn foo$0(_: &Path) {} fn main() { } "##, - expect![[r##" - *foo* + expect![[r#" + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo(_: &Path) - ``` + ```rust + pub fn foo(_: &Path) + ``` - --- + --- - Raw string doc attr - "##]], + Raw string doc attr + "#]], ); } @@ -674,7 +690,8 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } ``` ```rust - field_a: u8 // size = 1, align = 1, offset = 6 + // size = 1, align = 1, offset = 6 + field_a: u8 ``` "#]], ); @@ -699,7 +716,8 @@ fn main() { ``` ```rust - field_a: u32 // size = 4, align = 4, offset = 0 + // size = 4, align = 4, offset = 0 + field_a: u32 ``` "#]], ); @@ -721,7 +739,8 @@ fn main() { ``` ```rust - field_a: u32 // size = 4, align = 4, offset = 0 + // size = 4, align = 4, offset = 0 + field_a: u32 ``` "#]], ); @@ -848,7 +867,8 @@ fn main() { *zz* ```rust - let zz: Test // size = 8, align = 4 + // size = 8, align = 4 + let zz: Test ``` "#]], ); @@ -899,7 +919,8 @@ fn main() { let b$0ar = Some(12); } *bar* ```rust - let bar: Option // size = 4, align = 4 + // size = 4, align = 4 + let bar: Option ``` "#]], ); @@ -968,7 +989,8 @@ fn hover_for_local_variable() { *foo* ```rust - foo: i32 // size = 4, align = 4 + // size = 4, align = 4 + foo: i32 ``` "#]], ) @@ -982,7 +1004,8 @@ fn hover_for_local_variable_pat() { *foo* ```rust - foo: i32 // size = 4, align = 4 + // size = 4, align = 4 + foo: i32 ``` "#]], ) @@ -996,7 +1019,8 @@ fn hover_local_var_edge() { *foo* ```rust - foo: i32 // size = 4, align = 4 + // size = 4, align = 4 + foo: i32 ``` "#]], ) @@ -1010,7 +1034,8 @@ fn hover_for_param_edge() { *foo* ```rust - foo: i32 // size = 4, align = 4 + // size = 4, align = 4 + foo: i32 ``` "#]], ) @@ -1029,12 +1054,12 @@ fn hover_for_param_with_multiple_traits() { } fn f(_x$0: impl Deref + DerefMut) {}"#, expect![[r#" - *_x* + *_x* - ```rust - _x: impl Deref + DerefMut - ``` - "#]], + ```rust + _x: impl Deref + DerefMut + ``` + "#]], ) } @@ -1054,7 +1079,8 @@ fn main() { let foo_$0test = Thing::new(); } *foo_test* ```rust - let foo_test: Thing // size = 4, align = 4 + // size = 4, align = 4 + let foo_test: Thing ``` "#]], ) @@ -1075,15 +1101,15 @@ mod wrapper { fn main() { let foo_test = wrapper::Thing::new$0(); } "#, expect![[r#" - *new* + *new* - ```rust - test::wrapper::Thing - ``` + ```rust + test::wrapper::Thing + ``` - ```rust - pub fn new() -> Thing - ``` + ```rust + pub fn new() -> Thing + ``` "#]], ) } @@ -1222,7 +1248,8 @@ fn y() { *x* ```rust - let x: i32 // size = 4, align = 4 + // size = 4, align = 4 + let x: i32 ``` "#]], ) @@ -1286,12 +1313,12 @@ fn test_hover_tuple_field() { check( r#"struct TS(String, i32$0);"#, expect![[r#" - *i32* + *i32* - ```rust - i32 - ``` - "#]], + ```rust + i32 + ``` + "#]], ) } @@ -1306,16 +1333,16 @@ id! { } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` - "#]], + ```rust + fn foo() + ``` + "#]], ); } @@ -1328,16 +1355,16 @@ fn test_hover_through_attr() { fn foo$0() {} "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` - "#]], + ```rust + fn foo() + ``` + "#]], ); } @@ -1352,7 +1379,8 @@ fn foo(bar:u32) { let a = id!(ba$0r); } *bar* ```rust - bar: u32 // size = 4, align = 4 + // size = 4, align = 4 + bar: u32 ``` "#]], ); @@ -1370,7 +1398,8 @@ fn foo(bar:u32) { let a = id!(ba$0r); } *bar* ```rust - bar: u32 // size = 4, align = 4 + // size = 4, align = 4 + bar: u32 ``` "#]], ); @@ -1412,16 +1441,16 @@ fn foo() { } "#, expect![[r#" - *bar* + *bar* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn bar() -> bool - ``` - "#]], + ```rust + fn bar() -> bool + ``` + "#]], ); } @@ -1458,20 +1487,6 @@ fn foo(Foo { b$0ar }: &Foo) {} ) } -#[test] -fn test_hover_through_literal_string_in_builtin_macro() { - check_hover_no_result( - r#" - #[rustc_builtin_macro] - macro_rules! format {} - - fn foo() { - format!("hel$0lo {}", 0); - } -"#, - ); -} - #[test] fn test_hover_non_ascii_space_doc() { check( @@ -1482,20 +1497,20 @@ fn foo() { } fn bar() { fo$0o(); } ", expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` + ```rust + fn foo() + ``` - --- + --- - \<- ` ` here - "#]], + \<- ` ` here + "#]], ); } @@ -1504,45 +1519,45 @@ fn test_hover_function_show_qualifiers() { check( r#"async fn foo$0() {}"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - async fn foo() - ``` - "#]], + ```rust + async fn foo() + ``` + "#]], ); check( r#"pub const unsafe fn foo$0() {}"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub const unsafe fn foo() - ``` - "#]], + ```rust + pub const unsafe fn foo() + ``` + "#]], ); // Top level `pub(crate)` will be displayed as no visibility. check( r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#, expect![[r#" - *foo* + *foo* - ```rust - test::m - ``` + ```rust + test::m + ``` - ```rust - pub(crate) async unsafe extern "C" fn foo() - ``` - "#]], + ```rust + pub(crate) async unsafe extern "C" fn foo() + ``` + "#]], ); } @@ -1551,16 +1566,16 @@ fn test_hover_function_show_types() { check( r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo(a: i32, b: i32) -> i32 - ``` - "#]], + ```rust + fn foo(a: i32, b: i32) -> i32 + ``` + "#]], ); } @@ -1619,7 +1634,8 @@ fn test_hover_function_pointer_show_identifiers() { ``` ```rust - type foo = fn(a: i32, b: i32) -> i32 // size = 8, align = 8, niches = 1 + // size = 8, align = 8, niches = 1 + type foo = fn(a: i32, b: i32) -> i32 ``` "#]], ); @@ -1637,7 +1653,8 @@ fn test_hover_function_pointer_no_identifier() { ``` ```rust - type foo = fn(i32, i32) -> i32 // size = 8, align = 8, niches = 1 + // size = 8, align = 8, niches = 1 + type foo = fn(i32, i32) -> i32 ``` "#]], ); @@ -1783,7 +1800,8 @@ fn foo() { let bar = Ba$0r; } ``` ```rust - struct Bar // size = 0, align = 1 + // size = 0, align = 1 + struct Bar ``` --- @@ -1819,7 +1837,8 @@ fn foo() { let bar = Ba$0r; } ``` ```rust - struct Bar // size = 0, align = 1 + // size = 0, align = 1 + struct Bar ``` --- @@ -1848,7 +1867,8 @@ fn foo() { let bar = Ba$0r; } ``` ```rust - struct Bar // size = 0, align = 1 + // size = 0, align = 1 + struct Bar ``` --- @@ -1876,7 +1896,8 @@ pub struct B$0ar ``` ```rust - pub struct Bar // size = 0, align = 1 + // size = 0, align = 1 + pub struct Bar ``` --- @@ -1903,7 +1924,8 @@ pub struct B$0ar ``` ```rust - pub struct Bar // size = 0, align = 1 + // size = 0, align = 1 + pub struct Bar ``` --- @@ -1941,39 +1963,39 @@ fn test_hover_no_links() { pub fn fo$0o() {} "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo() - ``` + ```rust + pub fn foo() + ``` - --- + --- - Test cases: - case 1. bare URL: https://www.example.com/ - case 2. inline URL with title: [example](https://www.example.com/) - case 3. code reference: `Result` - case 4. code reference but miss footnote: `String` - case 5. autolink: http://www.example.com/ - case 6. email address: test@example.com - case 7. reference: example - case 8. collapsed link: example - case 9. shortcut link: example - case 10. inline without URL: example - case 11. reference: foo - case 12. reference: foo - case 13. collapsed link: foo - case 14. shortcut link: foo - case 15. inline without URL: foo - case 16. just escaped text: \[foo\] - case 17. inline link: Foo - - [^example]: https://www.example.com/ - "#]], + Test cases: + case 1. bare URL: https://www.example.com/ + case 2. inline URL with title: [example](https://www.example.com/) + case 3. code reference: `Result` + case 4. code reference but miss footnote: `String` + case 5. autolink: http://www.example.com/ + case 6. email address: test@example.com + case 7. reference: example + case 8. collapsed link: example + case 9. shortcut link: example + case 10. inline without URL: example + case 11. reference: foo + case 12. reference: foo + case 13. collapsed link: foo + case 14. shortcut link: foo + case 15. inline without URL: foo + case 16. just escaped text: \[foo\] + case 17. inline link: Foo + + [^example]: https://www.example.com/ + "#]], ); } @@ -1992,7 +2014,8 @@ fn test_hover_layout_of_variant() { ``` ```rust - Variant1(u8, u16) // size = 4, align = 2 + // size = 4, align = 2 + Variant1(u8, u16) ``` "#]], ); @@ -2013,10 +2036,11 @@ fn test_hover_layout_of_enum() { ``` ```rust + // size = 16 (0x10), align = 8, niches = 254 enum Foo { Variant1(u8, u16), Variant2(i32, u8, i64), - } // size = 16 (0x10), align = 8, niches = 254 + } ``` "#]], ); @@ -2081,20 +2105,20 @@ bar!(); fn foo() { let bar = Bar; bar.fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test::Bar - ``` + ```rust + test::Bar + ``` - ```rust - fn foo(&self) - ``` + ```rust + fn foo(&self) + ``` - --- + --- - Do the foo - "#]], + Do the foo + "#]], ); } @@ -2119,20 +2143,20 @@ bar!(); fn foo() { let bar = Bar; bar.fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test::Bar - ``` + ```rust + test::Bar + ``` - ```rust - fn foo(&self) - ``` + ```rust + fn foo(&self) + ``` - --- + --- - Do the foo - "#]], + Do the foo + "#]], ); } @@ -2377,39 +2401,39 @@ struct S{ f1: T } fn main() { let s$0t = S{ f1:Arg(0) }; } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..37, - focus_range: 24..25, - name: "S", - kind: Struct, - description: "struct S {\n f1: T,\n}", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Arg", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..16, + focus_range: 7..10, + name: "Arg", + kind: Struct, + description: "struct Arg(u32);", }, - HoverGotoTypeData { - mod_path: "test::Arg", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..16, - focus_range: 7..10, - name: "Arg", - kind: Struct, - description: "struct Arg(u32);", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 17..37, + focus_range: 24..25, + name: "S", + kind: Struct, + description: "struct S {\n f1: T,\n}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2436,39 +2460,39 @@ struct S{ f1: T } fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..37, - focus_range: 24..25, - name: "S", - kind: Struct, - description: "struct S {\n f1: T,\n}", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Arg", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..16, + focus_range: 7..10, + name: "Arg", + kind: Struct, + description: "struct Arg(u32);", }, - HoverGotoTypeData { - mod_path: "test::Arg", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..16, - focus_range: 7..10, - name: "Arg", - kind: Struct, - description: "struct Arg(u32);", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 17..37, + focus_range: 24..25, + name: "S", + kind: Struct, + description: "struct S {\n f1: T,\n}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2626,39 +2650,39 @@ fn foo() -> impl Foo + Bar {} fn main() { let s$0t = foo(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 13..25, + focus_range: 19..22, + name: "Bar", + kind: Trait, + description: "trait Bar", }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 13..25, - focus_range: 19..22, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2674,6 +2698,76 @@ struct S2 {} fn foo() -> impl Foo + Bar {} fn main() { let s$0t = foo(); } +"#, + expect![[r#" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 16..31, + focus_range: 22..25, + name: "Bar", + kind: Trait, + description: "trait Bar", + }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..15, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", + }, + }, + HoverGotoTypeData { + mod_path: "test::S1", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 32..44, + focus_range: 39..41, + name: "S1", + kind: Struct, + description: "struct S1 {}", + }, + }, + HoverGotoTypeData { + mod_path: "test::S2", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 45..57, + focus_range: 52..54, + name: "S2", + kind: Struct, + description: "struct S2 {}", + }, + }, + ], + ), + ] + "#]], + ); +} + +#[test] +fn test_hover_arg_impl_trait_has_goto_type_action() { + check_actions( + r#" +trait Foo {} +fn foo(ar$0g: &impl Foo) {} "#, expect![[r#" [ @@ -2685,81 +2779,11 @@ fn main() { let s$0t = foo(); } file_id: FileId( 0, ), - full_range: 0..15, + full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..31, - focus_range: 22..25, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, - }, - HoverGotoTypeData { - mod_path: "test::S1", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 32..44, - focus_range: 39..41, - name: "S1", - kind: Struct, - description: "struct S1 {}", - }, - }, - HoverGotoTypeData { - mod_path: "test::S2", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 45..57, - focus_range: 52..54, - name: "S2", - kind: Struct, - description: "struct S2 {}", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_arg_impl_trait_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -fn foo(ar$0g: &impl Foo) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", + description: "trait Foo", }, }, ], @@ -2780,52 +2804,52 @@ struct S{} fn foo(ar$0g: &impl Foo + Bar) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 13..28, + focus_range: 19..22, + name: "Bar", + kind: Trait, + description: "trait Bar", }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 13..28, - focus_range: 19..22, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 29..39, - focus_range: 36..37, - name: "S", - kind: Struct, - description: "struct S {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 29..39, + focus_range: 36..37, + name: "S", + kind: Struct, + description: "struct S {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3067,65 +3091,65 @@ struct S {} fn foo(a$0rg: &impl ImplTrait>>>) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::ImplTrait", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..21, - focus_range: 6..15, - name: "ImplTrait", - kind: Trait, - description: "trait ImplTrait", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::B", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 43..57, + focus_range: 50..51, + name: "B", + kind: Struct, + description: "struct B {}", }, - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 43..57, - focus_range: 50..51, - name: "B", - kind: Struct, - description: "struct B {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::DynTrait", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 22..42, + focus_range: 28..36, + name: "DynTrait", + kind: Trait, + description: "trait DynTrait", }, - HoverGotoTypeData { - mod_path: "test::DynTrait", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 22..42, - focus_range: 28..36, - name: "DynTrait", - kind: Trait, - description: "trait DynTrait", - }, + }, + HoverGotoTypeData { + mod_path: "test::ImplTrait", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..21, + focus_range: 6..15, + name: "ImplTrait", + kind: Trait, + description: "trait ImplTrait", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 58..69, - focus_range: 65..66, - name: "S", - kind: Struct, - description: "struct S {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 58..69, + focus_range: 65..66, + name: "S", + kind: Struct, + description: "struct S {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3295,7 +3319,7 @@ fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } ```rust pub fn new() -> Thing ``` - "#]], + "#]], ) } @@ -3316,7 +3340,8 @@ fn main() { *f* ```rust - f: &i32 // size = 8, align = 8, niches = 1 + // size = 8, align = 8, niches = 1 + let f: &i32 ``` --- @@ -3325,7 +3350,8 @@ fn main() { ``` ```rust - f: i32 // size = 4, align = 4, offset = 0 + // size = 4, align = 4, offset = 0 + f: i32 ``` "#]], ); @@ -3409,7 +3435,8 @@ fn main() { *value* ```rust - let value: Const<1> // size = 0, align = 1 + // size = 0, align = 1 + let value: Const<1> ``` "#]], ); @@ -3429,7 +3456,8 @@ fn main() { *value* ```rust - let value: Const<0> // size = 0, align = 1 + // size = 0, align = 1 + let value: Const<0> ``` "#]], ); @@ -3449,7 +3477,8 @@ fn main() { *value* ```rust - let value: Const<-1> // size = 0, align = 1 + // size = 0, align = 1 + let value: Const<-1> ``` "#]], ); @@ -3469,7 +3498,8 @@ fn main() { *value* ```rust - let value: Const // size = 0, align = 1 + // size = 0, align = 1 + let value: Const ``` "#]], ); @@ -3489,7 +3519,8 @@ fn main() { *value* ```rust - let value: Const<'🦀'> // size = 0, align = 1 + // size = 0, align = 1 + let value: Const<'🦀'> ``` "#]], ); @@ -3508,7 +3539,8 @@ impl Foo { *self* ```rust - self: &Foo // size = 8, align = 8, niches = 1 + // size = 8, align = 8, niches = 1 + self: &Foo ``` "#]], ); @@ -3528,7 +3560,8 @@ impl Foo { *self* ```rust - self: Arc // size = 0, align = 1 + // size = 0, align = 1 + self: Arc ``` "#]], ); @@ -3609,24 +3642,24 @@ fn hover_doc_block_style_indent_end() { fn foo$0() {} "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` + ```rust + fn foo() + ``` - --- + --- - foo + foo - ```rust - let x = 3; - ``` - "#]], + ```rust + let x = 3; + ``` + "#]], ); } @@ -3685,12 +3718,12 @@ trait TraitB {} impl Foo where T: Sized {} "#, expect![[r#" - *T* + *T* - ```rust - T: TraitA + TraitB - ``` - "#]], + ```rust + T: TraitA + TraitB + ``` + "#]], ); check( r#" @@ -3699,12 +3732,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); // lifetimes bounds arent being tracked yet check( @@ -3714,12 +3747,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); } @@ -3734,12 +3767,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); check( r#" @@ -3749,12 +3782,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait + ?Sized - ``` - "#]], + ```rust + T: Trait + ?Sized + ``` + "#]], ); } @@ -3769,14 +3802,14 @@ mod type_param_sized_bounds { fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], - ); - } + ```rust + T + ``` + "#]], + ); + } #[test] fn single_explicit() { @@ -3786,12 +3819,12 @@ fn foo() {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); } @@ -3803,12 +3836,12 @@ fn foo() {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: ?Sized - ``` - "#]], + ```rust + T: ?Sized + ``` + "#]], ); } @@ -3821,12 +3854,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); } @@ -3839,12 +3872,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); } @@ -3857,12 +3890,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait + ?Sized - ``` - "#]], + ```rust + T: Trait + ?Sized + ``` + "#]], ); } @@ -3874,12 +3907,12 @@ fn foo() {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); check( r#" @@ -3888,12 +3921,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); } } @@ -3913,7 +3946,8 @@ type Fo$0o2 = Foo<2>; ``` ```rust - type Foo2 = Foo<2> // size = 0, align = 1 + // size = 0, align = 1 + type Foo2 = Foo<2> ``` "#]], ); @@ -3927,12 +3961,12 @@ struct Foo; impl Foo {} "#, expect![[r#" - *LEN* + *LEN* - ```rust - const LEN: usize - ``` - "#]], + ```rust + const LEN: usize + ``` + "#]], ); } @@ -3955,7 +3989,8 @@ enum E { ``` ```rust - A = 8 // size = 1, align = 1 + // size = 1, align = 1 + A = 8 ``` --- @@ -3980,7 +4015,8 @@ enum E { ``` ```rust - A = 12 (0xC) // size = 1, align = 1 + // size = 1, align = 1 + A = 12 (0xC) ``` --- @@ -4006,7 +4042,8 @@ enum E { ``` ```rust - B = 2 // size = 1, align = 1 + // size = 1, align = 1 + B = 2 ``` --- @@ -4032,7 +4069,8 @@ enum E { ``` ```rust - B = 5 // size = 1, align = 1 + // size = 1, align = 1 + B = 5 ``` --- @@ -4058,20 +4096,20 @@ fn main() { } "#, expect![[r#" - *B* + *B* - ```rust - test - ``` + ```rust + test + ``` - ```rust - const B: bool = true - ``` + ```rust + const B: bool = true + ``` - --- + --- - true - "#]], + true + "#]], ); check( @@ -4095,16 +4133,16 @@ fn main() { } "#, expect![[r#" - *AA* + *AA* - ```rust - test - ``` + ```rust + test + ``` - ```rust - const AA: A = A { i: 5 } - ``` - "#]], + ```rust + const AA: A = A { i: 5 } + ``` + "#]], ); check( @@ -4838,7 +4876,8 @@ fn foo(e: E) { ``` ```rust - A = 3 // size = 0, align = 1 + // size = 0, align = 1 + A = 3 ``` --- @@ -4860,7 +4899,8 @@ fn main() { *tile4* ```rust - let tile4: [u32; 8] // size = 32 (0x20), align = 4 + // size = 32 (0x20), align = 4 + let tile4: [u32; 8] ``` "#]], ); @@ -5019,17 +5059,17 @@ const _: &str$0 = ""; } mod prim_str {} "#, expect![[r#" - *str* + *str* - ```rust - str - ``` + ```rust + str + ``` - --- + --- - Docs for prim_str - [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html) - "#]], + Docs for prim_str + [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html) + "#]], ); } @@ -5055,20 +5095,20 @@ fn main() { } "#, expect![[r#" - *bar* + *bar* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 - where - T: Clone + 't, - 't: 't + 't, - for<'a> T: Clone + 'a, - ``` - "#]], + ```rust + fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 + where + T: Clone + 't, + 't: 't + 't, + for<'a> T: Clone + 'a, + ``` + "#]], ) } @@ -5096,7 +5136,8 @@ pub fn gimme() -> theitem::TheItem { ``` ```rust - pub struct TheItem // size = 0, align = 1 + // size = 0, align = 1 + pub struct TheItem ``` --- @@ -5137,16 +5178,16 @@ impl T1 for Foo { } "#, expect![[r#" -*Bar* + *Bar* -```rust -test::t2 -``` + ```rust + test::t2 + ``` -```rust -pub type Bar -``` -"#]], + ```rust + pub type Bar + ``` + "#]], ); } #[test] @@ -5159,16 +5200,16 @@ trait A { type Assoc; }"#, expect![[r#" - *Assoc* + *Assoc* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Assoc - ``` - "#]], + ```rust + type Assoc + ``` + "#]], ); check( r#" @@ -5180,16 +5221,16 @@ trait A { type Assoc; }"#, expect![[r#" - *Assoc* + *Assoc* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Assoc - ``` - "#]], + ```rust + type Assoc + ``` + "#]], ); check( r#" @@ -5199,16 +5240,16 @@ trait A where type Assoc; }"#, expect![[r#" - *Assoc* + *Assoc* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Assoc - ``` - "#]], + ```rust + type Assoc + ``` + "#]], ); } @@ -5244,7 +5285,8 @@ mod string { ``` ```rust - struct String // size = 0, align = 1 + // size = 0, align = 1 + struct String ``` --- @@ -5921,7 +5963,8 @@ foo_macro!( ``` ```rust - pub struct Foo // size = 0, align = 1 + // size = 0, align = 1 + pub struct Foo ``` --- @@ -5946,7 +5989,8 @@ pub struct Foo(i32); ``` ```rust - pub struct Foo(i32); // size = 4, align = 4 + // size = 4, align = 4 + pub struct Foo(i32); ``` --- @@ -6045,7 +6089,8 @@ enum Enum { ``` ```rust - RecordV { field: u32 } // size = 4, align = 4 + // size = 4, align = 4 + RecordV { field: u32 } ``` "#]], ); @@ -6067,7 +6112,8 @@ enum Enum { ``` ```rust - field: u32 // size = 4, align = 4 + // size = 4, align = 4 + field: u32 ``` "#]], ); @@ -6569,7 +6615,8 @@ fn test() { ``` ```rust - f: u32 // size = 4, align = 4, offset = 0 + // size = 4, align = 4, offset = 0 + f: u32 ``` "#]], ); @@ -6588,7 +6635,8 @@ fn test() { *s* ```rust - let s: S // size = 0, align = 1 + // size = 0, align = 1 + let s: S ``` "#]], ); @@ -6608,7 +6656,8 @@ fn test() { *foo* ```rust - let foo: i32 // size = 4, align = 4 + // size = 4, align = 4 + let foo: i32 ``` "#]], ); @@ -6628,7 +6677,8 @@ format_args!("{aaaaa$0}"); *aaaaa* ```rust - let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1 + // size = 16 (0x10), align = 8, niches = 1 + let aaaaa: &str ``` "#]], ); @@ -6648,7 +6698,8 @@ format_args!("{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1 + // size = 16 (0x10), align = 8, niches = 1 + let aaaaa: &str ``` "#]], ); @@ -6668,7 +6719,8 @@ format_args!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1 + // size = 16 (0x10), align = 8, niches = 1 + let aaaaa: &str ``` "#]], ); @@ -6693,7 +6745,8 @@ foo!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str // size = 16 (0x10), align = 8, niches = 1 + // size = 16 (0x10), align = 8, niches = 1 + let aaaaa: &str ``` "#]], ); @@ -6725,3 +6778,475 @@ fn main() { "#]], ); } + +#[test] +fn string_literal() { + check( + r#" +fn main() { + $0"🦀\u{1f980}\\\x41"; +} +"#, + expect![[r#" + *"🦀\u{1f980}\\\x41"* + ```text + 🦀🦀\A + ``` + "#]], + ); + check( + r#" +fn main() { + $0r"🦀\u{1f980}\\\x41"; +} +"#, + expect![[r#" + *r"🦀\u{1f980}\\\x41"* + ```text + 🦀\u{1f980}\\\x41 + ``` + "#]], + ); +} + +#[test] +fn cstring_literal() { + check( + r#" +fn main() { + $0c"🦀\u{1f980}\\\x41"; +} +"#, + expect![[r#" + *c"🦀\u{1f980}\\\x41"* + ```text + 🦀🦀\A + ``` + "#]], + ); +} + +#[test] +fn byte_string_literal() { + check( + r#" +fn main() { + $0b"\xF0\x9F\xA6\x80\\"; +} +"#, + expect![[r#" + *b"\xF0\x9F\xA6\x80\\"* + ```text + [240, 159, 166, 128, 92] + ``` + "#]], + ); + check( + r#" +fn main() { + $0br"\xF0\x9F\xA6\x80\\"; +} +"#, + expect![[r#" + *br"\xF0\x9F\xA6\x80\\"* + ```text + [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] + ``` + "#]], + ); +} + +#[test] +fn byte_literal() { + check( + r#" +fn main() { + $0b'\xF0'; +} +"#, + expect![[r#" + *b'\xF0'* + ```text + 0xF0 + ``` + "#]], + ); + check( + r#" +fn main() { + $0b'\\'; +} +"#, + expect![[r#" + *b'\\'* + ```text + 0x5C + ``` + "#]], + ); +} + +#[test] +fn char_literal() { + check( + r#" +fn main() { + $0'\x41'; +} +"#, + expect![[r#" + *'\x41'* + + "#]], + ); + check( + r#" +fn main() { + $0'\\'; +} +"#, + expect![[r#" + *'\\'* + + "#]], + ); + check( + r#" +fn main() { + $0'\u{1f980}'; +} +"#, + expect![[r#" + *'\u{1f980}'* + + "#]], + ); +} + +#[test] +fn float_literal() { + check( + r#" +fn main() { + $01.0; +} +"#, + expect![[r#" + *1.0* + ```text + 1 (bits: 0x3FF0000000000000) + ``` + "#]], + ); + check( + r#" +fn main() { + $01.0f32; +} +"#, + expect![[r#" + *1.0f32* + ```text + 1 (bits: 0x3F800000) + ``` + "#]], + ); + check( + r#" +fn main() { + $0134e12; +} +"#, + expect![[r#" + *134e12* + ```text + 134000000000000 (bits: 0x42DE77D399980000) + ``` + "#]], + ); + check( + r#" +fn main() { + $01523527134274733643531312.0; +} +"#, + expect![[r#" + *1523527134274733643531312.0* + ```text + 1523527134274733600000000 (bits: 0x44F429E9249F629B) + ``` + "#]], + ); + check( + r#" +fn main() { + $00.1ea123; +} +"#, + expect![[r#" + *0.1ea123* + ```text + invalid float literal + ``` + "#]], + ); +} + +#[test] +fn int_literal() { + check( + r#" +fn main() { + $034325236457856836345234; +} +"#, + expect![[r#" + *34325236457856836345234* + ```text + 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) + ``` + "#]], + ); + check( + r#" +fn main() { + $0134_123424_21; +} +"#, + expect![[r#" + *134_123424_21* + ```text + 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) + ``` + "#]], + ); + check( + r#" +fn main() { + $00x12423423; +} +"#, + expect![[r#" + *0x12423423* + ```text + 306328611 (0x12423423|0b10010010000100011010000100011) + ``` + "#]], + ); + check( + r#" +fn main() { + $00b1111_1111; +} +"#, + expect![[r#" + *0b1111_1111* + ```text + 255 (0xFF|0b11111111) + ``` + "#]], + ); + check( + r#" +fn main() { + $00o12345; +} +"#, + expect![[r#" + *0o12345* + ```text + 5349 (0x14E5|0b1010011100101) + ``` + "#]], + ); + check( + r#" +fn main() { + $00xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F; +} +"#, + expect![[r#" + *0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F* + ```text + number too large to fit in target type + ``` + "#]], + ); +} + +#[test] +fn notable_local() { + check( + r#" +#[doc(notable_trait)] +trait Notable { + type Assoc; + type Assoc2; +} + +impl Notable for u32 { + type Assoc = &str; + type Assoc2 = char; +} +fn main(notable$0: u32) {} +"#, + expect![[r#" + *notable* + + ```rust + // Implements notable traits: Notable + // size = 4, align = 4 + notable: u32 + ``` + "#]], + ); +} + +#[test] +fn notable_foreign() { + check( + r#" +//- minicore: future, iterator +struct S; +#[doc(notable_trait)] +trait Notable {} +impl Notable for S$0 {} +impl core::future::Future for S { + type Output = u32; +} +impl Iterator for S { + type Item = S; +} +"#, + expect![[r#" + *S* + + ```rust + test + ``` + + ```rust + // Implements notable traits: Notable, Future, Iterator + // size = 0, align = 1 + struct S + ``` + "#]], + ); +} + +#[test] +fn notable_ranged() { + check_hover_range( + r#" +//- minicore: future, iterator +struct S; +#[doc(notable_trait)] +trait Notable {} +impl Notable for S {} +impl core::future::Future for S { + type Output = u32; +} +impl Iterator for S { + type Item = S; +} +fn main() { + $0S$0; +} +"#, + expect![[r#" + ```rust + // Implements notable traits: Notable, Future, Iterator + S + ```"#]], + ); +} + +#[test] +fn notable_actions() { + check_actions( + r#" +//- minicore: future, iterator +struct S; +struct S2; +#[doc(notable_trait)] +trait Notable {} +impl Notable for S$0 {} +impl core::future::Future for S { + type Output = u32; +} +impl Iterator for S { + type Item = S2; +} +"#, + expect![[r#" + [ + Implementation( + FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + ), + GoToType( + [ + HoverGotoTypeData { + mod_path: "core::future::Future", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 6156..6364, + focus_range: 6221..6227, + name: "Future", + kind: Trait, + container_name: "future", + description: "pub trait Future", + }, + }, + HoverGotoTypeData { + mod_path: "core::iter::traits::iterator::Iterator", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 6994..7460, + focus_range: 7038..7046, + name: "Iterator", + kind: Trait, + container_name: "iterator", + description: "pub trait Iterator", + }, + }, + HoverGotoTypeData { + mod_path: "test::Notable", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 21..59, + focus_range: 49..56, + name: "Notable", + kind: Trait, + description: "trait Notable", + }, + }, + HoverGotoTypeData { + mod_path: "test::S2", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 10..20, + focus_range: 17..19, + name: "S2", + kind: Struct, + description: "struct S2", + }, + }, + ], + ), + ] + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index f466b8e938f98..8311e770b4b41 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -25,13 +25,13 @@ mod bind_pat; mod binding_mode; mod chaining; mod closing_brace; -mod closure_ret; mod closure_captures; +mod closure_ret; mod discriminant; mod fn_lifetime_fn; +mod implicit_drop; mod implicit_static; mod param_name; -mod implicit_drop; mod range_exclusive; #[derive(Clone, Debug, PartialEq, Eq)] @@ -357,7 +357,7 @@ fn label_of_ty( label_builder: &mut InlayHintLabelBuilder<'_>, config: &InlayHintsConfig, ) -> Result<(), HirDisplayError> { - let iter_item_type = hint_iterator(sema, famous_defs, &ty); + let iter_item_type = hint_iterator(sema, famous_defs, ty); match iter_item_type { Some((iter_trait, item, ty)) => { const LABEL_START: &str = "impl "; @@ -454,7 +454,7 @@ pub(crate) fn inlay_hints( range_limit: Option, config: &InlayHintsConfig, ) -> Vec { - let _p = profile::span("inlay_hints"); + let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered(); let sema = Semantics::new(db); let file = sema.parse(file_id); let file = file.syntax(); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 26dc6fa8b9c78..06cce147d2a16 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -74,7 +74,7 @@ fn variant_hints( }, Some(InlayTooltip::String(match &d { Ok(_) => "enum variant discriminant".into(), - Err(e) => format!("{e:?}").into(), + Err(e) => format!("{e:?}"), })), None, ); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs index 7b05e32ad86fe..6e5f23bed09fb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs @@ -4,11 +4,11 @@ //! ``` use ide_db::{syntax_helpers::node_ext::walk_ty, FxHashMap}; use itertools::Itertools; -use syntax::SmolStr; use syntax::{ ast::{self, AstNode, HasGenericParams, HasName}, SyntaxToken, }; +use syntax::{format_smolstr, SmolStr}; use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints}; @@ -80,7 +80,7 @@ pub(super) fn hints( let mut gen_idx_name = { let mut gen = (0u8..).map(|idx| match idx { idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]), - idx => format!("'{idx}").into(), + idx => format_smolstr!("'{idx}"), }); move || gen.next().unwrap_or_default() }; @@ -98,15 +98,13 @@ pub(super) fn hints( }; { let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided); - if let Some(_) = &self_param { - if let Some(_) = potential_lt_refs.next() { - allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints { - // self can't be used as a lifetime, so no need to check for collisions - "'self".into() - } else { - gen_idx_name() - }); - } + if self_param.is_some() && potential_lt_refs.next().is_some() { + allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints { + // self can't be used as a lifetime, so no need to check for collisions + "'self".into() + } else { + gen_idx_name() + }); } potential_lt_refs.for_each(|(name, ..)| { let name = match name { @@ -130,11 +128,11 @@ pub(super) fn hints( [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => { match lifetime { Some(lt) => match lt.text().as_str() { - "'_" => allocated_lifetimes.get(0).cloned(), + "'_" => allocated_lifetimes.first().cloned(), "'static" => None, name => Some(name.into()), }, - None => allocated_lifetimes.get(0).cloned(), + None => allocated_lifetimes.first().cloned(), } } [..] => None, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index 9cbaed090dc78..3104b85768f47 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -118,9 +118,8 @@ fn nearest_token_after_node( token_type: syntax::SyntaxKind, ) -> Option { node.siblings_with_tokens(syntax::Direction::Next) - .filter_map(|it| it.as_token().map(|it| it.clone())) - .filter(|it| it.kind() == token_type) - .next() + .filter_map(|it| it.as_token().cloned()) + .find(|it| it.kind() == token_type) } #[cfg(test)] @@ -178,7 +177,7 @@ mod tests { #[test] fn try_operator() { - // We currently show drop inlay hint for every `?` operator that may potentialy drop something. We probably need to + // We currently show drop inlay hint for every `?` operator that may potentially drop something. We probably need to // make it configurable as it doesn't seem very useful. check_with_config( ONLY_DROP_CONFIG, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index b4260d82506af..418fc002a8beb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -47,7 +47,7 @@ pub(super) fn hints( if let Some(name) = param { if let hir::CallableKind::Function(f) = callable.kind() { // assert the file is cached so we can map out of macros - if let Some(_) = sema.source(f) { + if sema.source(f).is_some() { linked_location = sema.original_range_opt(name.syntax()); } } diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs index 21697490482ec..adbd191888447 100644 --- a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs +++ b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs @@ -18,7 +18,7 @@ pub(crate) fn interpret_function(db: &RootDatabase, position: FilePosition) -> S let mut result = find_and_interpret(db, position) .unwrap_or_else(|| "Not inside a function body".to_string()); let duration = Instant::now() - start_time; - writeln!(result, "").unwrap(); + writeln!(result).unwrap(); writeln!(result, "----------------------").unwrap(); writeln!(result, " Finished in {}s", duration.as_secs_f32()).unwrap(); result diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 60a9367adceec..e9f42d478554f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -21,24 +21,25 @@ macro_rules! eprintln { mod fixture; mod markup; -mod prime_caches; mod navigation_target; +mod prime_caches; mod annotations; mod call_hierarchy; -mod signature_help; mod doc_links; -mod highlight_related; mod expand_macro; mod extend_selection; +mod fetch_crates; mod file_structure; mod folding_ranges; mod goto_declaration; mod goto_definition; mod goto_implementation; mod goto_type_definition; +mod highlight_related; mod hover; mod inlay_hints; +mod interpret_function; mod join_lines; mod markdown_remove; mod matching_brace; @@ -48,6 +49,8 @@ mod parent_module; mod references; mod rename; mod runnables; +mod shuffle_crate_graph; +mod signature_help; mod ssr; mod static_index; mod status; @@ -56,12 +59,9 @@ mod syntax_tree; mod typing; mod view_crate_graph; mod view_hir; -mod view_mir; -mod interpret_function; mod view_item_tree; -mod shuffle_crate_graph; -mod fetch_crates; mod view_memory_layout; +mod view_mir; use std::ffi::OsStr; @@ -79,7 +79,7 @@ use syntax::SourceFile; use triomphe::Arc; use view_memory_layout::{view_memory_layout, RecursiveMemoryLayout}; -use crate::navigation_target::{ToNav, TryToNav}; +use crate::navigation_target::ToNav; pub use crate::{ annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation}, @@ -104,7 +104,7 @@ pub use crate::{ SymbolInformationKind, }, move_item::Direction, - navigation_target::{NavigationTarget, UpmappingResult}, + navigation_target::{NavigationTarget, TryToNav, UpmappingResult}, prime_caches::ParallelPrimeCachesProgress, references::ReferenceSearchResult, rename::RenameError, @@ -269,7 +269,7 @@ impl Analysis { /// Debug info about the current state of the analysis. pub fn status(&self, file_id: Option) -> Cancellable { - self.with_db(|db| status::status(&*db, file_id)) + self.with_db(|db| status::status(db, file_id)) } pub fn parallel_prime_caches(&self, num_worker_threads: u8, cb: F) -> Cancellable<()> @@ -348,7 +348,7 @@ impl Analysis { } pub fn fetch_crates(&self) -> Cancellable> { - self.with_db(|db| fetch_crates::fetch_crates(db)) + self.with_db(fetch_crates::fetch_crates) } pub fn expand_macro(&self, position: FilePosition) -> Cancellable> { @@ -667,8 +667,8 @@ impl Analysis { let assists = ide_assists::assists(db, assist_config, resolve, frange); let mut res = diagnostic_assists; - res.extend(ssr_assists.into_iter()); - res.extend(assists.into_iter()); + res.extend(ssr_assists); + res.extend(assists); res }) @@ -680,8 +680,9 @@ impl Analysis { &self, position: FilePosition, new_name: &str, + rename_external: bool, ) -> Cancellable> { - self.with_db(|db| rename::rename(db, position, new_name)) + self.with_db(|db| rename::rename(db, position, new_name, rename_external)) } pub fn prepare_rename( diff --git a/src/tools/rust-analyzer/crates/ide/src/markup.rs b/src/tools/rust-analyzer/crates/ide/src/markup.rs index 411eb695fbf27..4a4e29fa33b8b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/markup.rs +++ b/src/tools/rust-analyzer/crates/ide/src/markup.rs @@ -35,4 +35,7 @@ impl Markup { pub fn fenced_block(contents: impl fmt::Display) -> Markup { format!("```rust\n{contents}\n```").into() } + pub fn fenced_block_text(contents: impl fmt::Display) -> Markup { + format!("```text\n{contents}\n```").into() + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 486329dadedac..c49d75b2f811c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -95,11 +95,7 @@ pub struct MonikerIdentifier { impl ToString for MonikerIdentifier { fn to_string(&self) -> String { - match self { - MonikerIdentifier { description, crate_name } => { - format!("{}::{}", crate_name, description.iter().map(|x| &x.name).join("::")) - } - } + format!("{}::{}", self.crate_name, self.description.iter().map(|x| &x.name).join("::")) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index bc0574ca86ed2..bfd91feeb3900 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -17,7 +17,7 @@ use ide_db::{ use stdx::never; use syntax::{ ast::{self, HasName}, - AstNode, SmolStr, SyntaxNode, TextRange, + format_smolstr, AstNode, SmolStr, SyntaxNode, TextRange, }; /// `NavigationTarget` represents an element in the editor's UI which you can @@ -76,7 +76,7 @@ pub(crate) trait ToNav { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult; } -pub(crate) trait TryToNav { +pub trait TryToNav { fn try_to_nav(&self, db: &RootDatabase) -> Option>; } @@ -457,7 +457,7 @@ impl TryToNav for hir::Field { |(FileRange { file_id, range: full_range }, focus_range)| { NavigationTarget::from_syntax( file_id, - format!("{}", self.index()).into(), + format_smolstr!("{}", self.index()), focus_range, full_range, SymbolKind::Field, @@ -689,7 +689,7 @@ impl UpmappingResult { } pub fn collect>(self) -> FI { - FI::from_iter(self.into_iter()) + FI::from_iter(self) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs index d704d12a05b23..a95d1771ce0b3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs @@ -33,7 +33,7 @@ pub(crate) fn parallel_prime_caches( num_worker_threads: u8, cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync), ) { - let _p = profile::span("prime_caches"); + let _p = tracing::span!(tracing::Level::INFO, "prime_caches").entered(); let graph = db.crate_graph(); let mut crates_to_prime = { diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 6c0fb0baf2e2b..bdda25a111f81 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -21,7 +21,6 @@ use ide_db::{ use itertools::Itertools; use nohash_hasher::IntMap; use syntax::{ - algo::find_node_at_offset, ast::{self, HasName}, match_ast, AstNode, SyntaxKind::*, @@ -58,7 +57,7 @@ pub(crate) fn find_all_refs( position: FilePosition, search_scope: Option, ) -> Option> { - let _p = profile::span("find_all_refs"); + let _p = tracing::span!(tracing::Level::INFO, "find_all_refs").entered(); let syntax = sema.parse(position.file_id).syntax().clone(); let make_searcher = |literal_search: bool| { move |def: Definition| { @@ -98,9 +97,8 @@ pub(crate) fn find_all_refs( .or_default() .push((extra_ref.focus_or_full_range(), None)); } - let decl_range = nav.focus_or_full_range(); Declaration { - is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range), + is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)), nav, } }); @@ -189,21 +187,6 @@ pub(crate) fn find_defs<'a>( ) } -pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool { - match def { - Definition::Local(_) | Definition::Field(_) => {} - _ => return false, - }; - - match find_node_at_offset::(syntax, range.start()) { - Some(stmt) if stmt.initializer().is_some() => match stmt.pat() { - Some(ast::Pat::IdentPat(it)) => it.mut_token().is_some(), - _ => false, - }, - _ => false, - } -} - /// Filter out all non-literal usages for adt-defs fn retain_adt_literal_usages( usages: &mut UsageSearchResult, @@ -324,6 +307,51 @@ mod tests { use crate::{fixture, SearchScope}; + #[test] + fn exclude_tests() { + check( + r#" +fn test_func() {} + +fn func() { + test_func$0(); +} + +#[test] +fn test() { + test_func(); +} +"#, + expect![[r#" + test_func Function FileId(0) 0..17 3..12 + + FileId(0) 35..44 + FileId(0) 75..84 Test + "#]], + ); + + check( + r#" +fn test_func() {} + +fn func() { + test_func$0(); +} + +#[::core::prelude::v1::test] +fn test() { + test_func(); +} +"#, + expect![[r#" + test_func Function FileId(0) 0..17 3..12 + + FileId(0) 35..44 + FileId(0) 96..105 Test + "#]], + ); + } + #[test] fn test_struct_literal_after_space() { check( @@ -471,6 +499,7 @@ fn main() { "#]], ); } + #[test] fn test_variant_tuple_before_paren() { check( @@ -1452,7 +1481,7 @@ fn test$0() { expect![[r#" test Function FileId(0) 0..33 11..15 - FileId(0) 24..28 + FileId(0) 24..28 Test "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 3bf41defe343e..9fce4bb0f8271 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -84,6 +84,7 @@ pub(crate) fn rename( db: &RootDatabase, position: FilePosition, new_name: &str, + rename_external: bool, ) -> RenameResult { let sema = Semantics::new(db); let source_file = sema.parse(position.file_id); @@ -103,7 +104,7 @@ pub(crate) fn rename( return rename_to_self(&sema, local); } } - def.rename(&sema, new_name) + def.rename(&sema, new_name, rename_external) }) .collect(); @@ -122,9 +123,9 @@ pub(crate) fn will_rename_file( let module = sema.to_module_def(file_id)?; let def = Definition::Module(module); let mut change = if is_raw_identifier(new_name_stem) { - def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()? + def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem]), true).ok()? } else { - def.rename(&sema, new_name_stem).ok()? + def.rename(&sema, new_name_stem, true).ok()? }; change.file_system_edits.clear(); Some(change) @@ -371,12 +372,21 @@ mod tests { use test_utils::assert_eq_text; use text_edit::TextEdit; - use crate::{fixture, FileId}; + use crate::fixture; use super::{RangeInfo, RenameError}; - #[track_caller] fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { + check_with_rename_config(new_name, ra_fixture_before, ra_fixture_after, true); + } + + #[track_caller] + fn check_with_rename_config( + new_name: &str, + ra_fixture_before: &str, + ra_fixture_after: &str, + rename_external: bool, + ) { let ra_fixture_after = &trim_indent(ra_fixture_after); let (analysis, position) = fixture::position(ra_fixture_before); if !ra_fixture_after.starts_with("error: ") { @@ -385,23 +395,22 @@ mod tests { } } let rename_result = analysis - .rename(position, new_name) + .rename(position, new_name, rename_external) .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}")); match rename_result { Ok(source_change) => { let mut text_edit_builder = TextEdit::builder(); - let mut file_id: Option = None; - for edit in source_change.source_file_edits { - file_id = Some(edit.0); - for indel in edit.1 .0.into_iter() { - text_edit_builder.replace(indel.delete, indel.insert); - } - } - if let Some(file_id) = file_id { - let mut result = analysis.file_text(file_id).unwrap().to_string(); - text_edit_builder.finish().apply(&mut result); - assert_eq_text!(ra_fixture_after, &*result); + let (&file_id, edit) = match source_change.source_file_edits.len() { + 0 => return, + 1 => source_change.source_file_edits.iter().next().unwrap(), + _ => (&position.file_id, &source_change.source_file_edits[&position.file_id]), + }; + for indel in edit.0.iter() { + text_edit_builder.replace(indel.delete, indel.insert.clone()); } + let mut result = analysis.file_text(file_id).unwrap().to_string(); + text_edit_builder.finish().apply(&mut result); + assert_eq_text!(ra_fixture_after, &*result); } Err(err) => { if ra_fixture_after.starts_with("error:") { @@ -417,8 +426,10 @@ mod tests { fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let source_change = - analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError"); + let source_change = analysis + .rename(position, new_name, true) + .unwrap() + .expect("Expect returned a RenameError"); expect.assert_eq(&filter_expect(source_change)) } @@ -2617,6 +2628,18 @@ use qux as frob; #[test] fn disallow_renaming_for_non_local_definition() { + check_with_rename_config( + "Baz", + r#" +//- /lib.rs crate:lib new_source_root:library +pub struct S; +//- /main.rs crate:main deps:lib new_source_root:local +use lib::S$0; +"#, + "error: Cannot rename a non-local definition as the config for it is disabled", + false, + ); + check( "Baz", r#" @@ -2625,13 +2648,13 @@ pub struct S; //- /main.rs crate:main deps:lib new_source_root:local use lib::S$0; "#, - "error: Cannot rename a non-local definition.", + "use lib::Baz;\n", ); } #[test] fn disallow_renaming_for_builtin_macros() { - check( + check_with_rename_config( "Baz", r#" //- minicore: derive, hash @@ -2640,8 +2663,9 @@ use core::hash::Hash; #[derive(H$0ash)] struct A; "#, - "error: Cannot rename a non-local definition.", - ) + "error: Cannot rename a non-local definition as the config for it is disabled", + false, + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 352ce89820dec..3008722cdbb6f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -500,7 +500,7 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { docs_from_attrs(attrs).map_or(false, |doc| { let mut in_code_block = false; - for line in String::from(doc).lines() { + for line in doc.lines() { if let Some(header) = RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence)) { @@ -570,7 +570,7 @@ mod tests { if let Some(cfg) = runnable.cfg { a.push_str(&format!(", {cfg:?}")); } - a.push_str(")"); + a.push(')'); a }) .collect::>(); diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 483fb76d91cf2..b2eb5a5fff1e3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -428,7 +428,7 @@ fn signature_help_for_tuple_struct_pat( let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { let en = variant.parent_enum(db); - res.doc = en.docs(db).map(|it| it.into()); + res.doc = en.docs(db); format_to!( res.signature, "enum {}::{} (", @@ -445,7 +445,7 @@ fn signature_help_for_tuple_struct_pat( match adt { hir::Adt::Struct(it) => { - res.doc = it.docs(db).map(|it| it.into()); + res.doc = it.docs(db); format_to!(res.signature, "struct {} (", it.name(db).display(db)); it.fields(db) } @@ -549,7 +549,7 @@ fn signature_help_for_record_( fields = variant.fields(db); let en = variant.parent_enum(db); - res.doc = en.docs(db).map(|it| it.into()); + res.doc = en.docs(db); format_to!( res.signature, "enum {}::{} {{ ", @@ -566,12 +566,12 @@ fn signature_help_for_record_( match adt { hir::Adt::Struct(it) => { fields = it.fields(db); - res.doc = it.docs(db).map(|it| it.into()); + res.doc = it.docs(db); format_to!(res.signature, "struct {} {{ ", it.name(db).display(db)); } hir::Adt::Union(it) => { fields = it.fields(db); - res.doc = it.docs(db).map(|it| it.into()); + res.doc = it.docs(db); format_to!(res.signature, "union {} {{ ", it.name(db).display(db)); } _ => return None, @@ -638,7 +638,7 @@ fn signature_help_for_tuple_pat_ish( res.push_call_param(&buf); buf.clear(); } - res.signature.push_str(")"); + res.signature.push(')'); res } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 307812156e92b..dfcbaf54d4f92 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -3,11 +3,11 @@ pub(crate) mod tags; mod highlights; mod injector; -mod highlight; +mod escape; mod format; -mod macro_; +mod highlight; mod inject; -mod escape; +mod macro_; mod html; #[cfg(test)] @@ -186,7 +186,7 @@ pub(crate) fn highlight( file_id: FileId, range_to_highlight: Option, ) -> Vec { - let _p = profile::span("highlight"); + let _p = tracing::span!(tracing::Level::INFO, "highlight").entered(); let sema = Semantics::new(db); // Determine the root based on the given range. @@ -282,8 +282,8 @@ fn traverse( inside_attribute = false } - Enter(NodeOrToken::Node(node)) => match ast::Item::cast(node.clone()) { - Some(item) => { + Enter(NodeOrToken::Node(node)) => { + if let Some(item) = ast::Item::cast(node.clone()) { match item { ast::Item::MacroRules(mac) => { macro_highlighter.init(); @@ -324,8 +324,7 @@ fn traverse( } } } - _ => (), - }, + } Leave(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => { match ast::Item::cast(node.clone()) { Some(ast::Item::MacroRules(mac)) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs index df1971242657d..2108b53861c13 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs @@ -67,8 +67,6 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option Option".to_string()), is_snippet: true, - }); + }) + } else { + None } - - None } /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` @@ -384,9 +381,7 @@ fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option if file_text.char_at(after_arrow) != Some('{') { return None; } - if find_node_at_offset::(file.syntax(), offset).is_none() { - return None; - } + find_node_at_offset::(file.syntax(), offset)?; Some(TextEdit::insert(after_arrow, " ".to_string())) } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs index 8c84461f659f7..727012112ebd4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs @@ -86,7 +86,7 @@ impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph { } fn node_label(&'a self, n: &CrateId) -> LabelText<'a> { - let name = self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| &*name); + let name = self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| name); LabelText::LabelStr(name.into()) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 53f998e5457d1..a229bc87c8935 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -128,7 +128,7 @@ pub(crate) fn view_memory_layout( ) .collect::>(); - if fields.len() == 0 { + if fields.is_empty() { return; } @@ -174,7 +174,7 @@ pub(crate) fn view_memory_layout( for (i, (_, child_ty)) in fields.iter().enumerate() { if let Ok(child_layout) = child_ty.layout(db) { - read_layout(nodes, db, &child_ty, &child_layout, children_start + i); + read_layout(nodes, db, child_ty, &child_layout, children_start + i); } } } diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index e6ddfd580c30e..3878e20a2a63a 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -317,8 +317,8 @@ fn load_crate_graph( // wait until Vfs has loaded all roots for task in receiver { match task { - vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => { - if n_done == n_total { + vfs::loader::Message::Progress { n_done, n_total, .. } => { + if n_done == Some(n_total) { break; } } @@ -358,7 +358,7 @@ fn expander_to_proc_macro( proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, }; let expander: sync::Arc = - if dummy_replace.iter().any(|replace| &**replace == name) { + if dummy_replace.iter().any(|replace| **replace == name) { match kind { ProcMacroKind::Attr => sync::Arc::new(IdentityExpander), _ => sync::Arc::new(EmptyExpander), diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 6e79cdaa0b9d0..800bc994adab2 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -96,19 +96,19 @@ impl Bindings { | MetaVarKind::Expr | MetaVarKind::Ident => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_inline("missing"), + text: SmolStr::new_static("missing"), span, }))) } MetaVarKind::Lifetime => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_inline("'missing"), + text: SmolStr::new_static("'missing"), span, }))) } MetaVarKind::Literal => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_inline("\"missing\""), + text: SmolStr::new_static("\"missing\""), span, }))) } @@ -187,7 +187,7 @@ fn expand_subtree( for punct in puncts { arena.push( tt::Leaf::from({ - let mut it = punct.clone(); + let mut it = *punct; marker(&mut it.span); it }) @@ -282,9 +282,9 @@ fn expand_subtree( } let res = if ctx.new_meta_vars { - count(ctx, binding, 0, depth.unwrap_or(0)) + count(binding, 0, depth.unwrap_or(0)) } else { - count_old(ctx, binding, 0, *depth) + count_old(binding, 0, *depth) }; let c = match res { @@ -292,7 +292,7 @@ fn expand_subtree( Err(e) => { // XXX: It *might* make sense to emit a dummy integer value like `0` here. // That would type inference a bit more robust in cases like - // `v[${count(t)}]` where index doesn't matter, but also coult also lead to + // `v[${count(t)}]` where index doesn't matter, but also could lead to // wrong infefrence for cases like `tup.${count(t)}` where index itself // does matter. if err.is_none() { @@ -537,7 +537,6 @@ fn fix_up_and_push_path_tt( /// Handles `${count(t, depth)}`. `our_depth` is the recursion depth and `count_depth` is the depth /// defined by the metavar expression. fn count( - ctx: &ExpandCtx<'_, S>, binding: &Binding, depth_curr: usize, depth_max: usize, @@ -547,7 +546,7 @@ fn count( if depth_curr == depth_max { Ok(bs.len()) } else { - bs.iter().map(|b| count(ctx, b, depth_curr + 1, depth_max)).sum() + bs.iter().map(|b| count(b, depth_curr + 1, depth_max)).sum() } } Binding::Empty => Ok(0), @@ -556,16 +555,15 @@ fn count( } fn count_old( - ctx: &ExpandCtx<'_, S>, binding: &Binding, our_depth: usize, count_depth: Option, ) -> Result { match binding { Binding::Nested(bs) => match count_depth { - None => bs.iter().map(|b| count_old(ctx, b, our_depth + 1, None)).sum(), + None => bs.iter().map(|b| count_old(b, our_depth + 1, None)).sum(), Some(0) => Ok(bs.len()), - Some(d) => bs.iter().map(|b| count_old(ctx, b, our_depth + 1, Some(d - 1))).sum(), + Some(d) => bs.iter().map(|b| count_old(b, our_depth + 1, Some(d - 1))).sum(), }, Binding::Empty => Ok(0), Binding::Fragment(_) | Binding::Missing(_) => { diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index 2622d7eac10ee..62fdce36892f2 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -8,11 +8,11 @@ #![warn(rust_2018_idioms, unused_lifetimes)] -mod parser; mod expander; +mod parser; mod syntax_bridge; -mod tt_iter; mod to_parser_input; +mod tt_iter; #[cfg(test)] mod benchmark; @@ -254,7 +254,7 @@ impl DeclarativeMacro { new_meta_vars: bool, call_site: S, ) -> ExpandResult> { - expander::expand_rules(&self.rules, &tt, marker, self.is_2021, new_meta_vars, call_site) + expander::expand_rules(&self.rules, tt, marker, self.is_2021, new_meta_vars, call_site) } } diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs index 8fa04ab983f06..d6c3bd1892693 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs @@ -234,7 +234,7 @@ where let mut stack = NonEmptyVec::new(entry); while let Some((token, abs_range)) = conv.bump() { - let tt::Subtree { delimiter, token_trees: result } = stack.last_mut(); + let tt::Subtree { delimiter, token_trees } = stack.last_mut(); let tt = match token.as_leaf() { Some(leaf) => tt::TokenTree::Leaf(leaf.clone()), @@ -243,7 +243,7 @@ where COMMENT => { let span = conv.span_for(abs_range); if let Some(tokens) = conv.convert_doc_comment(&token, span) { - result.extend(tokens); + token_trees.extend(tokens); } continue; } @@ -317,7 +317,7 @@ where span: conv .span_for(TextRange::at(abs_range.start(), TextSize::of('\''))), }); - result.push(apostrophe.into()); + token_trees.push(apostrophe.into()); let ident = tt::Leaf::from(tt::Ident { text: SmolStr::new(&token.to_text(conv)[1..]), @@ -326,7 +326,7 @@ where abs_range.end(), )), }); - result.push(ident.into()); + token_trees.push(ident.into()); continue; } _ => continue, @@ -337,7 +337,7 @@ where }, }; - result.push(tt); + token_trees.push(tt); } // If we get here, we've consumed all input tokens. @@ -622,7 +622,7 @@ where struct Converter { current: Option, - current_leafs: Vec>, + current_leaves: Vec>, preorder: PreorderWithTokens, range: TextRange, punct_offset: Option<(SyntaxToken, TextSize)>, @@ -650,7 +650,7 @@ impl Converter { append, remove, call_site, - current_leafs: vec![], + current_leaves: vec![], }; let first = this.next_token(); this.current = first; @@ -665,7 +665,7 @@ impl Converter { self.preorder.skip_subtree(); if let Some(mut v) = self.append.remove(&n.into()) { v.reverse(); - self.current_leafs.extend(v); + self.current_leaves.extend(v); return None; } } @@ -673,7 +673,7 @@ impl Converter { WalkEvent::Leave(ele) => { if let Some(mut v) = self.append.remove(&ele) { v.reverse(); - self.current_leafs.extend(v); + self.current_leaves.extend(v); return None; } } @@ -758,8 +758,8 @@ where } } - if let Some(leaf) = self.current_leafs.pop() { - if self.current_leafs.is_empty() { + if let Some(leaf) = self.current_leaves.pop() { + if self.current_leaves.is_empty() { self.current = self.next_token(); } return Some((SynToken::Leaf(leaf), TextRange::empty(TextSize::new(0)))); @@ -775,7 +775,7 @@ where self.punct_offset = Some((curr.clone(), 0.into())); let range = curr.text_range(); let range = TextRange::at(range.start(), TextSize::of('.')); - (SynToken::Punct { token: curr, offset: 0 as usize }, range) + (SynToken::Punct { token: curr, offset: 0_usize }, range) } else { self.punct_offset = None; let range = curr.text_range(); @@ -799,7 +799,7 @@ where } let token = if curr.kind().is_punct() { - SynToken::Punct { token: curr, offset: 0 as usize } + SynToken::Punct { token: curr, offset: 0_usize } } else { SynToken::Ordinary(curr) }; diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index 19da297b58ccc..53fda3ae4fd26 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -30,12 +30,12 @@ mod attributes; mod expressions; +mod generic_args; +mod generic_params; mod items; mod params; mod paths; mod patterns; -mod generic_args; -mod generic_params; mod types; use crate::{ diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 34fd3420f1c99..243a219525a8a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -1,5 +1,5 @@ -mod consts; mod adt; +mod consts; mod traits; mod use_item; @@ -58,14 +58,21 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { Err(m) => m, }; - if paths::is_use_path_start(p) { - match macro_call(p) { - BlockLike::Block => (), - BlockLike::NotBlock => { - p.expect(T![;]); - } - } - m.complete(p, MACRO_CALL); + // test macro_rules_as_macro_name + // macro_rules! {} + // macro_rules! (); + // macro_rules! []; + // fn main() { + // let foo = macro_rules!(); + // } + + // test_err macro_rules_as_macro_name + // macro_rules! {}; + // macro_rules! () + // macro_rules! [] + let no_ident = p.at_contextual_kw(T![macro_rules]) && p.nth_at(1, BANG) && !p.nth_at(2, IDENT); + if paths::is_use_path_start(p) || no_ident { + macro_call(p, m); return; } @@ -228,7 +235,15 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke IDENT if p.at_contextual_kw(T![union]) && p.nth(1) == IDENT => adt::union(p, m), T![macro] => macro_def(p, m), - IDENT if p.at_contextual_kw(T![macro_rules]) && p.nth(1) == BANG => macro_rules(p, m), + // check if current token is "macro_rules" followed by "!" followed by an identifier or "try" + // try is keyword since the 2018 edition and the parser is not edition aware (yet!) + IDENT + if p.at_contextual_kw(T![macro_rules]) + && p.nth_at(1, BANG) + && (p.nth_at(2, IDENT) || p.nth_at(2, T![try])) => + { + macro_rules(p, m) + } T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m), T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m), @@ -414,10 +429,16 @@ fn fn_(p: &mut Parser<'_>, m: Marker) { m.complete(p, FN); } -fn macro_call(p: &mut Parser<'_>) -> BlockLike { +fn macro_call(p: &mut Parser<'_>, m: Marker) { assert!(paths::is_use_path_start(p)); paths::use_path(p); - macro_call_after_excl(p) + match macro_call_after_excl(p) { + BlockLike::Block => (), + BlockLike::NotBlock => { + p.expect(T![;]); + } + } + m.complete(p, MACRO_CALL); } pub(super) fn macro_call_after_excl(p: &mut Parser<'_>) -> BlockLike { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs index 69880b7946b69..f689c06b31c29 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs @@ -11,7 +11,7 @@ pub(super) fn use_(p: &mut Parser<'_>, m: Marker) { // test use_tree // use outer::tree::{inner::tree}; -fn use_tree(p: &mut Parser<'_>, top_level: bool) { +fn use_tree(p: &mut Parser<'_>, top_level: bool) -> bool { let m = p.start(); match p.current() { // test use_tree_star @@ -70,24 +70,32 @@ fn use_tree(p: &mut Parser<'_>, top_level: bool) { // main balanced `{}` p.err_and_bump(msg); } - return; + return false; } } m.complete(p, USE_TREE); + true } +pub(super) const USE_TREE_LIST_RECOVERY_SET: TokenSet = + TokenSet::new(&[T![;], T![,], T![.], T![ident]]).union(ITEM_RECOVERY_SET); + +pub(super) const USE_TREE_LIST_FIRST_SET: TokenSet = TokenSet::new(&[T!['{'], T![ident]]); + // test use_tree_list // use {a, b, c}; pub(crate) fn use_tree_list(p: &mut Parser<'_>) { assert!(p.at(T!['{'])); let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - use_tree(p, false); - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); + + // test_err use_tree_list_err_recovery + // use {a; + // use b; + // struct T; + // fn test() {} + delimited(p, T!['{'], T!['}'], T![,], USE_TREE_LIST_FIRST_SET, |p: &mut Parser<'_>| { + use_tree(p, false) || p.at_ts(USE_TREE_LIST_RECOVERY_SET) + }); + m.complete(p, USE_TREE_LIST); } diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index aa25f82ae1d8d..bf1feb9a7eb07 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -379,14 +379,14 @@ fn unescape_string_error_message(text: &str, mode: Mode) -> &'static str { let mut error_message = ""; match mode { Mode::CStr => { - rustc_lexer::unescape::unescape_c_string(text, mode, &mut |_, res| { + rustc_lexer::unescape::unescape_mixed(text, mode, &mut |_, res| { if let Err(e) = res { error_message = error_to_diagnostic_message(e, mode); } }); } Mode::ByteStr | Mode::Str => { - rustc_lexer::unescape::unescape_literal(text, mode, &mut |_, res| { + rustc_lexer::unescape::unescape_unicode(text, mode, &mut |_, res| { if let Err(e) = res { error_message = error_to_diagnostic_message(e, mode); } diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs index ed0aec3cab32a..3ca285e787e81 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs @@ -26,15 +26,15 @@ extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] extern crate rustc_lexer; -mod lexed_str; -mod token_set; -mod syntax_kind; mod event; -mod parser; mod grammar; mod input; +mod lexed_str; mod output; +mod parser; mod shortcuts; +mod syntax_kind; +mod token_set; #[cfg(test)] mod tests; diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs index 2fec765bd7871..c65219b28dce6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests.rs +++ b/src/tools/rust-analyzer/crates/parser/src/tests.rs @@ -1,6 +1,6 @@ +mod prefix_entries; mod sourcegen_inline_tests; mod top_entries; -mod prefix_entries; use std::{ fmt::Write, diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs index 54e85c07344b2..bd9e188e4d84a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs +++ b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs @@ -22,7 +22,7 @@ fn sourcegen_parser_tests() { } // ok is never actually read, but it needs to be specified to create a Test in existing_tests let existing = existing_tests(&tests_dir, true); - for t in existing.keys().filter(|&t| !tests.contains_key(t)) { + if let Some(t) = existing.keys().find(|&t| !tests.contains_key(t)) { panic!("Test is deleted: {t}"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast index 13e76e68307e6..e27c941793915 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast @@ -20,32 +20,21 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Error" - ERROR - SEMICOLON ";" - WHITESPACE "\n" - ERROR - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "io" - ERROR - SEMICOLON ";" + SEMICOLON ";" + WHITESPACE "\n" + USE + USE_KW "use" + WHITESPACE " " + USE_TREE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "std" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "io" + SEMICOLON ";" WHITESPACE "\n" -error 22: expected COMMA -error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 23: expected COMMA -error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 27: expected COMMA -error 35: expected COMMA -error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 36: expected COMMA -error 36: expected R_CURLY -error 36: expected SEMICOLON +error 22: expected R_CURLY diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast new file mode 100644 index 0000000000000..79d428a41c875 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast @@ -0,0 +1,39 @@ +SOURCE_FILE + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + ERROR + SEMICOLON ";" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_PAREN "(" + R_PAREN ")" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_BRACK "[" + R_BRACK "]" + WHITESPACE "\n" +error 15: expected an item +error 32: expected SEMICOLON +error 48: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs new file mode 100644 index 0000000000000..e8d402443d60a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs @@ -0,0 +1,3 @@ +macro_rules! {}; +macro_rules! () +macro_rules! [] diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast new file mode 100644 index 0000000000000..cb90b093ba0de --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast @@ -0,0 +1,46 @@ +SOURCE_FILE + USE + USE_KW "use" + WHITESPACE " " + USE_TREE + USE_TREE_LIST + L_CURLY "{" + USE_TREE + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + SEMICOLON ";" + WHITESPACE "\n" + USE + USE_KW "use" + WHITESPACE " " + USE_TREE + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + SEMICOLON ";" + WHITESPACE "\n" + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "T" + SEMICOLON ";" + WHITESPACE "\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "test" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" +error 6: expected R_CURLY diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs new file mode 100644 index 0000000000000..f16959c25f276 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs @@ -0,0 +1,4 @@ +use {a; +use b; +struct T; +fn test() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast new file mode 100644 index 0000000000000..b997250ab4d27 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast @@ -0,0 +1,72 @@ +SOURCE_FILE + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_BRACK "[" + R_BRACK "]" + SEMICOLON ";" + WHITESPACE "\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + MACRO_EXPR + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + TOKEN_TREE + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs new file mode 100644 index 0000000000000..4c2ea378cbf93 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs @@ -0,0 +1,6 @@ +macro_rules! {} +macro_rules! (); +macro_rules! []; +fn main() { + let foo = macro_rules!(); +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 208051113a7d2..379d184dd684e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -113,7 +113,7 @@ impl ProcMacroServer { } pub fn load_dylib(&self, dylib: MacroDylib) -> Result, ServerError> { - let _p = profile::span("ProcMacroClient::load_dylib"); + let _p = tracing::span!(tracing::Level::INFO, "ProcMacroClient::load_dylib").entered(); let macros = self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?; @@ -184,7 +184,7 @@ impl ProcMacro { .process .lock() .unwrap_or_else(|e| e.into_inner()) - .send_task(msg::Request::ExpandMacro(task))?; + .send_task(msg::Request::ExpandMacro(Box::new(task)))?; match response { msg::Response::ExpandMacro(it) => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs index 557ddba5c78fe..e28fe387b84bd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs @@ -29,7 +29,7 @@ pub enum Request { /// Since [`NO_VERSION_CHECK_VERSION`] ListMacros { dylib_path: PathBuf }, /// Since [`NO_VERSION_CHECK_VERSION`] - ExpandMacro(ExpandMacro), + ExpandMacro(Box), /// Since [`VERSION_CHECK_VERSION`] ApiVersionCheck {}, /// Since [`RUST_ANALYZER_SPAN_SUPPORT`] diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs index 5ff1f36c545e6..5f81c0a96d967 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs @@ -106,9 +106,9 @@ fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&' /// pub fn read_version(dylib_path: &AbsPath) -> io::Result { let dylib_file = File::open(dylib_path)?; - let dylib_mmaped = unsafe { Mmap::map(&dylib_file) }?; + let dylib_mmapped = unsafe { Mmap::map(&dylib_file) }?; - let dot_rustc = read_section(&dylib_mmaped, ".rustc")?; + let dot_rustc = read_section(&dylib_mmapped, ".rustc")?; // check if magic is valid if &dot_rustc[0..4] != b"rust" { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs index af9a03826ffc0..a36200cdb4c35 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs @@ -45,9 +45,11 @@ fn run() -> io::Result<()> { msg::Response::ListMacros(srv.list_macros(&dylib_path)) } msg::Request::ExpandMacro(task) => match srv.span_mode() { - msg::SpanMode::Id => msg::Response::ExpandMacro(srv.expand(task).map(|(it, _)| it)), + msg::SpanMode::Id => { + msg::Response::ExpandMacro(srv.expand(*task).map(|(it, _)| it)) + } msg::SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended( - srv.expand(task).map(|(tree, span_data_table)| msg::ExpandMacroExtended { + srv.expand(*task).map(|(tree, span_data_table)| msg::ExpandMacroExtended { tree, span_data_table, }), diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs index 6cf2b5643e579..ff62980e4ffe3 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs @@ -92,14 +92,28 @@ fn main() { panic!("proc-macro-test-impl failed to build"); } + // Old Package ID Spec + let repr = format!("{name} {version}"); + // New Package Id Spec since rust-lang/cargo#13311 + let pkgid = String::from_utf8( + Command::new(toolchain::cargo()) + .current_dir(&staging_dir) + .args(["pkgid", name]) + .output() + .unwrap() + .stdout, + ) + .unwrap(); + let pkgid = pkgid.trim(); + let mut artifact_path = None; for message in Message::parse_stream(output.stdout.as_slice()) { if let Message::CompilerArtifact(artifact) = message.unwrap() { - if artifact.target.kind.contains(&"proc-macro".to_string()) { - let repr = format!("{name} {version}"); - if artifact.package_id.repr.starts_with(&repr) { - artifact_path = Some(PathBuf::from(&artifact.filenames[0])); - } + if artifact.target.kind.contains(&"proc-macro".to_string()) + && (artifact.package_id.repr.starts_with(&repr) + || artifact.package_id.repr == pkgid) + { + artifact_path = Some(PathBuf::from(&artifact.filenames[0])); } } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 67b9f57a1636c..460a96c07f367 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -21,8 +21,8 @@ extern crate proc_macro; extern crate rustc_driver as _; mod dylib; -mod server; mod proc_macros; +mod server; use std::{ collections::{hash_map::Entry, HashMap}, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs index 1854322ddb5c3..ff8fd295d884a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs @@ -13,9 +13,9 @@ use proc_macro::bridge; mod token_stream; pub use token_stream::TokenStream; -pub mod token_id; pub mod rust_analyzer_span; mod symbol; +pub mod token_id; pub use symbol::*; use tt::Spacing; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs index bcf3600d27366..b864a5e4fd63e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs @@ -1,4 +1,4 @@ -//! proc-macro server backend based on rust-analyzer's internal span represention +//! proc-macro server backend based on rust-analyzer's internal span representation //! This backend is used solely by rust-analyzer as it ties into rust-analyzer internals. //! //! It is an unfortunate result of how the proc-macro API works that we need to look into the diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs index 12526ad4f3ae6..c83e09af0d6e1 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs @@ -206,7 +206,7 @@ impl server::TokenStream for TokenIdServer { stream: if subtree.token_trees.is_empty() { None } else { - Some(subtree.token_trees.into_iter().collect()) + Some(TokenStream { token_trees: subtree.token_trees }) }, span: bridge::DelimSpan::from_single(subtree.delimiter.open), }), diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml index 5350023c88fac..a87b67f5c69f3 100644 --- a/src/tools/rust-analyzer/crates/profile/Cargo.toml +++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml @@ -13,6 +13,7 @@ doctest = false [dependencies] once_cell = "1.17.0" +tracing.workspace = true cfg-if = "1.0.0" la-arena.workspace = true libc.workspace = true @@ -33,4 +34,4 @@ jemalloc = ["jemalloc-ctl"] # default = [ "cpu_profiler" ] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/profile/src/hprof.rs b/src/tools/rust-analyzer/crates/profile/src/hprof.rs deleted file mode 100644 index ea89a89c5c5ca..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/hprof.rs +++ /dev/null @@ -1,326 +0,0 @@ -//! Simple hierarchical profiler -use std::{ - cell::RefCell, - collections::{BTreeMap, HashSet}, - env, fmt, - io::{stderr, Write}, - sync::{ - atomic::{AtomicBool, Ordering}, - RwLock, - }, - time::{Duration, Instant}, -}; - -use once_cell::sync::Lazy; - -use crate::tree::{Idx, Tree}; - -/// Filtering syntax -/// env RA_PROFILE=* // dump everything -/// env RA_PROFILE=foo|bar|baz // enabled only selected entries -/// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms -pub fn init() { - countme::enable(env::var("RA_COUNT").is_ok()); - let spec = env::var("RA_PROFILE").unwrap_or_default(); - init_from(&spec); -} - -pub fn init_from(spec: &str) { - let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) }; - filter.install(); -} - -type Label = &'static str; - -/// This function starts a profiling scope in the current execution stack with a given description. -/// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop. -/// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack. -/// In this case the profiling information will be nested at the output. -/// Profiling information is being printed in the stderr. -/// -/// # Example -/// ``` -/// profile::init_from("profile1|profile2@2"); -/// profiling_function1(); -/// -/// fn profiling_function1() { -/// let _p = profile::span("profile1"); -/// profiling_function2(); -/// } -/// -/// fn profiling_function2() { -/// let _p = profile::span("profile2"); -/// } -/// ``` -/// This will print in the stderr the following: -/// ```text -/// 0ms - profile -/// 0ms - profile2 -/// ``` -#[inline] -pub fn span(label: Label) -> ProfileSpan { - debug_assert!(!label.is_empty()); - - let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); - if enabled && with_profile_stack(|stack| stack.push(label)) { - ProfileSpan(Some(ProfilerImpl { label, detail: None })) - } else { - ProfileSpan(None) - } -} - -#[inline] -pub fn heartbeat_span() -> HeartbeatSpan { - let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); - HeartbeatSpan::new(enabled) -} - -#[inline] -pub fn heartbeat() { - let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); - if enabled { - with_profile_stack(|it| it.heartbeat(1)); - } -} - -pub struct ProfileSpan(Option); - -struct ProfilerImpl { - label: Label, - detail: Option, -} - -impl ProfileSpan { - pub fn detail(mut self, detail: impl FnOnce() -> String) -> ProfileSpan { - if let Some(profiler) = &mut self.0 { - profiler.detail = Some(detail()); - } - self - } -} - -impl Drop for ProfilerImpl { - #[inline] - fn drop(&mut self) { - with_profile_stack(|it| it.pop(self.label, self.detail.take())); - } -} - -pub struct HeartbeatSpan { - enabled: bool, -} - -impl HeartbeatSpan { - #[inline] - pub fn new(enabled: bool) -> Self { - if enabled { - with_profile_stack(|it| it.heartbeats(true)); - } - Self { enabled } - } -} - -impl Drop for HeartbeatSpan { - fn drop(&mut self) { - if self.enabled { - with_profile_stack(|it| it.heartbeats(false)); - } - } -} - -static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); -static FILTER: Lazy> = Lazy::new(Default::default); - -fn with_profile_stack(f: impl FnOnce(&mut ProfileStack) -> T) -> T { - thread_local!(static STACK: RefCell = RefCell::new(ProfileStack::new())); - STACK.with(|it| f(&mut it.borrow_mut())) -} - -#[derive(Default, Clone, Debug)] -struct Filter { - depth: usize, - allowed: HashSet, - longer_than: Duration, - heartbeat_longer_than: Duration, - version: usize, -} - -impl Filter { - fn disabled() -> Filter { - Filter::default() - } - - fn from_spec(mut spec: &str) -> Filter { - let longer_than = if let Some(idx) = spec.rfind('>') { - let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than"); - spec = &spec[..idx]; - Duration::from_millis(longer_than) - } else { - Duration::new(0, 0) - }; - let heartbeat_longer_than = longer_than; - - let depth = if let Some(idx) = spec.rfind('@') { - let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); - spec = &spec[..idx]; - depth - } else { - 999 - }; - let allowed = - if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; - Filter { depth, allowed, longer_than, heartbeat_longer_than, version: 0 } - } - - fn install(mut self) { - PROFILING_ENABLED.store(self.depth > 0, Ordering::SeqCst); - let mut old = FILTER.write().unwrap(); - self.version = old.version + 1; - *old = self; - } -} - -struct ProfileStack { - frames: Vec, - filter: Filter, - messages: Tree, - heartbeats: bool, -} - -struct Frame { - t: Instant, - heartbeats: u32, -} - -#[derive(Default)] -struct Message { - duration: Duration, - label: Label, - detail: Option, -} - -impl ProfileStack { - fn new() -> ProfileStack { - ProfileStack { - frames: Vec::new(), - messages: Tree::default(), - filter: Default::default(), - heartbeats: false, - } - } - - fn push(&mut self, label: Label) -> bool { - if self.frames.is_empty() { - if let Ok(f) = FILTER.try_read() { - if f.version > self.filter.version { - self.filter = f.clone(); - } - }; - } - if self.frames.len() > self.filter.depth { - return false; - } - let allowed = &self.filter.allowed; - if self.frames.is_empty() && !allowed.is_empty() && !allowed.contains(label) { - return false; - } - - self.frames.push(Frame { t: Instant::now(), heartbeats: 0 }); - self.messages.start(); - true - } - - fn pop(&mut self, label: Label, detail: Option) { - let frame = self.frames.pop().unwrap(); - let duration = frame.t.elapsed(); - - if self.heartbeats { - self.heartbeat(frame.heartbeats); - let avg_span = duration / (frame.heartbeats + 1); - if avg_span > self.filter.heartbeat_longer_than { - eprintln!("Too few heartbeats {label} ({}/{duration:?})?", frame.heartbeats); - } - } - - self.messages.finish(Message { duration, label, detail }); - if self.frames.is_empty() { - let longer_than = self.filter.longer_than; - // Convert to millis for comparison to avoid problems with rounding - // (otherwise we could print `0ms` despite user's `>0` filter when - // `duration` is just a few nanos). - if duration.as_millis() > longer_than.as_millis() { - if let Some(root) = self.messages.root() { - print(&self.messages, root, 0, longer_than, &mut stderr().lock()); - } - } - self.messages.clear(); - } - } - - fn heartbeats(&mut self, yes: bool) { - self.heartbeats = yes; - } - fn heartbeat(&mut self, n: u32) { - if let Some(frame) = self.frames.last_mut() { - frame.heartbeats += n; - } - } -} - -fn print( - tree: &Tree, - curr: Idx, - level: u32, - longer_than: Duration, - out: &mut impl Write, -) { - let current_indent = " ".repeat(level as usize); - let detail = tree[curr].detail.as_ref().map(|it| format!(" @ {it}")).unwrap_or_default(); - writeln!( - out, - "{}{} - {}{}", - current_indent, - ms(tree[curr].duration), - tree[curr].label, - detail, - ) - .expect("printing profiling info"); - - let mut accounted_for = Duration::default(); - let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output. - for child in tree.children(curr) { - accounted_for += tree[child].duration; - - if tree[child].duration.as_millis() > longer_than.as_millis() { - print(tree, child, level + 1, longer_than, out); - } else { - let (total_duration, cnt) = - short_children.entry(tree[child].label).or_insert((Duration::default(), 0)); - *total_duration += tree[child].duration; - *cnt += 1; - } - } - - for (child_msg, (duration, count)) in &short_children { - writeln!(out, " {current_indent}{} - {child_msg} ({count} calls)", ms(*duration)) - .expect("printing profiling info"); - } - - let unaccounted = tree[curr].duration - accounted_for; - if tree.children(curr).next().is_some() && unaccounted > longer_than { - writeln!(out, " {current_indent}{} - ???", ms(unaccounted)) - .expect("printing profiling info"); - } -} - -#[allow(non_camel_case_types)] -struct ms(Duration); - -impl fmt::Display for ms { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0.as_millis() { - 0 => f.write_str(" 0 "), - n => write!(f, "{n:5}ms"), - } - } -} diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs index fdd724e2aab45..38c5b3fc9c725 100644 --- a/src/tools/rust-analyzer/crates/profile/src/lib.rs +++ b/src/tools/rust-analyzer/crates/profile/src/lib.rs @@ -2,17 +2,14 @@ #![warn(rust_2018_idioms, unused_lifetimes)] -mod stop_watch; -mod memory_usage; #[cfg(feature = "cpu_profiler")] mod google_cpu_profiler; -mod hprof; -mod tree; +mod memory_usage; +mod stop_watch; use std::cell::RefCell; pub use crate::{ - hprof::{heartbeat, heartbeat_span, init, init_from, span}, memory_usage::{Bytes, MemoryUsage}, stop_watch::{StopWatch, StopWatchSpan}, }; diff --git a/src/tools/rust-analyzer/crates/profile/src/tree.rs b/src/tools/rust-analyzer/crates/profile/src/tree.rs deleted file mode 100644 index 1290fba36fab3..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/tree.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! A simple tree implementation which tries to not allocate all over the place. -use std::ops; - -use la_arena::Arena; - -#[derive(Default)] -pub(crate) struct Tree { - nodes: Arena>, - current_path: Vec<(Idx, Option>)>, -} - -pub(crate) type Idx = la_arena::Idx>; - -impl Tree { - pub(crate) fn start(&mut self) - where - T: Default, - { - let me = self.nodes.alloc(Node::new(T::default())); - if let Some((parent, last_child)) = self.current_path.last_mut() { - let slot = match *last_child { - Some(last_child) => &mut self.nodes[last_child].next_sibling, - None => &mut self.nodes[*parent].first_child, - }; - let prev = slot.replace(me); - assert!(prev.is_none()); - *last_child = Some(me); - } - - self.current_path.push((me, None)); - } - - pub(crate) fn finish(&mut self, data: T) { - let (me, _last_child) = self.current_path.pop().unwrap(); - self.nodes[me].data = data; - } - - pub(crate) fn root(&self) -> Option> { - self.nodes.iter().next().map(|(idx, _)| idx) - } - - pub(crate) fn children(&self, idx: Idx) -> impl Iterator> + '_ { - NodeIter { nodes: &self.nodes, next: self.nodes[idx].first_child } - } - pub(crate) fn clear(&mut self) { - self.nodes.clear(); - self.current_path.clear(); - } -} - -impl ops::Index> for Tree { - type Output = T; - fn index(&self, index: Idx) -> &T { - &self.nodes[index].data - } -} - -pub(crate) struct Node { - data: T, - first_child: Option>, - next_sibling: Option>, -} - -impl Node { - fn new(data: T) -> Node { - Node { data, first_child: None, next_sibling: None } - } -} - -struct NodeIter<'a, T> { - nodes: &'a Arena>, - next: Option>, -} - -impl Iterator for NodeIter<'_, T> { - type Item = Idx; - - fn next(&mut self) -> Option> { - self.next.map(|next| { - self.next = self.nodes[next].next_sibling; - next - }) - } -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs index 68cd40c040b3d..c1670c2004902 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs @@ -60,6 +60,7 @@ impl WorkspaceBuildScripts { fn build_command( config: &CargoConfig, allowed_features: &FxHashSet, + workspace_root: &AbsPathBuf, ) -> io::Result { let mut cmd = match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { @@ -73,6 +74,9 @@ impl WorkspaceBuildScripts { cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(&config.extra_args); + cmd.arg("--manifest-path"); + cmd.arg(workspace_root.join("Cargo.toml").as_os_str()); + if let Some(target_dir) = &config.target_dir { cmd.arg("--target-dir").arg(target_dir); } @@ -143,7 +147,11 @@ impl WorkspaceBuildScripts { let allowed_features = workspace.workspace_features(); match Self::run_per_ws( - Self::build_command(config, &allowed_features)?, + Self::build_command( + config, + &allowed_features, + &workspace.workspace_root().to_path_buf(), + )?, workspace, current_dir, progress, @@ -153,7 +161,11 @@ impl WorkspaceBuildScripts { { // building build scripts failed, attempt to build with --keep-going so // that we potentially get more build data - let mut cmd = Self::build_command(config, &allowed_features)?; + let mut cmd = Self::build_command( + config, + &allowed_features, + &workspace.workspace_root().to_path_buf(), + )?; cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; res.error = Some(error); @@ -169,6 +181,7 @@ impl WorkspaceBuildScripts { config: &CargoConfig, workspaces: &[&CargoWorkspace], progress: &dyn Fn(String), + workspace_root: &AbsPathBuf, ) -> io::Result> { assert_eq!(config.invocation_strategy, InvocationStrategy::Once); @@ -181,7 +194,7 @@ impl WorkspaceBuildScripts { )) } }; - let cmd = Self::build_command(config, &Default::default())?; + let cmd = Self::build_command(config, &Default::default(), workspace_root)?; // NB: Cargo.toml could have been modified between `cargo metadata` and // `cargo check`. We shouldn't assume that package ids we see here are // exactly those from `config`. diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index bc1fcd08e20ce..361f8721a4ec2 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -82,6 +82,8 @@ pub struct CargoConfig { pub target: Option, /// Sysroot loading behavior pub sysroot: Option, + /// Whether to invoke `cargo metadata` on the sysroot crate. + pub sysroot_query_metadata: bool, pub sysroot_src: Option, /// rustc private crate source pub rustc_source: Option, @@ -366,7 +368,7 @@ impl CargoWorkspace { name, root: AbsPathBuf::assert(src_path.into()), kind: TargetKind::new(&kind), - is_proc_macro: &*kind == ["proc-macro"], + is_proc_macro: *kind == ["proc-macro"], required_features, }); pkg_data.targets.push(tgt); @@ -439,7 +441,7 @@ impl CargoWorkspace { .collect::>(); // some packages has this pkg as dep. return their manifests - if parent_manifests.len() > 0 { + if !parent_manifests.is_empty() { return Some(parent_manifests); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index 5f9b708289d16..5114c9c016ded 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -17,15 +17,15 @@ #![warn(rust_2018_idioms, unused_lifetimes)] -mod manifest_path; +mod build_scripts; mod cargo_workspace; mod cfg_flag; +mod manifest_path; mod project_json; -mod sysroot; -mod workspace; mod rustc_cfg; -mod build_scripts; +mod sysroot; pub mod target_data_layout; +mod workspace; #[cfg(test)] mod tests; diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs index 490e1a4ea8860..d86e81e7e1aca 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs @@ -36,7 +36,7 @@ impl ManifestPath { } pub fn canonicalize(&self) -> ! { - (&**self).canonicalize() + (**self).canonicalize() } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs index c5d55f7d2171f..cf12d5b71df56 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs @@ -26,7 +26,7 @@ pub(crate) fn get( extra_env: &FxHashMap, config: RustcCfgConfig<'_>, ) -> Vec { - let _p = profile::span("rustc_cfg::get"); + let _p = tracing::span!(tracing::Level::INFO, "rustc_cfg::get").entered(); let mut res = Vec::with_capacity(6 * 2 + 1); // Some nightly-only cfgs, which are required for stdlib diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index d52e448d74700..c24c0196dd9b3 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -8,6 +8,7 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command}; use anyhow::{format_err, Context, Result}; use base_db::CrateName; +use itertools::Itertools; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; @@ -18,42 +19,29 @@ use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; pub struct Sysroot { root: AbsPathBuf, src_root: AbsPathBuf, - crates: Arena, - /// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace. - pub hack_cargo_workspace: Option, + mode: SysrootMode, } -pub(crate) type SysrootCrate = Idx; +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) enum SysrootMode { + Workspace(CargoWorkspace), + Stitched(Stitched), +} #[derive(Debug, Clone, Eq, PartialEq)] -pub struct SysrootCrateData { - pub name: String, - pub root: ManifestPath, - pub deps: Vec, +pub(crate) struct Stitched { + crates: Arena, } -impl ops::Index for Sysroot { +impl ops::Index for Stitched { type Output = SysrootCrateData; fn index(&self, index: SysrootCrate) -> &SysrootCrateData { &self.crates[index] } } -impl Sysroot { - /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` - /// subfolder live, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` - pub fn root(&self) -> &AbsPath { - &self.root - } - - /// Returns the sysroot "source" directory, where stdlib sources are located, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` - pub fn src_root(&self) -> &AbsPath { - &self.src_root - } - - pub fn public_deps(&self) -> impl Iterator + '_ { +impl Stitched { + pub(crate) fn public_deps(&self) -> impl Iterator + '_ { // core is added as a dependency before std in order to // mimic rustcs dependency order ["core", "alloc", "std"] @@ -65,20 +53,56 @@ impl Sysroot { }) } - pub fn proc_macro(&self) -> Option { + pub(crate) fn proc_macro(&self) -> Option { self.by_name("proc_macro") } - pub fn crates(&self) -> impl Iterator + ExactSizeIterator + '_ { + pub(crate) fn crates(&self) -> impl Iterator + ExactSizeIterator + '_ { self.crates.iter().map(|(id, _data)| id) } + fn by_name(&self, name: &str) -> Option { + let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?; + Some(id) + } +} + +pub(crate) type SysrootCrate = Idx; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) struct SysrootCrateData { + pub(crate) name: String, + pub(crate) root: ManifestPath, + pub(crate) deps: Vec, +} + +impl Sysroot { + /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` + /// subfolder live, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` + pub fn root(&self) -> &AbsPath { + &self.root + } + + /// Returns the sysroot "source" directory, where stdlib sources are located, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` + pub fn src_root(&self) -> &AbsPath { + &self.src_root + } + pub fn is_empty(&self) -> bool { - self.crates.is_empty() + match &self.mode { + SysrootMode::Workspace(ws) => ws.packages().next().is_none(), + SysrootMode::Stitched(stitched) => stitched.crates.is_empty(), + } } pub fn loading_warning(&self) -> Option { - if self.by_name("core").is_none() { + let has_core = match &self.mode { + SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"), + SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(), + }; + if !has_core { let var_note = if env::var_os("RUST_SRC_PATH").is_some() { " (`RUST_SRC_PATH` might be incorrect, try unsetting it)" } else { @@ -92,27 +116,43 @@ impl Sysroot { None } } + + pub fn num_packages(&self) -> usize { + match &self.mode { + SysrootMode::Workspace(ws) => ws.packages().count(), + SysrootMode::Stitched(c) => c.crates().count(), + } + } + + pub(crate) fn mode(&self) -> &SysrootMode { + &self.mode + } } // FIXME: Expose a builder api as loading the sysroot got way too modular and complicated. impl Sysroot { /// Attempts to discover the toolchain's sysroot from the given `dir`. - pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Result { + pub fn discover( + dir: &AbsPath, + extra_env: &FxHashMap, + metadata: bool, + ) -> Result { tracing::debug!("discovering sysroot for {dir}"); let sysroot_dir = discover_sysroot_dir(dir, extra_env)?; let sysroot_src_dir = discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?; - Ok(Sysroot::load(sysroot_dir, sysroot_src_dir)) + Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata)) } pub fn discover_with_src_override( current_dir: &AbsPath, extra_env: &FxHashMap, src: AbsPathBuf, + metadata: bool, ) -> Result { tracing::debug!("discovering sysroot for {current_dir}"); let sysroot_dir = discover_sysroot_dir(current_dir, extra_env)?; - Ok(Sysroot::load(sysroot_dir, src)) + Ok(Sysroot::load(sysroot_dir, src, metadata)) } pub fn discover_rustc_src(&self) -> Option { @@ -131,49 +171,129 @@ impl Sysroot { } } - pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result { + pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Result { let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| { format_err!("can't load standard library from sysroot path {sysroot_dir}") })?; - Ok(Sysroot::load(sysroot_dir, sysroot_src_dir)) + Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata)) } - pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot { - // FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies - let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") { - let cargo_toml = ManifestPath::try_from( - AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(), - ) - .unwrap(); - sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library"); - CargoWorkspace::fetch_metadata( - &cargo_toml, - &AbsPathBuf::try_from("/").unwrap(), - &CargoConfig::default(), - &|_| (), - ) - .map(CargoWorkspace::new) - .ok() - } else { - None - }; - let mut sysroot = Sysroot { - root: sysroot_dir, - src_root: sysroot_src_dir, - crates: Arena::default(), - hack_cargo_workspace, - }; + pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf, metadata: bool) -> Sysroot { + if metadata { + let sysroot: Option<_> = (|| { + let sysroot_cargo_toml = ManifestPath::try_from( + AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot/Cargo.toml")).ok()?, + ) + .ok()?; + let current_dir = + AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot")).ok()?; + let res = CargoWorkspace::fetch_metadata( + &sysroot_cargo_toml, + ¤t_dir, + &CargoConfig::default(), + &|_| (), + ) + .map_err(|e| { + tracing::error!( + "failed to load sysroot `{sysroot_src_dir}/sysroot/Cargo.toml`: {}", + e + ); + e + }); + if let Err(e) = + std::fs::remove_file(format!("{sysroot_src_dir}/sysroot/Cargo.lock")) + { + tracing::error!( + "failed to remove sysroot `{sysroot_src_dir}/sysroot/Cargo.lock`: {}", + e + ) + } + let mut res = res.ok()?; + + // Patch out `rustc-std-workspace-*` crates to point to the real crates. + // This is done prior to `CrateGraph` construction to avoid having duplicate `std` targets. + + let mut fake_core = None; + let mut fake_alloc = None; + let mut fake_std = None; + let mut real_core = None; + let mut real_alloc = None; + let mut real_std = None; + res.packages.iter().enumerate().for_each(|(idx, package)| { + match package.name.strip_prefix("rustc-std-workspace-") { + Some("core") => fake_core = Some((idx, package.id.clone())), + Some("alloc") => fake_alloc = Some((idx, package.id.clone())), + Some("std") => fake_std = Some((idx, package.id.clone())), + Some(_) => { + tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name) + } + None => match &*package.name { + "core" => real_core = Some(package.id.clone()), + "alloc" => real_alloc = Some(package.id.clone()), + "std" => real_std = Some(package.id.clone()), + _ => (), + }, + } + }); + + let patches = + [fake_core.zip(real_core), fake_alloc.zip(real_alloc), fake_std.zip(real_std)] + .into_iter() + .flatten(); + + let resolve = res.resolve.as_mut().expect("metadata executed with deps"); + let mut remove_nodes = vec![]; + for (idx, node) in resolve.nodes.iter_mut().enumerate() { + // Replace them in the dependency list + node.deps.iter_mut().for_each(|dep| { + if let Some((_, real)) = + patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg) + { + dep.pkg = real; + } + }); + if patches.clone().any(|((_, fake), _)| fake == node.id) { + remove_nodes.push(idx); + } + } + // Remove the fake ones from the resolve data + remove_nodes.into_iter().rev().for_each(|r| { + resolve.nodes.remove(r); + }); + // Remove the fake ones from the packages + patches.map(|((r, _), _)| r).sorted().rev().for_each(|r| { + res.packages.remove(r); + }); + + res.workspace_members = res + .packages + .iter() + .filter(|&package| RELEVANT_SYSROOT_CRATES.contains(&&*package.name)) + .map(|package| package.id.clone()) + .collect(); + let cargo_workspace = CargoWorkspace::new(res); + Some(Sysroot { + root: sysroot_dir.clone(), + src_root: sysroot_src_dir.clone(), + mode: SysrootMode::Workspace(cargo_workspace), + }) + })(); + if let Some(sysroot) = sysroot { + return sysroot; + } + } + let mut stitched = Stitched { crates: Arena::default() }; for path in SYSROOT_CRATES.trim().lines() { let name = path.split('/').last().unwrap(); let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")] .into_iter() - .map(|it| sysroot.src_root.join(it)) + .map(|it| sysroot_src_dir.join(it)) .filter_map(|it| ManifestPath::try_from(it).ok()) .find(|it| fs::metadata(it).is_ok()); if let Some(root) = root { - sysroot.crates.alloc(SysrootCrateData { + stitched.crates.alloc(SysrootCrateData { name: name.into(), root, deps: Vec::new(), @@ -181,36 +301,34 @@ impl Sysroot { } } - if let Some(std) = sysroot.by_name("std") { + if let Some(std) = stitched.by_name("std") { for dep in STD_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[std].deps.push(dep) + if let Some(dep) = stitched.by_name(dep) { + stitched.crates[std].deps.push(dep) } } } - if let Some(alloc) = sysroot.by_name("alloc") { + if let Some(alloc) = stitched.by_name("alloc") { for dep in ALLOC_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[alloc].deps.push(dep) + if let Some(dep) = stitched.by_name(dep) { + stitched.crates[alloc].deps.push(dep) } } } - if let Some(proc_macro) = sysroot.by_name("proc_macro") { + if let Some(proc_macro) = stitched.by_name("proc_macro") { for dep in PROC_MACRO_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[proc_macro].deps.push(dep) + if let Some(dep) = stitched.by_name(dep) { + stitched.crates[proc_macro].deps.push(dep) } } } - - sysroot - } - - fn by_name(&self, name: &str) -> Option { - let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?; - Some(id) + Sysroot { + root: sysroot_dir, + src_root: sysroot_src_dir, + mode: SysrootMode::Stitched(stitched), + } } } @@ -318,3 +436,5 @@ test"; const PROC_MACRO_DEPS: &str = " std core"; + +const RELEVANT_SYSROOT_CRATES: &[&str] = &["core", "alloc", "std", "test", "proc_macro"]; diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 4887b29815ae2..7c078f72f5294 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -38,7 +38,7 @@ fn load_cargo_with_overrides( to_crate_graph(project_workspace) } -fn load_cargo_with_sysroot( +fn load_cargo_with_fake_sysroot( file_map: &mut FxHashMap, file: &str, ) -> (CrateGraph, ProcMacroPaths) { @@ -106,7 +106,7 @@ fn replace_fake_sys_root(s: &mut String) { let fake_sysroot_path = get_test_path("fake-sysroot"); let fake_sysroot_path = if cfg!(windows) { let normalized_path = - fake_sysroot_path.to_str().expect("expected str").replace(r#"\"#, r#"\\"#); + fake_sysroot_path.to_str().expect("expected str").replace('\\', r#"\\"#); format!(r#"{}\\"#, normalized_path) } else { format!("{}/", fake_sysroot_path.to_str().expect("expected str")) @@ -125,7 +125,7 @@ fn get_fake_sysroot() -> Sysroot { // fake sysroot, so we give them both the same path: let sysroot_dir = AbsPathBuf::assert(sysroot_path); let sysroot_src_dir = sysroot_dir.clone(); - Sysroot::load(sysroot_dir, sysroot_src_dir) + Sysroot::load(sysroot_dir, sysroot_src_dir, false) } fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { @@ -225,12 +225,12 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() { #[test] fn crate_graph_dedup_identical() { let (mut crate_graph, proc_macros) = - load_cargo_with_sysroot(&mut Default::default(), "regex-metadata.json"); + load_cargo_with_fake_sysroot(&mut Default::default(), "regex-metadata.json"); crate_graph.sort_deps(); let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone()); - crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros); + crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros, |_| ()); assert!(crate_graph.iter().eq(d_crate_graph.iter())); assert_eq!(proc_macros, d_proc_macros); } @@ -239,14 +239,14 @@ fn crate_graph_dedup_identical() { fn crate_graph_dedup() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = - load_cargo_with_sysroot(path_map, "ripgrep-metadata.json"); + load_cargo_with_fake_sysroot(path_map, "ripgrep-metadata.json"); assert_eq!(crate_graph.iter().count(), 81); crate_graph.sort_deps(); let (regex_crate_graph, mut regex_proc_macros) = - load_cargo_with_sysroot(path_map, "regex-metadata.json"); + load_cargo_with_fake_sysroot(path_map, "regex-metadata.json"); assert_eq!(regex_crate_graph.iter().count(), 60); - crate_graph.extend(regex_crate_graph, &mut regex_proc_macros); + crate_graph.extend(regex_crate_graph, &mut regex_proc_macros, |_| ()); assert_eq!(crate_graph.iter().count(), 118); } @@ -254,12 +254,12 @@ fn crate_graph_dedup() { fn test_deduplicate_origin_dev() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json"); crate_graph.sort_deps(); let (crate_graph_1, mut _proc_macros_2) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json"); - crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ()); let mut crates_named_p2 = vec![]; for id in crate_graph.iter() { @@ -280,12 +280,12 @@ fn test_deduplicate_origin_dev() { fn test_deduplicate_origin_dev_rev() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json"); crate_graph.sort_deps(); let (crate_graph_1, mut _proc_macros_2) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json"); - crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ()); let mut crates_named_p2 = vec![]; for id in crate_graph.iter() { @@ -301,3 +301,40 @@ fn test_deduplicate_origin_dev_rev() { let p2 = crates_named_p2[0]; assert!(p2.origin.is_local()); } + +#[test] +fn smoke_test_real_sysroot_cargo() { + if std::env::var("SYSROOT_CARGO_METADATA").is_err() { + return; + } + let file_map = &mut FxHashMap::::default(); + let meta = get_test_json_file("hello-world-metadata.json"); + + let cargo_workspace = CargoWorkspace::new(meta); + let sysroot = Ok(Sysroot::discover( + AbsPath::assert(Path::new(env!("CARGO_MANIFEST_DIR"))), + &Default::default(), + true, + ) + .unwrap()); + + let project_workspace = ProjectWorkspace::Cargo { + cargo: cargo_workspace, + build_scripts: WorkspaceBuildScripts::default(), + sysroot, + rustc: Err(None), + rustc_cfg: Vec::new(), + cfg_overrides: Default::default(), + toolchain: None, + target_layout: Err("target_data_layout not loaded".into()), + }; + project_workspace.to_crate_graph( + &mut { + |path| { + let len = file_map.len(); + Some(*file_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32))) + } + }, + &Default::default(), + ); +} diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index c04eddc56fb7f..8c5ea0619ac7e 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -9,7 +9,7 @@ use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind, Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, }; -use cfg::{CfgDiff, CfgOptions}; +use cfg::{CfgAtom, CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; @@ -22,7 +22,7 @@ use crate::{ cfg_flag::CfgFlag, project_json::Crate, rustc_cfg::{self, RustcCfgConfig}, - sysroot::SysrootCrate, + sysroot::{SysrootCrate, SysrootMode}, target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts, }; @@ -38,7 +38,7 @@ pub struct CfgOverrides { impl CfgOverrides { pub fn len(&self) -> usize { - self.global.len() + self.selective.iter().map(|(_, it)| it.len()).sum::() + self.global.len() + self.selective.values().map(|it| it.len()).sum::() } } @@ -60,7 +60,7 @@ pub enum ProjectWorkspace { cargo: CargoWorkspace, build_scripts: WorkspaceBuildScripts, sysroot: Result>, - rustc: Result<(CargoWorkspace, WorkspaceBuildScripts), Option>, + rustc: Result, Option>, /// Holds cfg flags for the current target. We get those by running /// `rustc --print cfg`. /// @@ -119,7 +119,7 @@ impl fmt::Debug for ProjectWorkspace { .field("sysroot", &sysroot.is_ok()) .field( "n_rustc_compiler_crates", - &rustc.as_ref().map_or(0, |(rc, _)| rc.packages().len()), + &rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(rc, _)| rc.packages().len()), ) .field("n_rustc_cfg", &rustc_cfg.len()) .field("n_cfg_overrides", &cfg_overrides.len()) @@ -130,7 +130,7 @@ impl fmt::Debug for ProjectWorkspace { let mut debug_struct = f.debug_struct("Json"); debug_struct.field("n_crates", &project.n_crates()); if let Ok(sysroot) = sysroot { - debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); + debug_struct.field("n_sysroot_crates", &sysroot.num_packages()); } debug_struct.field("toolchain", &toolchain); debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); @@ -177,7 +177,7 @@ impl ProjectWorkspace { }; let res = match manifest { ProjectManifest::ProjectJson(project_json) => { - let file = fs::read_to_string(&project_json) + let file = fs::read_to_string(project_json) .with_context(|| format!("Failed to read json file {project_json}"))?; let data = serde_json::from_str(&file) .with_context(|| format!("Failed to deserialize json file {project_json}"))?; @@ -194,7 +194,7 @@ impl ProjectWorkspace { ProjectManifest::CargoToml(cargo_toml) => { let toolchain = version(cargo_toml.parent(), toolchain::cargo(), "cargo ")?; let meta = CargoWorkspace::fetch_metadata( - &cargo_toml, + cargo_toml, cargo_toml.parent(), config, progress, @@ -208,23 +208,23 @@ impl ProjectWorkspace { let sysroot = match (&config.sysroot, &config.sysroot_src) { (Some(RustLibSource::Path(path)), None) => { - Sysroot::with_sysroot_dir(path.clone()).map_err(|e| { + Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata).map_err(|e| { Some(format!("Failed to find sysroot at {path}:{e}")) }) } (Some(RustLibSource::Discover), None) => { - Sysroot::discover(cargo_toml.parent(), &config.extra_env).map_err(|e| { + Sysroot::discover(cargo_toml.parent(), &config.extra_env, config.sysroot_query_metadata).map_err(|e| { Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}")) }) } (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => { - Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone())) + Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone(), config.sysroot_query_metadata)) } (Some(RustLibSource::Discover), Some(sysroot_src)) => { Sysroot::discover_with_src_override( cargo_toml.parent(), &config.extra_env, - sysroot_src.clone(), + sysroot_src.clone(), config.sysroot_query_metadata, ).map_err(|e| { Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}")) }) @@ -241,7 +241,7 @@ impl ProjectWorkspace { .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))), Some(RustLibSource::Discover) => { sysroot.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else( - || Some(format!("Failed to discover rustc source for sysroot.")), + || Some("Failed to discover rustc source for sysroot.".to_string()), ) } None => Err(None), @@ -265,7 +265,7 @@ impl ProjectWorkspace { cargo_toml.parent(), &config.extra_env, ); - Ok((workspace, buildscripts)) + Ok(Box::new((workspace, buildscripts))) } Err(e) => { tracing::error!( @@ -287,7 +287,7 @@ impl ProjectWorkspace { let cfg_overrides = config.cfg_overrides.clone(); let data_layout = target_data_layout::get( - Some(&cargo_toml), + Some(cargo_toml), config.target.as_deref(), &config.extra_env, ); @@ -317,12 +317,12 @@ impl ProjectWorkspace { toolchain: Option, ) -> ProjectWorkspace { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { - (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)), + (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src, false)), (Some(sysroot), None) => { // assume sysroot is structured like rustup's and guess `sysroot_src` let sysroot_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); - Ok(Sysroot::load(sysroot, sysroot_src)) + Ok(Sysroot::load(sysroot, sysroot_src, false)) } (None, Some(sysroot_src)) => { // assume sysroot is structured like rustup's and guess `sysroot` @@ -330,7 +330,7 @@ impl ProjectWorkspace { for _ in 0..5 { sysroot.pop(); } - Ok(Sysroot::load(sysroot, sysroot_src)) + Ok(Sysroot::load(sysroot, sysroot_src, false)) } (None, None) => Err(None), }; @@ -354,16 +354,22 @@ impl ProjectWorkspace { config: &CargoConfig, ) -> anyhow::Result { let sysroot = match &config.sysroot { - Some(RustLibSource::Path(path)) => Sysroot::with_sysroot_dir(path.clone()) - .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))), + Some(RustLibSource::Path(path)) => { + Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) + .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) + } Some(RustLibSource::Discover) => { let dir = &detached_files .first() .and_then(|it| it.parent()) .ok_or_else(|| format_err!("No detached files to load"))?; - Sysroot::discover(dir, &config.extra_env).map_err(|e| { - Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}")) - }) + Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata).map_err( + |e| { + Some(format!( + "Failed to find sysroot for {dir}. Is rust-src installed? {e}" + )) + }, + ) } None => Err(None), }; @@ -407,6 +413,7 @@ impl ProjectWorkspace { workspaces: &[ProjectWorkspace], config: &CargoConfig, progress: &dyn Fn(String), + workspace_root: &AbsPathBuf, ) -> Vec> { if matches!(config.invocation_strategy, InvocationStrategy::PerWorkspace) || config.run_build_script_command.is_none() @@ -421,11 +428,13 @@ impl ProjectWorkspace { _ => None, }) .collect(); - let outputs = &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) { - Ok(it) => Ok(it.into_iter()), - // io::Error is not Clone? - Err(e) => Err(sync::Arc::new(e)), - }; + let outputs = + &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress, workspace_root) + { + Ok(it) => Ok(it.into_iter()), + // io::Error is not Clone? + Err(e) => Err(sync::Arc::new(e)), + }; workspaces .iter() @@ -494,13 +503,43 @@ impl ProjectWorkspace { /// The return type contains the path and whether or not /// the root is a member of the current workspace pub fn to_roots(&self) -> Vec { - let mk_sysroot = |sysroot: Result<&Sysroot, _>, project_root: Option<&AbsPath>| { - sysroot.map(|sysroot| PackageRoot { - // mark the sysroot as mutable if it is located inside of the project - is_local: project_root - .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)), - include: vec![sysroot.src_root().to_path_buf()], - exclude: Vec::new(), + let mk_sysroot = |sysroot: Result<_, _>, project_root: Option<&AbsPath>| { + let project_root = project_root.map(ToOwned::to_owned); + sysroot.into_iter().flat_map(move |sysroot: &Sysroot| { + let mut r = match sysroot.mode() { + SysrootMode::Workspace(ws) => ws + .packages() + .filter_map(|pkg| { + if ws[pkg].is_local { + // the local ones are included in the main `PackageRoot`` below + return None; + } + let pkg_root = ws[pkg].manifest.parent().to_path_buf(); + + let include = vec![pkg_root.clone()]; + + let exclude = vec![ + pkg_root.join(".git"), + pkg_root.join("target"), + pkg_root.join("tests"), + pkg_root.join("examples"), + pkg_root.join("benches"), + ]; + Some(PackageRoot { is_local: false, include, exclude }) + }) + .collect(), + SysrootMode::Stitched(_) => vec![], + }; + + r.push(PackageRoot { + // mark the sysroot as mutable if it is located inside of the project + is_local: project_root + .as_ref() + .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)), + include: vec![sysroot.src_root().to_path_buf()], + exclude: Vec::new(), + }); + r }) }; match self { @@ -564,7 +603,7 @@ impl ProjectWorkspace { PackageRoot { is_local, include, exclude } }) .chain(mk_sysroot(sysroot.as_ref(), Some(cargo.workspace_root()))) - .chain(rustc.iter().flat_map(|(rustc, _)| { + .chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| { rustc.packages().map(move |krate| PackageRoot { is_local: false, include: vec![rustc[krate].manifest.parent().to_path_buf()], @@ -588,16 +627,17 @@ impl ProjectWorkspace { pub fn n_packages(&self) -> usize { match self { ProjectWorkspace::Json { project, sysroot, .. } => { - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); sysroot_package_len + project.n_crates() } ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { - let rustc_package_len = rustc.as_ref().map_or(0, |(it, _)| it.packages().len()); - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + let rustc_package_len = + rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(it, _)| it.packages().len()); + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); cargo.packages().len() + sysroot_package_len + rustc_package_len } ProjectWorkspace::DetachedFiles { sysroot, files, .. } => { - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); sysroot_package_len + files.len() } } @@ -608,7 +648,7 @@ impl ProjectWorkspace { load: &mut dyn FnMut(&AbsPath) -> Option, extra_env: &FxHashMap, ) -> (CrateGraph, ProcMacroPaths) { - let _p = profile::span("ProjectWorkspace::to_crate_graph"); + let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered(); let (mut crate_graph, proc_macros) = match self { ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => { @@ -633,12 +673,11 @@ impl ProjectWorkspace { target_layout, } => cargo_to_crate_graph( load, - rustc.as_ref().ok(), + rustc.as_ref().map(|a| a.as_ref()).ok(), cargo, sysroot.as_ref().ok(), rustc_cfg.clone(), cfg_overrides, - None, build_scripts, match target_layout.as_ref() { Ok(it) => Ok(Arc::from(it.as_str())), @@ -849,13 +888,11 @@ fn cargo_to_crate_graph( sysroot: Option<&Sysroot>, rustc_cfg: Vec, override_cfg: &CfgOverrides, - // Don't compute cfg and use this if present, only used for the sysroot experiment hack - forced_cfg: Option, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, toolchain: Option<&Version>, ) -> (CrateGraph, ProcMacroPaths) { - let _p = profile::span("cargo_to_crate_graph"); + let _p = tracing::span!(tracing::Level::INFO, "cargo_to_crate_graph").entered(); let mut res = (CrateGraph::default(), ProcMacroPaths::default()); let crate_graph = &mut res.0; let proc_macros = &mut res.1; @@ -883,7 +920,7 @@ fn cargo_to_crate_graph( for pkg in cargo.packages() { has_private |= cargo[pkg].metadata.rustc_private; - let cfg_options = forced_cfg.clone().unwrap_or_else(|| { + let cfg_options = { let mut cfg_options = cfg_options.clone(); // Add test cfg for local crates @@ -908,7 +945,7 @@ fn cargo_to_crate_graph( cfg_options.apply_diff(diff.clone()); }; cfg_options - }); + }; let mut lib_tgt = None; for &tgt in cargo[pkg].targets.iter() { @@ -1052,7 +1089,7 @@ fn detached_files_to_crate_graph( sysroot: Option<&Sysroot>, target_layout: TargetLayoutLoadResult, ) -> (CrateGraph, ProcMacroPaths) { - let _p = profile::span("detached_files_to_crate_graph"); + let _p = tracing::span!(tracing::Level::INFO, "detached_files_to_crate_graph").entered(); let mut crate_graph = CrateGraph::default(); let (public_deps, _libproc_macro) = match sysroot { Some(sysroot) => sysroot_to_crate_graph( @@ -1348,125 +1385,127 @@ fn sysroot_to_crate_graph( load: &mut dyn FnMut(&AbsPath) -> Option, toolchain: Option<&Version>, ) -> (SysrootPublicDeps, Option) { - let _p = profile::span("sysroot_to_crate_graph"); - let cfg_options = create_cfg_options(rustc_cfg.clone()); - let sysroot_crates: FxHashMap = match &sysroot.hack_cargo_workspace { - Some(cargo) => handle_hack_cargo_workspace( - load, - cargo, - rustc_cfg, - cfg_options, - target_layout, - toolchain, - crate_graph, - sysroot, - ), - None => sysroot - .crates() - .filter_map(|krate| { - let file_id = load(&sysroot[krate].root)?; - - let env = Env::default(); - let display_name = - CrateDisplayName::from_canonical_name(sysroot[krate].name.clone()); - let crate_id = crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - Some(display_name), - None, - cfg_options.clone(), - None, - env, - false, - CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), - target_layout.clone(), - toolchain.cloned(), - ); - Some((krate, crate_id)) - }) - .collect(), - }; - for from in sysroot.crates() { - for &to in sysroot[from].deps.iter() { - let name = CrateName::new(&sysroot[to].name).unwrap(); - if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { - add_dep(crate_graph, from, name, to, DependencyKind::Normal); + let _p = tracing::span!(tracing::Level::INFO, "sysroot_to_crate_graph").entered(); + match sysroot.mode() { + SysrootMode::Workspace(cargo) => { + let (mut cg, mut pm) = cargo_to_crate_graph( + load, + None, + cargo, + None, + rustc_cfg, + &CfgOverrides::default(), + &WorkspaceBuildScripts::default(), + target_layout, + toolchain, + ); + + let mut pub_deps = vec![]; + let mut libproc_macro = None; + let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap(); + for (cid, c) in cg.iter_mut() { + // uninject `test` flag so `core` keeps working. + c.cfg_options.apply_diff(diff.clone()); + // patch the origin + if c.origin.is_local() { + let lang_crate = LangCrateOrigin::from( + c.display_name.as_ref().map_or("", |it| it.canonical_name()), + ); + c.origin = CrateOrigin::Lang(lang_crate); + match lang_crate { + LangCrateOrigin::Test + | LangCrateOrigin::Alloc + | LangCrateOrigin::Core + | LangCrateOrigin::Std => pub_deps.push(( + CrateName::normalize_dashes(&lang_crate.to_string()), + cid, + !matches!(lang_crate, LangCrateOrigin::Test), + )), + LangCrateOrigin::ProcMacro => libproc_macro = Some(cid), + LangCrateOrigin::Other => (), + } + } } + + let mut marker_set = vec![]; + for &(_, cid, _) in pub_deps.iter() { + marker_set.extend(cg.transitive_deps(cid)); + } + if let Some(cid) = libproc_macro { + marker_set.extend(cg.transitive_deps(cid)); + } + + marker_set.sort(); + marker_set.dedup(); + + // Remove all crates except the ones we are interested in to keep the sysroot graph small. + let removed_mapping = cg.remove_crates_except(&marker_set); + + crate_graph.extend(cg, &mut pm, |mapping| { + // Map the id through the removal mapping first, then through the crate graph extension mapping. + pub_deps.iter_mut().for_each(|(_, cid, _)| { + *cid = mapping[&removed_mapping[cid.into_raw().into_u32() as usize].unwrap()] + }); + if let Some(libproc_macro) = &mut libproc_macro { + *libproc_macro = mapping + [&removed_mapping[libproc_macro.into_raw().into_u32() as usize].unwrap()]; + } + }); + + (SysrootPublicDeps { deps: pub_deps }, libproc_macro) } - } + SysrootMode::Stitched(stitched) => { + let cfg_options = create_cfg_options(rustc_cfg.clone()); + let sysroot_crates: FxHashMap = stitched + .crates() + .filter_map(|krate| { + let file_id = load(&stitched[krate].root)?; - let public_deps = SysrootPublicDeps { - deps: sysroot - .public_deps() - .filter_map(|(name, idx, prelude)| Some((name, *sysroot_crates.get(&idx)?, prelude))) - .collect::>(), - }; + let env = Env::default(); + let display_name = + CrateDisplayName::from_canonical_name(stitched[krate].name.clone()); + let crate_id = crate_graph.add_crate_root( + file_id, + Edition::CURRENT, + Some(display_name), + None, + cfg_options.clone(), + None, + env, + false, + CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)), + target_layout.clone(), + toolchain.cloned(), + ); + Some((krate, crate_id)) + }) + .collect(); + + for from in stitched.crates() { + for &to in stitched[from].deps.iter() { + let name = CrateName::new(&stitched[to].name).unwrap(); + if let (Some(&from), Some(&to)) = + (sysroot_crates.get(&from), sysroot_crates.get(&to)) + { + add_dep(crate_graph, from, name, to, DependencyKind::Normal); + } + } + } - let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied()); - (public_deps, libproc_macro) -} + let public_deps = SysrootPublicDeps { + deps: stitched + .public_deps() + .filter_map(|(name, idx, prelude)| { + Some((name, *sysroot_crates.get(&idx)?, prelude)) + }) + .collect::>(), + }; -fn handle_hack_cargo_workspace( - load: &mut dyn FnMut(&AbsPath) -> Option, - cargo: &CargoWorkspace, - rustc_cfg: Vec, - cfg_options: CfgOptions, - target_layout: Result, Arc>, - toolchain: Option<&Version>, - crate_graph: &mut CrateGraph, - sysroot: &Sysroot, -) -> FxHashMap { - let (cg, mut pm) = cargo_to_crate_graph( - load, - None, - cargo, - None, - rustc_cfg, - &CfgOverrides::default(), - Some(cfg_options), - &WorkspaceBuildScripts::default(), - target_layout, - toolchain, - ); - crate_graph.extend(cg, &mut pm); - for crate_name in ["std", "alloc", "core"] { - let original = crate_graph - .iter() - .find(|x| { - crate_graph[*x] - .display_name - .as_ref() - .map(|x| x.canonical_name() == crate_name) - .unwrap_or(false) - }) - .unwrap(); - let fake_crate_name = format!("rustc-std-workspace-{}", crate_name); - let fake = crate_graph - .iter() - .find(|x| { - crate_graph[*x] - .display_name - .as_ref() - .map(|x| x.canonical_name() == fake_crate_name) - .unwrap_or(false) - }) - .unwrap(); - crate_graph.remove_and_replace(fake, original).unwrap(); - } - for (_, c) in crate_graph.iter_mut() { - if c.origin.is_local() { - // LangCrateOrigin::Other is good enough for a hack. - c.origin = CrateOrigin::Lang(LangCrateOrigin::Other); + let libproc_macro = + stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied()); + (public_deps, libproc_macro) } } - sysroot - .crates() - .filter_map(|krate| { - let file_id = load(&sysroot[krate].root)?; - let crate_id = crate_graph.crate_id_for_crate_root(file_id)?; - Some((krate, crate_id)) - }) - .collect() } fn add_dep( diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index e35f0fc7327e2..0df99534c5bd9 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -182,7 +182,7 @@ }, ], origin: Lang( - Other, + ProcMacro, ), is_proc_macro: false, target_layout: Err( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 76414160716c8..a212041e66b46 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -23,7 +23,7 @@ anyhow.workspace = true crossbeam-channel = "0.5.5" dissimilar.workspace = true itertools.workspace = true -scip = "0.3.1" +scip = "0.3.3" lsp-types = { version = "=0.95.0", features = ["proposed"] } parking_lot = "0.12.1" xflags = "0.3.0" @@ -37,11 +37,10 @@ mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server.workspace = true tracing.workspace = true tracing-subscriber.workspace = true -tracing-log = "0.2.0" tracing-tree.workspace = true triomphe.workspace = true nohash-hasher.workspace = true -always-assert = "0.1.2" +always-assert = "0.2.0" walkdir = "2.3.2" cfg.workspace = true @@ -63,6 +62,7 @@ parser.workspace = true toolchain.workspace = true vfs-notify.workspace = true vfs.workspace = true +memchr = "2.7.1" [target.'cfg(windows)'.dependencies] winapi = "0.3.9" diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs deleted file mode 100644 index 1f923f6cf8dda..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Simple logger that logs either to stderr or to a file, using `tracing_subscriber` -//! filter syntax and `tracing_appender` for non blocking output. - -use std::{ - fmt, - fs::File, - io::{self, Stderr}, - sync::Arc, -}; - -use anyhow::Context; -use tracing::{level_filters::LevelFilter, Event, Subscriber}; -use tracing_log::NormalizeEvent; -use tracing_subscriber::{ - filter::Targets, - fmt::{ - format::Writer, writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields, - FormattedFields, MakeWriter, - }, - layer::SubscriberExt, - registry::LookupSpan, - util::SubscriberInitExt, - Registry, -}; -use tracing_tree::HierarchicalLayer; - -pub(crate) struct LoggerConfig { - pub(crate) log_file: Option, - pub(crate) filter: String, - pub(crate) chalk_filter: Option, -} - -struct MakeWriterStderr; - -impl MakeWriter<'_> for MakeWriterStderr { - type Writer = Stderr; - - fn make_writer(&self) -> Self::Writer { - io::stderr() - } -} - -impl LoggerConfig { - pub(crate) fn init(self) -> anyhow::Result<()> { - let mut filter: Targets = self - .filter - .parse() - .with_context(|| format!("invalid log filter: `{}`", self.filter))?; - - let mut chalk_layer = None; - if let Some(chalk_filter) = self.chalk_filter { - let level: LevelFilter = - chalk_filter.parse().with_context(|| "invalid chalk log filter")?; - chalk_layer = Some( - HierarchicalLayer::default() - .with_indent_lines(true) - .with_ansi(false) - .with_indent_amount(2) - .with_writer(io::stderr), - ); - filter = filter - .with_target("chalk_solve", level) - .with_target("chalk_ir", level) - .with_target("chalk_recursive", level); - }; - - let writer = match self.log_file { - Some(file) => BoxMakeWriter::new(Arc::new(file)), - None => BoxMakeWriter::new(io::stderr), - }; - let ra_fmt_layer = - tracing_subscriber::fmt::layer().event_format(LoggerFormatter).with_writer(writer); - - let registry = Registry::default().with(filter).with(ra_fmt_layer); - match chalk_layer { - Some(chalk_layer) => registry.with(chalk_layer).init(), - None => registry.init(), - } - Ok(()) - } -} - -#[derive(Debug)] -struct LoggerFormatter; - -impl FormatEvent for LoggerFormatter -where - S: Subscriber + for<'a> LookupSpan<'a>, - N: for<'a> FormatFields<'a> + 'static, -{ - fn format_event( - &self, - ctx: &FmtContext<'_, S, N>, - mut writer: Writer<'_>, - event: &Event<'_>, - ) -> fmt::Result { - // Write level and target - let level = *event.metadata().level(); - - // If this event is issued from `log` crate, then the value of target is - // always "log". `tracing-log` has hard coded it for some reason, so we - // need to extract it using `normalized_metadata` method which is part of - // `tracing_log::NormalizeEvent`. - let target = match event.normalized_metadata() { - // This event is issued from `log` crate - Some(log) => log.target(), - None => event.metadata().target(), - }; - write!(writer, "[{level} {target}] ")?; - - // Write spans and fields of each span - ctx.visit_spans(|span| { - write!(writer, "{}", span.name())?; - - let ext = span.extensions(); - - // `FormattedFields` is a formatted representation of the span's - // fields, which is stored in its extensions by the `fmt` layer's - // `new_span` method. The fields will have been formatted - // by the same field formatter that's provided to the event - // formatter in the `FmtContext`. - let fields = &ext.get::>().expect("will never be `None`"); - - if !fields.is_empty() { - write!(writer, "{{{fields}}}")?; - } - write!(writer, ": ")?; - - Ok(()) - })?; - - // Write fields on the event - ctx.field_format().format_fields(writer.by_ref(), event)?; - - writeln!(writer) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index 7432f0f7a7ce1..66b680571a97d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -7,17 +7,17 @@ #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; -mod logger; mod rustc_wrapper; -use std::{env, fs, path::PathBuf, process}; +use std::{env, fs, path::PathBuf, process, sync::Arc}; use anyhow::Context; use lsp_server::Connection; use rust_analyzer::{cli::flags, config::Config, from_json}; +use tracing_subscriber::fmt::writer::BoxMakeWriter; use vfs::AbsPathBuf; -#[cfg(all(feature = "mimalloc"))] +#[cfg(feature = "mimalloc")] #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -123,26 +123,21 @@ fn setup_logging(log_file_flag: Option) -> anyhow::Result<()> { None => None, }; - logger::LoggerConfig { - log_file, + let writer = match log_file { + Some(file) => BoxMakeWriter::new(Arc::new(file)), + None => BoxMakeWriter::new(std::io::stderr), + }; + + rust_analyzer::tracing::Config { + writer, // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually // useful information in there for debugging. filter: env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_string()), - // The meaning of CHALK_DEBUG I suspected is to tell chalk crates - // (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing - // logs. But now we can only have just one filter, which means we have to - // merge chalk filter to our main filter (from RA_LOG env). - // - // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. - // As the value should only affect chalk crates, we'd better manually - // specify the target. And for simplicity, CHALK_DEBUG only accept the value - // that specify level. chalk_filter: env::var("CHALK_DEBUG").ok(), + profile_filter: env::var("RA_PROFILE").ok(), } .init()?; - profile::init(); - Ok(()) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index de00c4192b46a..00670f2cb4c8d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -1,16 +1,16 @@ //! Various batch processing tasks, intended primarily for debugging. -pub mod flags; -mod parse; -mod symbols; -mod highlight; mod analysis_stats; mod diagnostics; -mod ssr; +pub mod flags; +mod highlight; mod lsif; -mod scip; +mod parse; mod run_tests; mod rustc_tests; +mod scip; +mod ssr; +mod symbols; mod progress_report; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index e69302dbaccf3..31bdd2a0e82b1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -58,10 +58,13 @@ impl flags::AnalysisStats { Rand32::new(seed) }; - let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = match self.no_sysroot { - true => None, - false => Some(RustLibSource::Discover), + let cargo_config = CargoConfig { + sysroot: match self.no_sysroot { + true => None, + false => Some(RustLibSource::Discover), + }, + sysroot_query_metadata: self.query_sysroot_metadata, + ..Default::default() }; let no_progress = &|_| (); @@ -276,7 +279,7 @@ impl flags::AnalysisStats { } all += 1; let Err(e) = db.layout_of_adt( - hir_def::AdtId::from(a).into(), + hir_def::AdtId::from(a), Substitution::empty(Interner), db.trait_environment(a.into()), ) else { @@ -301,13 +304,13 @@ impl flags::AnalysisStats { let mut fail = 0; for &c in consts { all += 1; - let Err(e) = c.render_eval(db) else { + let Err(error) = c.render_eval(db) else { continue; }; if verbosity.is_spammy() { let full_name = full_name_of_item(db, c.module(db), c.name(db).unwrap_or(Name::missing())); - println!("Const eval for {full_name} failed due {e:?}"); + println!("Const eval for {full_name} failed due {error:?}"); } fail += 1; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index abec2679464ea..6d2e97be20e50 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -13,10 +13,10 @@ use crate::cli::flags; impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { - let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustLibSource::Discover); + let cargo_config = + CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv { - let path = vfs::AbsPathBuf::assert(std::env::current_dir()?.join(&p)); + let path = vfs::AbsPathBuf::assert(std::env::current_dir()?.join(p)); ProcMacroServerChoice::Explicit(path) } else { ProcMacroServerChoice::Sysroot diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 5633c0c488aa7..252b1e1a48581 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -71,6 +71,9 @@ xflags::xflags! { optional --with-deps /// Don't load sysroot crates (`std`, `core` & friends). optional --no-sysroot + /// Run cargo metadata on the sysroot to analyze its third-party dependencies. + /// Requires --no-sysroot to not be set. + optional --query-sysroot-metadata /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis. optional --disable-build-scripts @@ -206,6 +209,7 @@ pub struct AnalysisStats { pub only: Option, pub with_deps: bool, pub no_sysroot: bool, + pub query_sysroot_metadata: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, pub skip_lowering: bool, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index d6a45ce06f21f..64f965e22ac70 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -217,8 +217,7 @@ impl LsifManager<'_> { let mut edges = token.references.iter().fold( HashMap::<_, Vec>::new(), |mut edges, it| { - let entry = - edges.entry((it.range.file_id, it.is_definition)).or_insert_with(Vec::new); + let entry = edges.entry((it.range.file_id, it.is_definition)).or_default(); entry.push((*self.range_map.get(&it.range).unwrap()).into()); edges }, @@ -288,15 +287,15 @@ impl flags::Lsif { pub fn run(self) -> anyhow::Result<()> { eprintln!("Generating LSIF started..."); let now = Instant::now(); - let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustLibSource::Discover); + let cargo_config = + CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; let no_progress = &|_| (); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, }; - let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path)); + let path = AbsPathBuf::assert(env::current_dir()?.join(self.path)); let manifest = ProjectManifest::discover_single(&path)?; let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs index 5ef8cdff4cf25..757f2dd70cad9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs @@ -5,7 +5,7 @@ use crate::cli::{flags, read_stdin}; impl flags::Parse { pub fn run(self) -> anyhow::Result<()> { - let _p = profile::span("parsing"); + let _p = tracing::span!(tracing::Level::INFO, "parsing").entered(); let text = read_stdin()?; let file = SourceFile::parse(&text).tree(); if !self.no_dump { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs index c236f9c7fe1b6..8166aa23b4477 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs @@ -59,7 +59,7 @@ impl<'a> ProgressReport<'a> { "{}/{} {percent:3>}% {}", self.pos, self.len, - self.msg.as_ref().map_or_else(|| String::new(), |it| it()) + self.msg.as_ref().map_or_else(String::new, |it| it()) ); self.update_text(&text); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs index e1704199151a6..d07dcdec25105 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs @@ -13,8 +13,8 @@ use crate::cli::{flags, full_name_of_item, Result}; impl flags::RunTests { pub fn run(self) -> Result<()> { - let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustLibSource::Discover); + let cargo_config = + CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index b8f6138161e5c..be7e434acac25 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -55,15 +55,20 @@ fn detect_errors_from_rustc_stderr_file(p: PathBuf) -> HashMap Result { - let tmp_file = AbsPathBuf::assert("/tmp/ra-rustc-test.rs".into()); + let mut path = std::env::temp_dir(); + path.push("ra-rustc-test.rs"); + let tmp_file = AbsPathBuf::try_from(path).unwrap(); std::fs::write(&tmp_file, "")?; - let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustLibSource::Discover); + let cargo_config = + CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; let workspace = ProjectWorkspace::DetachedFiles { files: vec![tmp_file.clone()], - sysroot: Ok( - Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env).unwrap() - ), + sysroot: Ok(Sysroot::discover( + tmp_file.parent().unwrap(), + &cargo_config.extra_env, + false, + ) + .unwrap()), rustc_cfg: vec![], }; let load_cargo_config = LoadCargoConfig { @@ -119,26 +124,43 @@ impl Tester { change.change_file(self.root_file, Some(Arc::from(text))); self.host.apply_change(change); let diagnostic_config = DiagnosticsConfig::test_sample(); - let diags = self - .host - .analysis() - .diagnostics(&diagnostic_config, ide::AssistResolveStrategy::None, self.root_file) - .unwrap(); + let mut actual = HashMap::new(); - for diag in diags { - if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) { - continue; - } - if !should_have_no_error && !SUPPORTED_DIAGNOSTICS.contains(&diag.code) { - continue; + let panicked = match std::panic::catch_unwind(|| { + self.host + .analysis() + .diagnostics(&diagnostic_config, ide::AssistResolveStrategy::None, self.root_file) + .unwrap() + }) { + Err(e) => Some(e), + Ok(diags) => { + for diag in diags { + if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) { + continue; + } + if !should_have_no_error && !SUPPORTED_DIAGNOSTICS.contains(&diag.code) { + continue; + } + *actual.entry(diag.code).or_insert(0) += 1; + } + None } - *actual.entry(diag.code).or_insert(0) += 1; - } + }; // Ignore tests with diagnostics that we don't emit. ignore_test |= expected.keys().any(|k| !SUPPORTED_DIAGNOSTICS.contains(k)); if ignore_test { println!("{p:?} IGNORE"); self.ignore_count += 1; + } else if let Some(panic) = panicked { + if let Some(msg) = panic + .downcast_ref::() + .map(String::as_str) + .or_else(|| panic.downcast_ref::<&str>().copied()) + { + println!("{msg:?} ") + } + println!("PANIC"); + self.fail_count += 1; } else if actual == expected { println!("{p:?} PASS"); self.pass_count += 1; @@ -222,11 +244,10 @@ impl flags::RustcTests { let tester = AssertUnwindSafe(&mut tester); let p = p.clone(); move || { - let tester = tester; - tester.0.test(p); + let _guard = stdx::panic_context::enter(p.display().to_string()); + { tester }.0.test(p); } }) { - println!("panic detected at test {:?}", p); std::panic::resume_unwind(e); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index c86b2c0ba4052..81622a4617ab9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -143,11 +143,14 @@ impl flags::Scip { .map(|hover| hover.markup.as_str()) .filter(|it| !it.is_empty()) .map(|it| vec![it.to_owned()]); + let position_encoding = + scip_types::PositionEncoding::UTF8CodeUnitOffsetFromLineStart.into(); let signature_documentation = token.signature.clone().map(|text| scip_types::Document { relative_path: relative_path.clone(), language: "rust".to_string(), text, + position_encoding, ..Default::default() }); let symbol_info = scip_types::SymbolInformation { @@ -181,13 +184,16 @@ impl flags::Scip { continue; } + let position_encoding = + scip_types::PositionEncoding::UTF8CodeUnitOffsetFromLineStart.into(); documents.push(scip_types::Document { relative_path, language: "rust".to_string(), occurrences, symbols, - special_fields: Default::default(), text: String::new(), + position_encoding, + special_fields: Default::default(), }); } @@ -246,7 +252,7 @@ fn new_descriptor(name: &str, suffix: scip_types::descriptor::Suffix) -> scip_ty if name.contains('\'') { new_descriptor_str(&format!("`{name}`"), suffix) } else { - new_descriptor_str(&name, suffix) + new_descriptor_str(name, suffix) } } @@ -359,7 +365,7 @@ mod test { } } - if expected == "" { + if expected.is_empty() { assert!(found_symbol.is_none(), "must have no symbols {found_symbol:?}"); return; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs index f87dcb889a48b..8f11d82f8fd93 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs @@ -10,8 +10,8 @@ use crate::cli::flags; impl flags::Ssr { pub fn run(self) -> anyhow::Result<()> { use ide_db::base_db::SourceDatabaseExt; - let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustLibSource::Discover); + let cargo_config = + CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index fe009f82a71fd..815f6ea12e86c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -32,6 +32,7 @@ use project_model::{ }; use rustc_hash::{FxHashMap, FxHashSet}; use serde::{de::DeserializeOwned, Deserialize}; +use stdx::format_to_acc; use vfs::{AbsPath, AbsPathBuf}; use crate::{ @@ -135,6 +136,13 @@ config_data! { /// /// This option does not take effect until rust-analyzer is restarted. cargo_sysroot: Option = "\"discover\"", + /// Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze + /// third-party dependencies of the standard libraries. + /// + /// This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer + /// will attempt to clean up afterwards, but nevertheless requires the location to be + /// writable to. + cargo_sysrootQueryMetadata: bool = "false", /// Relative path to the sysroot library sources. If left unset, this will default to /// `{cargo.sysroot}/lib/rustlib/src/rust/library`. /// @@ -487,6 +495,13 @@ config_data! { /// Exclude imports from find-all-references. references_excludeImports: bool = "false", + /// Exclude tests from find-all-references. + references_excludeTests: bool = "false", + + /// Allow renaming of items not belonging to the loaded workspaces. + rename_allowExternalItems: bool = "false", + + /// Command to be executed instead of 'cargo' for runnables. runnables_command: Option = "null", /// Additional arguments to be passed to cargo for runnables such as @@ -1172,12 +1187,12 @@ impl Config { } pub fn lru_query_capacities(&self) -> Option<&FxHashMap, usize>> { - self.data.lru_query_capacities.is_empty().not().then(|| &self.data.lru_query_capacities) + self.data.lru_query_capacities.is_empty().not().then_some(&self.data.lru_query_capacities) } pub fn proc_macro_srv(&self) -> Option { let path = self.data.procMacro_server.clone()?; - Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(&path))) + Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path))) } pub fn dummy_replacements(&self) -> &FxHashMap, Box<[Box]>> { @@ -1233,6 +1248,7 @@ impl Config { }); let sysroot_src = self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot)); + let sysroot_query_metadata = self.data.cargo_sysrootQueryMetadata; CargoConfig { features: match &self.data.cargo_features { @@ -1244,6 +1260,7 @@ impl Config { }, target: self.data.cargo_target.clone(), sysroot, + sysroot_query_metadata, sysroot_src, rustc_source, cfg_overrides: project_model::CfgOverrides { @@ -1484,6 +1501,7 @@ impl Config { ImportGranularityDef::Item => ImportGranularity::Item, ImportGranularityDef::Crate => ImportGranularity::Crate, ImportGranularityDef::Module => ImportGranularity::Module, + ImportGranularityDef::One => ImportGranularity::One, }, enforce_granularity: self.data.imports_granularity_enforce, prefix_kind: match self.data.imports_prefix { @@ -1531,6 +1549,10 @@ impl Config { self.data.references_excludeImports } + pub fn find_all_refs_exclude_tests(&self) -> bool { + self.data.references_excludeTests + } + pub fn snippet_cap(&self) -> bool { self.experimental("snippetTextEdit") } @@ -1723,13 +1745,17 @@ impl Config { } pub fn main_loop_num_threads(&self) -> usize { - self.data.numThreads.unwrap_or(num_cpus::get_physical().try_into().unwrap_or(1)) + self.data.numThreads.unwrap_or(num_cpus::get_physical()) } pub fn typing_autoclose_angle(&self) -> bool { self.data.typing_autoClosingAngleBrackets_enable } + pub fn rename(&self) -> bool { + self.data.rename_allowExternalItems + } + // FIXME: VSCode seems to work wrong sometimes, see https://github.com/microsoft/vscode/issues/193124 // hence, distinguish it for now. pub fn is_visual_studio_code(&self) -> bool { @@ -1845,18 +1871,14 @@ mod de_unit_v { #[derive(Deserialize, Debug, Clone, Copy)] #[serde(rename_all = "snake_case")] +#[derive(Default)] enum SnippetScopeDef { + #[default] Expr, Item, Type, } -impl Default for SnippetScopeDef { - fn default() -> Self { - SnippetScopeDef::Expr - } -} - #[derive(Deserialize, Debug, Clone, Default)] #[serde(default)] struct SnippetDef { @@ -1924,6 +1946,7 @@ enum ImportGranularityDef { Item, Crate, Module, + One, } #[derive(Deserialize, Debug, Copy, Clone)] @@ -2265,12 +2288,13 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, "ImportGranularityDef" => set! { "type": "string", - "enum": ["preserve", "crate", "module", "item"], + "enum": ["preserve", "crate", "module", "item", "one"], "enumDescriptions": [ "Do not change the granularity of any imports and preserve the original structure written by the developer.", "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", - "Flatten imports so that each has its own use statement." + "Flatten imports so that each has its own use statement.", + "Merge all imports into a single use statement as long as they have the same visibility and attributes." ], }, "ImportPrefixDef" => set! { @@ -2540,14 +2564,13 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json #[cfg(test)] fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String { - fields - .iter() - .map(|(field, _ty, doc, default)| { - let name = format!("rust-analyzer.{}", field.replace('_', ".")); - let doc = doc_comment_to_string(doc); - if default.contains('\n') { - format!( - r#"[[{name}]]{name}:: + fields.iter().fold(String::new(), |mut acc, (field, _ty, doc, default)| { + let name = format!("rust-analyzer.{}", field.replace('_', ".")); + let doc = doc_comment_to_string(doc); + if default.contains('\n') { + format_to_acc!( + acc, + r#"[[{name}]]{name}:: + -- Default: @@ -2557,16 +2580,17 @@ Default: {doc} -- "# - ) - } else { - format!("[[{name}]]{name} (default: `{default}`)::\n+\n--\n{doc}--\n") - } - }) - .collect::() + ) + } else { + format_to_acc!(acc, "[[{name}]]{name} (default: `{default}`)::\n+\n--\n{doc}--\n") + } + }) } fn doc_comment_to_string(doc: &[&str]) -> String { - doc.iter().map(|it| it.strip_prefix(' ').unwrap_or(it)).map(|it| format!("{it}\n")).collect() + doc.iter() + .map(|it| it.strip_prefix(' ').unwrap_or(it)) + .fold(String::new(), |mut acc, it| format_to_acc!(acc, "{it}\n")) } #[cfg(test)] @@ -2708,7 +2732,7 @@ mod tests { .unwrap(); assert_eq!(config.data.rust_analyzerTargetDir, None); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == None) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir.is_none()) ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index f80beb9caadd8..c91b22999dede 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -128,12 +128,12 @@ pub(crate) fn fetch_native_diagnostics( snapshot: GlobalStateSnapshot, subscriptions: Vec, ) -> Vec<(FileId, Vec)> { - let _p = profile::span("fetch_native_diagnostics"); + let _p = tracing::span!(tracing::Level::INFO, "fetch_native_diagnostics").entered(); let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned()); let convert_diagnostic = |line_index: &crate::line_index::LineIndex, d: ide::Diagnostic| lsp_types::Diagnostic { - range: lsp::to_proto::range(&line_index, d.range.range), + range: lsp::to_proto::range(line_index, d.range.range), severity: Some(lsp::to_proto::diagnostic_severity(d.severity)), code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_string())), code_description: Some(lsp_types::CodeDescription { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs index 7da4311888181..fa856a796a8ef 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs @@ -1,5 +1,8 @@ //! See [RequestDispatcher]. -use std::{fmt, panic, thread}; +use std::{ + fmt::{self, Debug}, + panic, thread, +}; use ide::Cancelled; use lsp_server::ExtractError; @@ -49,6 +52,8 @@ impl RequestDispatcher<'_> { Some(it) => it, None => return self, }; + let _guard = tracing::span!(tracing::Level::INFO, "request", method = ?req.method, "request_id" = ?req.id).entered(); + tracing::debug!(?params); let result = { let _pctx = stdx::panic_context::enter(panic_context); f(self.global_state, params) @@ -74,6 +79,8 @@ impl RequestDispatcher<'_> { Some(it) => it, None => return self, }; + let _guard = tracing::span!(tracing::Level::INFO, "request", method = ?req.method, "request_id" = ?req.id).entered(); + tracing::debug!(?params); let global_state_snapshot = self.global_state.snapshot(); let result = panic::catch_unwind(move || { @@ -192,6 +199,8 @@ impl RequestDispatcher<'_> { Some(it) => it, None => return self, }; + let _guard = tracing::span!(tracing::Level::INFO, "request", method = ?req.method, "request_id" = ?req.id).entered(); + tracing::debug!(?params); let world = self.global_state.snapshot(); if MAIN_POOL { @@ -313,12 +322,16 @@ impl NotificationDispatcher<'_> { ) -> anyhow::Result<&mut Self> where N: lsp_types::notification::Notification, - N::Params: DeserializeOwned + Send, + N::Params: DeserializeOwned + Send + Debug, { let not = match self.not.take() { Some(it) => it, None => return Ok(self), }; + + let _guard = + tracing::span!(tracing::Level::INFO, "notification", method = ?not.method).entered(); + let params = match not.extract::(N::METHOD) { Ok(it) => it, Err(ExtractError::JsonError { method, error }) => { @@ -329,6 +342,9 @@ impl NotificationDispatcher<'_> { return Ok(self); } }; + + tracing::debug!(?params); + let _pctx = stdx::panic_context::enter(format!( "\nversion: {}\nnotification: {}", version(), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index c4a29e0cbb03b..2f226d01155bd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -215,7 +215,7 @@ impl GlobalState { } pub(crate) fn process_changes(&mut self) -> bool { - let _p = profile::span("GlobalState::process_changes"); + let _p = tracing::span!(tracing::Level::INFO, "GlobalState::process_changes").entered(); let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default(); let (change, modified_rust_files, workspace_structure_change) = { @@ -299,11 +299,11 @@ impl GlobalState { } let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change { - String::from_utf8(v).ok().and_then(|text| { + String::from_utf8(v).ok().map(|text| { // FIXME: Consider doing normalization in the `vfs` instead? That allows // getting rid of some locking let (text, line_endings) = LineEndings::normalize(text); - Some((Arc::from(text), line_endings)) + (Arc::from(text), line_endings) }) } else { None diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index ce69d612255a5..1f24e95010571 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -36,7 +36,7 @@ pub(crate) fn handle_work_done_progress_cancel( ) -> anyhow::Result<()> { if let lsp_types::NumberOrString::String(s) = ¶ms.token { if let Some(id) = s.strip_prefix("rust-analyzer/flycheck/") { - if let Ok(id) = u32::from_str_radix(id, 10) { + if let Ok(id) = id.parse::() { if let Some(flycheck) = state.flycheck.get(id as usize) { flycheck.cancel(); } @@ -54,7 +54,7 @@ pub(crate) fn handle_did_open_text_document( state: &mut GlobalState, params: DidOpenTextDocumentParams, ) -> anyhow::Result<()> { - let _p = profile::span("handle_did_open_text_document"); + let _p = tracing::span!(tracing::Level::INFO, "handle_did_open_text_document").entered(); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { let already_exists = state @@ -79,7 +79,7 @@ pub(crate) fn handle_did_change_text_document( state: &mut GlobalState, params: DidChangeTextDocumentParams, ) -> anyhow::Result<()> { - let _p = profile::span("handle_did_change_text_document"); + let _p = tracing::span!(tracing::Level::INFO, "handle_did_change_text_document").entered(); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { let data = match state.mem_docs.get_mut(&path) { @@ -113,7 +113,7 @@ pub(crate) fn handle_did_close_text_document( state: &mut GlobalState, params: DidCloseTextDocumentParams, ) -> anyhow::Result<()> { - let _p = profile::span("handle_did_close_text_document"); + let _p = tracing::span!(tracing::Level::INFO, "handle_did_close_text_document").entered(); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { if state.mem_docs.remove(&path).is_err() { @@ -247,7 +247,7 @@ pub(crate) fn handle_did_change_watched_files( } fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { - let _p = profile::span("run_flycheck"); + let _p = tracing::span!(tracing::Level::INFO, "run_flycheck").entered(); let file_id = state.vfs.read().0.file_id(&vfs_path); if let Some(file_id) = file_id { @@ -326,13 +326,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { } pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { - let _p = profile::span("handle_stop_flycheck"); + let _p = tracing::span!(tracing::Level::INFO, "handle_stop_flycheck").entered(); state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); Ok(()) } pub(crate) fn handle_clear_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { - let _p = profile::span("handle_clear_flycheck"); + let _p = tracing::span!(tracing::Level::INFO, "handle_clear_flycheck").entered(); state.diagnostics.clear_check_all(); Ok(()) } @@ -341,7 +341,7 @@ pub(crate) fn handle_run_flycheck( state: &mut GlobalState, params: RunFlycheckParams, ) -> anyhow::Result<()> { - let _p = profile::span("handle_run_flycheck"); + let _p = tracing::span!(tracing::Level::INFO, "handle_run_flycheck").entered(); if let Some(text_document) = params.text_document { if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) { if run_flycheck(state, vfs_path) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 22c7e9b0503c5..2be2ba5c44657 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -70,7 +70,7 @@ pub(crate) fn handle_analyzer_status( snap: GlobalStateSnapshot, params: lsp_ext::AnalyzerStatusParams, ) -> anyhow::Result { - let _p = profile::span("handle_analyzer_status"); + let _p = tracing::span!(tracing::Level::INFO, "handle_analyzer_status").entered(); let mut buf = String::new(); @@ -114,7 +114,7 @@ pub(crate) fn handle_analyzer_status( } pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Result { - let _p = profile::span("handle_memory_usage"); + let _p = tracing::span!(tracing::Level::INFO, "handle_memory_usage").entered(); let mem = state.analysis_host.per_query_memory_usage(); let mut out = String::new(); @@ -135,7 +135,7 @@ pub(crate) fn handle_syntax_tree( snap: GlobalStateSnapshot, params: lsp_ext::SyntaxTreeParams, ) -> anyhow::Result { - let _p = profile::span("handle_syntax_tree"); + let _p = tracing::span!(tracing::Level::INFO, "handle_syntax_tree").entered(); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(id)?; let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok()); @@ -147,7 +147,7 @@ pub(crate) fn handle_view_hir( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result { - let _p = profile::span("handle_view_hir"); + let _p = tracing::span!(tracing::Level::INFO, "handle_view_hir").entered(); let position = from_proto::file_position(&snap, params)?; let res = snap.analysis.view_hir(position)?; Ok(res) @@ -157,7 +157,7 @@ pub(crate) fn handle_view_mir( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result { - let _p = profile::span("handle_view_mir"); + let _p = tracing::span!(tracing::Level::INFO, "handle_view_mir").entered(); let position = from_proto::file_position(&snap, params)?; let res = snap.analysis.view_mir(position)?; Ok(res) @@ -167,7 +167,7 @@ pub(crate) fn handle_interpret_function( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result { - let _p = profile::span("handle_interpret_function"); + let _p = tracing::span!(tracing::Level::INFO, "handle_interpret_function").entered(); let position = from_proto::file_position(&snap, params)?; let res = snap.analysis.interpret_function(position)?; Ok(res) @@ -185,7 +185,7 @@ pub(crate) fn handle_view_item_tree( snap: GlobalStateSnapshot, params: lsp_ext::ViewItemTreeParams, ) -> anyhow::Result { - let _p = profile::span("handle_view_item_tree"); + let _p = tracing::span!(tracing::Level::INFO, "handle_view_item_tree").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let res = snap.analysis.view_item_tree(file_id)?; Ok(res) @@ -195,7 +195,7 @@ pub(crate) fn handle_view_crate_graph( snap: GlobalStateSnapshot, params: ViewCrateGraphParams, ) -> anyhow::Result { - let _p = profile::span("handle_view_crate_graph"); + let _p = tracing::span!(tracing::Level::INFO, "handle_view_crate_graph").entered(); let dot = snap.analysis.view_crate_graph(params.full)?.map_err(anyhow::Error::msg)?; Ok(dot) } @@ -204,7 +204,7 @@ pub(crate) fn handle_expand_macro( snap: GlobalStateSnapshot, params: lsp_ext::ExpandMacroParams, ) -> anyhow::Result> { - let _p = profile::span("handle_expand_macro"); + let _p = tracing::span!(tracing::Level::INFO, "handle_expand_macro").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position)?; @@ -217,7 +217,7 @@ pub(crate) fn handle_selection_range( snap: GlobalStateSnapshot, params: lsp_types::SelectionRangeParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_selection_range"); + let _p = tracing::span!(tracing::Level::INFO, "handle_selection_range").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; let res: anyhow::Result> = params @@ -260,7 +260,7 @@ pub(crate) fn handle_matching_brace( snap: GlobalStateSnapshot, params: lsp_ext::MatchingBraceParams, ) -> anyhow::Result> { - let _p = profile::span("handle_matching_brace"); + let _p = tracing::span!(tracing::Level::INFO, "handle_matching_brace").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; params @@ -283,7 +283,7 @@ pub(crate) fn handle_join_lines( snap: GlobalStateSnapshot, params: lsp_ext::JoinLinesParams, ) -> anyhow::Result> { - let _p = profile::span("handle_join_lines"); + let _p = tracing::span!(tracing::Level::INFO, "handle_join_lines").entered(); let config = snap.config.join_lines(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; @@ -308,7 +308,7 @@ pub(crate) fn handle_on_enter( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_on_enter"); + let _p = tracing::span!(tracing::Level::INFO, "handle_on_enter").entered(); let position = from_proto::file_position(&snap, params)?; let edit = match snap.analysis.on_enter(position)? { None => return Ok(None), @@ -323,7 +323,7 @@ pub(crate) fn handle_on_type_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentOnTypeFormattingParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_on_type_formatting"); + let _p = tracing::span!(tracing::Level::INFO, "handle_on_type_formatting").entered(); let mut position = from_proto::file_position(&snap, params.text_document_position)?; let line_index = snap.file_line_index(position.file_id)?; @@ -364,7 +364,7 @@ pub(crate) fn handle_document_symbol( snap: GlobalStateSnapshot, params: lsp_types::DocumentSymbolParams, ) -> anyhow::Result> { - let _p = profile::span("handle_document_symbol"); + let _p = tracing::span!(tracing::Level::INFO, "handle_document_symbol").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; @@ -453,7 +453,7 @@ pub(crate) fn handle_workspace_symbol( snap: GlobalStateSnapshot, params: WorkspaceSymbolParams, ) -> anyhow::Result> { - let _p = profile::span("handle_workspace_symbol"); + let _p = tracing::span!(tracing::Level::INFO, "handle_workspace_symbol").entered(); let config = snap.config.workspace_symbol(); let (all_symbols, libs) = decide_search_scope_and_kind(¶ms, &config); @@ -545,7 +545,7 @@ pub(crate) fn handle_will_rename_files( snap: GlobalStateSnapshot, params: lsp_types::RenameFilesParams, ) -> anyhow::Result> { - let _p = profile::span("handle_will_rename_files"); + let _p = tracing::span!(tracing::Level::INFO, "handle_will_rename_files").entered(); let source_changes: Vec = params .files @@ -607,7 +607,7 @@ pub(crate) fn handle_goto_definition( snap: GlobalStateSnapshot, params: lsp_types::GotoDefinitionParams, ) -> anyhow::Result> { - let _p = profile::span("handle_goto_definition"); + let _p = tracing::span!(tracing::Level::INFO, "handle_goto_definition").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_definition(position)? { None => return Ok(None), @@ -622,7 +622,7 @@ pub(crate) fn handle_goto_declaration( snap: GlobalStateSnapshot, params: lsp_types::request::GotoDeclarationParams, ) -> anyhow::Result> { - let _p = profile::span("handle_goto_declaration"); + let _p = tracing::span!(tracing::Level::INFO, "handle_goto_declaration").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?; let nav_info = match snap.analysis.goto_declaration(position)? { None => return handle_goto_definition(snap, params), @@ -637,7 +637,7 @@ pub(crate) fn handle_goto_implementation( snap: GlobalStateSnapshot, params: lsp_types::request::GotoImplementationParams, ) -> anyhow::Result> { - let _p = profile::span("handle_goto_implementation"); + let _p = tracing::span!(tracing::Level::INFO, "handle_goto_implementation").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_implementation(position)? { None => return Ok(None), @@ -652,7 +652,7 @@ pub(crate) fn handle_goto_type_definition( snap: GlobalStateSnapshot, params: lsp_types::request::GotoTypeDefinitionParams, ) -> anyhow::Result> { - let _p = profile::span("handle_goto_type_definition"); + let _p = tracing::span!(tracing::Level::INFO, "handle_goto_type_definition").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_type_definition(position)? { None => return Ok(None), @@ -667,7 +667,7 @@ pub(crate) fn handle_parent_module( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { - let _p = profile::span("handle_parent_module"); + let _p = tracing::span!(tracing::Level::INFO, "handle_parent_module").entered(); if let Ok(file_path) = ¶ms.text_document.uri.to_file_path() { if file_path.file_name().unwrap_or_default() == "Cargo.toml" { // search workspaces for parent packages or fallback to workspace root @@ -734,7 +734,7 @@ pub(crate) fn handle_runnables( snap: GlobalStateSnapshot, params: lsp_ext::RunnablesParams, ) -> anyhow::Result> { - let _p = profile::span("handle_runnables"); + let _p = tracing::span!(tracing::Level::INFO, "handle_runnables").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok()); @@ -829,7 +829,7 @@ pub(crate) fn handle_related_tests( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { - let _p = profile::span("handle_related_tests"); + let _p = tracing::span!(tracing::Level::INFO, "handle_related_tests").entered(); let position = from_proto::file_position(&snap, params)?; let tests = snap.analysis.related_tests(position, None)?; @@ -847,7 +847,7 @@ pub(crate) fn handle_completion( snap: GlobalStateSnapshot, params: lsp_types::CompletionParams, ) -> anyhow::Result> { - let _p = profile::span("handle_completion"); + let _p = tracing::span!(tracing::Level::INFO, "handle_completion").entered(); let text_document_position = params.text_document_position.clone(); let position = from_proto::file_position(&snap, params.text_document_position)?; let completion_trigger_character = @@ -875,7 +875,7 @@ pub(crate) fn handle_completion_resolve( snap: GlobalStateSnapshot, mut original_completion: CompletionItem, ) -> anyhow::Result { - let _p = profile::span("handle_completion_resolve"); + let _p = tracing::span!(tracing::Level::INFO, "handle_completion_resolve").entered(); if !all_edits_are_disjoint(&original_completion, &[]) { return Err(invalid_params_error( @@ -919,7 +919,7 @@ pub(crate) fn handle_completion_resolve( } if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() { - original_additional_edits.extend(additional_edits.into_iter()) + original_additional_edits.extend(additional_edits) } else { original_completion.additional_text_edits = Some(additional_edits); } @@ -931,7 +931,7 @@ pub(crate) fn handle_folding_range( snap: GlobalStateSnapshot, params: FoldingRangeParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_folding_range"); + let _p = tracing::span!(tracing::Level::INFO, "handle_folding_range").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let folds = snap.analysis.folding_ranges(file_id)?; let text = snap.analysis.file_text(file_id)?; @@ -948,7 +948,7 @@ pub(crate) fn handle_signature_help( snap: GlobalStateSnapshot, params: lsp_types::SignatureHelpParams, ) -> anyhow::Result> { - let _p = profile::span("handle_signature_help"); + let _p = tracing::span!(tracing::Level::INFO, "handle_signature_help").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let help = match snap.analysis.signature_help(position)? { Some(it) => it, @@ -963,7 +963,7 @@ pub(crate) fn handle_hover( snap: GlobalStateSnapshot, params: lsp_ext::HoverParams, ) -> anyhow::Result> { - let _p = profile::span("handle_hover"); + let _p = tracing::span!(tracing::Level::INFO, "handle_hover").entered(); let range = match params.position { PositionOrRange::Position(position) => Range::new(position, position), PositionOrRange::Range(range) => range, @@ -1000,7 +1000,7 @@ pub(crate) fn handle_prepare_rename( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { - let _p = profile::span("handle_prepare_rename"); + let _p = tracing::span!(tracing::Level::INFO, "handle_prepare_rename").entered(); let position = from_proto::file_position(&snap, params)?; let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?; @@ -1014,11 +1014,13 @@ pub(crate) fn handle_rename( snap: GlobalStateSnapshot, params: RenameParams, ) -> anyhow::Result> { - let _p = profile::span("handle_rename"); + let _p = tracing::span!(tracing::Level::INFO, "handle_rename").entered(); let position = from_proto::file_position(&snap, params.text_document_position)?; - let mut change = - snap.analysis.rename(position, ¶ms.new_name)?.map_err(to_proto::rename_error)?; + let mut change = snap + .analysis + .rename(position, ¶ms.new_name, snap.config.rename())? + .map_err(to_proto::rename_error)?; // this is kind of a hack to prevent double edits from happening when moving files // When a module gets renamed by renaming the mod declaration this causes the file to move @@ -1037,11 +1039,7 @@ pub(crate) fn handle_rename( { for op in ops { if let lsp_types::DocumentChangeOperation::Op(doc_change_op) = op { - if let Err(err) = - resource_ops_supported(&snap.config, resolve_resource_op(doc_change_op)) - { - return Err(err); - } + resource_ops_supported(&snap.config, resolve_resource_op(doc_change_op))? } } } @@ -1053,10 +1051,11 @@ pub(crate) fn handle_references( snap: GlobalStateSnapshot, params: lsp_types::ReferenceParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_references"); + let _p = tracing::span!(tracing::Level::INFO, "handle_references").entered(); let position = from_proto::file_position(&snap, params.text_document_position)?; let exclude_imports = snap.config.find_all_refs_exclude_imports(); + let exclude_tests = snap.config.find_all_refs_exclude_tests(); let refs = match snap.analysis.find_all_refs(position, None)? { None => return Ok(None), @@ -1080,7 +1079,8 @@ pub(crate) fn handle_references( .flat_map(|(file_id, refs)| { refs.into_iter() .filter(|&(_, category)| { - !exclude_imports || category != Some(ReferenceCategory::Import) + (!exclude_imports || category != Some(ReferenceCategory::Import)) + && (!exclude_tests || category != Some(ReferenceCategory::Test)) }) .map(move |(range, _)| FileRange { file_id, range }) }) @@ -1096,7 +1096,7 @@ pub(crate) fn handle_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentFormattingParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_formatting"); + let _p = tracing::span!(tracing::Level::INFO, "handle_formatting").entered(); run_rustfmt(&snap, params.text_document, None) } @@ -1105,7 +1105,7 @@ pub(crate) fn handle_range_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentRangeFormattingParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_range_formatting"); + let _p = tracing::span!(tracing::Level::INFO, "handle_range_formatting").entered(); run_rustfmt(&snap, params.text_document, Some(params.range)) } @@ -1114,7 +1114,7 @@ pub(crate) fn handle_code_action( snap: GlobalStateSnapshot, params: lsp_types::CodeActionParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_code_action"); + let _p = tracing::span!(tracing::Level::INFO, "handle_code_action").entered(); if !snap.config.code_action_literals() { // We intentionally don't support command-based actions, as those either @@ -1158,11 +1158,7 @@ pub(crate) fn handle_code_action( if let Some(changes) = changes { for change in changes { if let lsp_ext::SnippetDocumentChangeOperation::Op(res_op) = change { - if let Err(err) = - resource_ops_supported(&snap.config, resolve_resource_op(res_op)) - { - return Err(err); - } + resource_ops_supported(&snap.config, resolve_resource_op(res_op))? } } } @@ -1192,7 +1188,7 @@ pub(crate) fn handle_code_action_resolve( snap: GlobalStateSnapshot, mut code_action: lsp_ext::CodeAction, ) -> anyhow::Result { - let _p = profile::span("handle_code_action_resolve"); + let _p = tracing::span!(tracing::Level::INFO, "handle_code_action_resolve").entered(); let params = match code_action.data.take() { Some(it) => it, None => return Err(invalid_params_error("code action without data".to_string()).into()), @@ -1254,11 +1250,7 @@ pub(crate) fn handle_code_action_resolve( if let Some(changes) = edit.document_changes.as_ref() { for change in changes { if let lsp_ext::SnippetDocumentChangeOperation::Op(res_op) = change { - if let Err(err) = - resource_ops_supported(&snap.config, resolve_resource_op(res_op)) - { - return Err(err); - } + resource_ops_supported(&snap.config, resolve_resource_op(res_op))? } } } @@ -1286,7 +1278,7 @@ pub(crate) fn handle_code_lens( snap: GlobalStateSnapshot, params: lsp_types::CodeLensParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_code_lens"); + let _p = tracing::span!(tracing::Level::INFO, "handle_code_lens").entered(); let lens_config = snap.config.lens(); if lens_config.none() { @@ -1329,6 +1321,9 @@ pub(crate) fn handle_code_lens_resolve( snap: GlobalStateSnapshot, code_lens: CodeLens, ) -> anyhow::Result { + if code_lens.data.is_none() { + return Ok(code_lens); + } let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else { return Ok(code_lens); }; @@ -1337,13 +1332,14 @@ pub(crate) fn handle_code_lens_resolve( let mut acc = Vec::new(); to_proto::code_lens(&mut acc, &snap, annotation)?; - let res = match acc.pop() { + let mut res = match acc.pop() { Some(it) if acc.is_empty() => it, _ => { never!(); code_lens } }; + res.data = None; Ok(res) } @@ -1352,7 +1348,7 @@ pub(crate) fn handle_document_highlight( snap: GlobalStateSnapshot, params: lsp_types::DocumentHighlightParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_document_highlight"); + let _p = tracing::span!(tracing::Level::INFO, "handle_document_highlight").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let line_index = snap.file_line_index(position.file_id)?; @@ -1374,7 +1370,7 @@ pub(crate) fn handle_ssr( snap: GlobalStateSnapshot, params: lsp_ext::SsrParams, ) -> anyhow::Result { - let _p = profile::span("handle_ssr"); + let _p = tracing::span!(tracing::Level::INFO, "handle_ssr").entered(); let selections = params .selections .iter() @@ -1394,7 +1390,7 @@ pub(crate) fn handle_inlay_hints( snap: GlobalStateSnapshot, params: InlayHintParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_inlay_hints"); + let _p = tracing::span!(tracing::Level::INFO, "handle_inlay_hints").entered(); let document_uri = ¶ms.text_document.uri; let FileRange { file_id, range } = from_proto::file_range( &snap, @@ -1424,7 +1420,7 @@ pub(crate) fn handle_inlay_hints_resolve( snap: GlobalStateSnapshot, mut original_hint: InlayHint, ) -> anyhow::Result { - let _p = profile::span("handle_inlay_hints_resolve"); + let _p = tracing::span!(tracing::Level::INFO, "handle_inlay_hints_resolve").entered(); let data = match original_hint.data.take() { Some(it) => it, @@ -1471,7 +1467,7 @@ pub(crate) fn handle_call_hierarchy_prepare( snap: GlobalStateSnapshot, params: CallHierarchyPrepareParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_call_hierarchy_prepare"); + let _p = tracing::span!(tracing::Level::INFO, "handle_call_hierarchy_prepare").entered(); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.call_hierarchy(position)? { @@ -1493,7 +1489,7 @@ pub(crate) fn handle_call_hierarchy_incoming( snap: GlobalStateSnapshot, params: CallHierarchyIncomingCallsParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_call_hierarchy_incoming"); + let _p = tracing::span!(tracing::Level::INFO, "handle_call_hierarchy_incoming").entered(); let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); @@ -1528,7 +1524,7 @@ pub(crate) fn handle_call_hierarchy_outgoing( snap: GlobalStateSnapshot, params: CallHierarchyOutgoingCallsParams, ) -> anyhow::Result>> { - let _p = profile::span("handle_call_hierarchy_outgoing"); + let _p = tracing::span!(tracing::Level::INFO, "handle_call_hierarchy_outgoing").entered(); let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); @@ -1563,7 +1559,7 @@ pub(crate) fn handle_semantic_tokens_full( snap: GlobalStateSnapshot, params: SemanticTokensParams, ) -> anyhow::Result> { - let _p = profile::span("handle_semantic_tokens_full"); + let _p = tracing::span!(tracing::Level::INFO, "handle_semantic_tokens_full").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let text = snap.analysis.file_text(file_id)?; @@ -1593,7 +1589,7 @@ pub(crate) fn handle_semantic_tokens_full_delta( snap: GlobalStateSnapshot, params: SemanticTokensDeltaParams, ) -> anyhow::Result> { - let _p = profile::span("handle_semantic_tokens_full_delta"); + let _p = tracing::span!(tracing::Level::INFO, "handle_semantic_tokens_full_delta").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let text = snap.analysis.file_text(file_id)?; @@ -1636,7 +1632,7 @@ pub(crate) fn handle_semantic_tokens_range( snap: GlobalStateSnapshot, params: SemanticTokensRangeParams, ) -> anyhow::Result> { - let _p = profile::span("handle_semantic_tokens_range"); + let _p = tracing::span!(tracing::Level::INFO, "handle_semantic_tokens_range").entered(); let frange = from_proto::file_range(&snap, ¶ms.text_document, params.range)?; let text = snap.analysis.file_text(frange.file_id)?; @@ -1662,7 +1658,7 @@ pub(crate) fn handle_open_docs( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result { - let _p = profile::span("handle_open_docs"); + let _p = tracing::span!(tracing::Level::INFO, "handle_open_docs").entered(); let position = from_proto::file_position(&snap, params)?; let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws { @@ -1701,7 +1697,7 @@ pub(crate) fn handle_open_cargo_toml( snap: GlobalStateSnapshot, params: lsp_ext::OpenCargoTomlParams, ) -> anyhow::Result> { - let _p = profile::span("handle_open_cargo_toml"); + let _p = tracing::span!(tracing::Level::INFO, "handle_open_cargo_toml").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? { @@ -1719,7 +1715,7 @@ pub(crate) fn handle_move_item( snap: GlobalStateSnapshot, params: lsp_ext::MoveItemParams, ) -> anyhow::Result> { - let _p = profile::span("handle_move_item"); + let _p = tracing::span!(tracing::Level::INFO, "handle_move_item").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let range = from_proto::file_range(&snap, ¶ms.text_document, params.range)?; @@ -1741,7 +1737,7 @@ pub(crate) fn handle_view_recursive_memory_layout( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { - let _p = profile::span("view_recursive_memory_layout"); + let _p = tracing::span!(tracing::Level::INFO, "view_recursive_memory_layout").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position)?; @@ -1982,20 +1978,19 @@ fn run_rustfmt( } RustfmtConfig::CustomCommand { command, args } => { let cmd = PathBuf::from(&command); - let workspace = CargoTargetSpec::for_file(&snap, file_id)?; + let workspace = CargoTargetSpec::for_file(snap, file_id)?; let mut cmd = match workspace { Some(spec) => { // approach: if the command name contains a path separator, join it with the workspace root. // however, if the path is absolute, joining will result in the absolute path being preserved. // as a fallback, rely on $PATH-based discovery. - let cmd_path = - if cfg!(windows) && command.contains(&[std::path::MAIN_SEPARATOR, '/']) { - spec.workspace_root.join(cmd).into() - } else if command.contains(std::path::MAIN_SEPARATOR) { - spec.workspace_root.join(cmd).into() - } else { - cmd - }; + let cmd_path = if command.contains(std::path::MAIN_SEPARATOR) + || (cfg!(windows) && command.contains('/')) + { + spec.workspace_root.join(cmd).into() + } else { + cmd + }; process::Command::new(cmd_path) } None => process::Command::new(cmd), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index d94f7cefa60ee..acc02d6447c63 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -60,7 +60,7 @@ fn integrated_highlighting_benchmark() { analysis.highlight_as_html(file_id, false).unwrap(); } - profile::init_from("*>100"); + crate::tracing::hprof::init("*>100"); { let _it = stdx::timeit("change"); @@ -152,8 +152,7 @@ fn integrated_completion_benchmark() { analysis.completions(&config, position, None).unwrap(); } - profile::init_from("*>5"); - // let _s = profile::heartbeat_span(); + crate::tracing::hprof::init("*>5"); let completion_offset = { let _it = stdx::timeit("change"); @@ -168,7 +167,7 @@ fn integrated_completion_benchmark() { }; { - let _p = profile::span("unqualified path completion"); + let _p = tracing::span!(tracing::Level::INFO, "unqualified path completion").entered(); let _span = profile::cpu_span(); let analysis = host.analysis(); let config = CompletionConfig { @@ -209,7 +208,7 @@ fn integrated_completion_benchmark() { }; { - let _p = profile::span("dot completion"); + let _p = tracing::span!(tracing::Level::INFO, "dot completion").entered(); let _span = profile::cpu_span(); let analysis = host.analysis(); let config = CompletionConfig { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 29bc0b80d8a1d..b1809f58ae700 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -13,11 +13,6 @@ pub mod cli; -#[allow(unused)] -macro_rules! eprintln { - ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; -} - mod caps; mod cargo_target_spec; mod diagnostics; @@ -37,6 +32,12 @@ mod handlers { pub(crate) mod request; } +pub mod tracing { + pub mod config; + pub use config::Config; + pub mod hprof; +} + pub mod config; pub mod lsp; use self::lsp::ext as lsp_ext; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs index 15450303ff250..9517620740736 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs @@ -6,6 +6,7 @@ //! convert back to `\r\n` on the way out). use ide_db::line_index::WideEncoding; +use memchr::memmem; use triomphe::Arc; #[derive(Clone, Copy)] @@ -39,10 +40,10 @@ impl LineEndings { let mut tail = buf.as_mut_slice(); let mut crlf_seen = false; - let find_crlf = |src: &[u8]| src.windows(2).position(|it| it == b"\r\n"); + let finder = memmem::Finder::new(b"\r\n"); loop { - let idx = match find_crlf(&tail[gap_len..]) { + let idx = match finder.find(&tail[gap_len..]) { None if crlf_seen => tail.len(), // SAFETY: buf is unchanged and therefore still contains utf8 data None => return (unsafe { String::from_utf8_unchecked(buf) }, LineEndings::Unix), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs index ac7e1a95e622f..9e0d42faed43f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs @@ -2,11 +2,11 @@ use core::fmt; -pub(crate) mod utils; -pub(crate) mod semantic_tokens; pub mod ext; pub(crate) mod from_proto; +pub(crate) mod semantic_tokens; pub(crate) mod to_proto; +pub(crate) mod utils; #[derive(Debug)] pub(crate) struct LspError { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs index 69d6aba94c36e..9923be382b773 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs @@ -51,7 +51,7 @@ pub(crate) fn text_range( let start = offset(line_index, range.start)?; let end = offset(line_index, range.end)?; match end < start { - true => Err(format_err!("Invalid Range").into()), + true => Err(format_err!("Invalid Range")), false => Ok(TextRange::new(start, end)), } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs index 1fe02fc7ead0d..dd7dcf5277830 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs @@ -157,7 +157,7 @@ pub(crate) struct ModifierSet(pub(crate) u32); impl ModifierSet { pub(crate) fn standard_fallback(&mut self) { // Remove all non standard modifiers - self.0 = self.0 & !(!0u32 << LAST_STANDARD_MOD) + self.0 &= !(!0u32 << LAST_STANDARD_MOD) } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 7f3c3aa7a15ba..d363ac69fdc33 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -92,6 +92,7 @@ pub(crate) fn document_highlight_kind( ReferenceCategory::Read => Some(lsp_types::DocumentHighlightKind::READ), ReferenceCategory::Write => Some(lsp_types::DocumentHighlightKind::WRITE), ReferenceCategory::Import => None, + ReferenceCategory::Test => None, } } @@ -310,22 +311,18 @@ fn completion_item( set_score(&mut lsp_item, max_relevance, item.relevance); - if config.completion().enable_imports_on_the_fly { - if !item.import_to_add.is_empty() { - let imports: Vec<_> = item - .import_to_add - .into_iter() - .filter_map(|(import_path, import_name)| { - Some(lsp_ext::CompletionImport { - full_import_path: import_path, - imported_name: import_name, - }) - }) - .collect(); - if !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports }; - lsp_item.data = Some(to_value(data).unwrap()); - } + if config.completion().enable_imports_on_the_fly && !item.import_to_add.is_empty() { + let imports = item + .import_to_add + .into_iter() + .map(|(import_path, import_name)| lsp_ext::CompletionImport { + full_import_path: import_path, + imported_name: import_name, + }) + .collect::>(); + if !imports.is_empty() { + let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports }; + lsp_item.data = Some(to_value(data).unwrap()); } } @@ -931,9 +928,9 @@ fn merge_text_and_snippet_edits( ) -> Vec { let mut edits: Vec = vec![]; let mut snippets = snippet_edit.into_edit_ranges().into_iter().peekable(); - let mut text_edits = edit.into_iter(); + let text_edits = edit.into_iter(); - while let Some(current_indel) = text_edits.next() { + for current_indel in text_edits { let new_range = { let insert_len = TextSize::try_from(current_indel.insert.len()).unwrap_or(TextSize::from(u32::MAX)); @@ -956,7 +953,7 @@ fn merge_text_and_snippet_edits( snippet_range }; - let range = range(&line_index, snippet_range); + let range = range(line_index, snippet_range); let new_text = format!("${snippet_index}"); edits.push(SnippetTextEdit { @@ -1026,7 +1023,7 @@ fn merge_text_and_snippet_edits( snippet_range }; - let range = range(&line_index, snippet_range); + let range = range(line_index, snippet_range); let new_text = format!("${snippet_index}"); SnippetTextEdit { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index ca7893faf5dd7..f3ead6d04f7d7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -60,6 +60,17 @@ enum Event { Flycheck(flycheck::Message), } +impl fmt::Display for Event { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Event::Lsp(_) => write!(f, "Event::Lsp"), + Event::Task(_) => write!(f, "Event::Task"), + Event::Vfs(_) => write!(f, "Event::Vfs"), + Event::Flycheck(_) => write!(f, "Event::Flycheck"), + } + } +} + #[derive(Debug)] pub(crate) enum Task { Response(lsp_server::Response), @@ -196,7 +207,8 @@ impl GlobalState { fn handle_event(&mut self, event: Event) -> anyhow::Result<()> { let loop_start = Instant::now(); // NOTE: don't count blocking select! call as a loop-turn time - let _p = profile::span("GlobalState::handle_event"); + let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event", event = %event) + .entered(); let event_dbg_msg = format!("{event:?}"); tracing::debug!("{:?} handle_event({})", loop_start, event_dbg_msg); @@ -215,7 +227,8 @@ impl GlobalState { lsp_server::Message::Response(resp) => self.complete_request(resp), }, Event::Task(task) => { - let _p = profile::span("GlobalState::handle_event/task"); + let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/task") + .entered(); let mut prime_caches_progress = Vec::new(); self.handle_task(&mut prime_caches_progress, task); @@ -269,7 +282,8 @@ impl GlobalState { } } Event::Vfs(message) => { - let _p = profile::span("GlobalState::handle_event/vfs"); + let _p = + tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/vfs").entered(); self.handle_vfs_msg(message); // Coalesce many VFS event into a single loop turn while let Ok(message) = self.loader.receiver.try_recv() { @@ -277,7 +291,8 @@ impl GlobalState { } } Event::Flycheck(message) => { - let _p = profile::span("GlobalState::handle_event/flycheck"); + let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/flycheck") + .entered(); self.handle_flycheck_msg(message); // Coalesce many flycheck updates into a single loop turn while let Ok(message) = self.flycheck_receiver.try_recv() { @@ -521,7 +536,7 @@ impl GlobalState { if self.config.run_build_scripts() && workspaces_updated { self.fetch_build_data_queue - .request_op(format!("workspace updated"), ()); + .request_op("workspace updated".to_string(), ()); } (Progress::End, None) @@ -579,32 +594,43 @@ impl GlobalState { let path = VfsPath::from(path); // if the file is in mem docs, it's managed by the client via notifications // so only set it if its not in there - if !self.mem_docs.contains(&path) { - if is_changed || vfs.file_id(&path).is_none() { - vfs.set_file_contents(path, contents); - } + if !self.mem_docs.contains(&path) + && (is_changed || vfs.file_id(&path).is_none()) + { + vfs.set_file_contents(path, contents); } } } - vfs::loader::Message::Progress { n_total, n_done, config_version } => { + vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => { always!(config_version <= self.vfs_config_version); + let state = match n_done { + None => Progress::Begin, + Some(done) if done == n_total => Progress::End, + Some(_) => Progress::Report, + }; + let n_done = n_done.unwrap_or_default(); + self.vfs_progress_config_version = config_version; self.vfs_progress_n_total = n_total; self.vfs_progress_n_done = n_done; - let state = if n_done == 0 { - Progress::Begin - } else if n_done < n_total { - Progress::Report - } else { - assert_eq!(n_done, n_total); - Progress::End - }; + let mut message = format!("{n_done}/{n_total}"); + if let Some(dir) = dir { + message += &format!( + ": {}", + match dir.strip_prefix(self.config.root_path()) { + Some(relative_path) => relative_path.as_ref(), + None => dir.as_ref(), + } + .display() + ); + } + self.report_progress( "Roots Scanned", state, - Some(format!("{n_done}/{n_total}")), + Some(message), Some(Progress::fraction(n_done, n_total)), None, ); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 8e3fa7fa4dace..65c00cc08d1a1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -70,7 +70,8 @@ impl GlobalState { } pub(crate) fn update_configuration(&mut self, config: Config) { - let _p = profile::span("GlobalState::update_configuration"); + let _p = + tracing::span!(tracing::Level::INFO, "GlobalState::update_configuration").entered(); let old_config = mem::replace(&mut self.config, Arc::new(config)); if self.config.lru_parse_query_capacity() != old_config.lru_parse_query_capacity() { self.analysis_host.update_lru_capacity(self.config.lru_parse_query_capacity()); @@ -109,7 +110,7 @@ impl GlobalState { status.health = lsp_ext::Health::Warning; message.push_str("Proc-macros have changed and need to be rebuilt.\n\n"); } - if let Err(_) = self.fetch_build_data_error() { + if self.fetch_build_data_error().is_err() { status.health = lsp_ext::Health::Warning; message.push_str("Failed to run build scripts of some packages.\n\n"); } @@ -173,7 +174,7 @@ impl GlobalState { } } - if let Err(_) = self.fetch_workspace_error() { + if self.fetch_workspace_error().is_err() { status.health = lsp_ext::Health::Error; message.push_str("Failed to load workspaces."); @@ -275,6 +276,8 @@ impl GlobalState { tracing::info!(%cause, "will fetch build data"); let workspaces = Arc::clone(&self.workspaces); let config = self.config.cargo(); + let root_path = self.config.root_path().clone(); + self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap(); @@ -284,7 +287,12 @@ impl GlobalState { sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap() } }; - let res = ProjectWorkspace::run_all_build_scripts(&workspaces, &config, &progress); + let res = ProjectWorkspace::run_all_build_scripts( + &workspaces, + &config, + &progress, + &root_path, + ); sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap(); }); @@ -348,7 +356,7 @@ impl GlobalState { } pub(crate) fn switch_workspaces(&mut self, cause: Cause) { - let _p = profile::span("GlobalState::switch_workspaces"); + let _p = tracing::span!(tracing::Level::INFO, "GlobalState::switch_workspaces").entered(); tracing::info!(%cause, "will switch workspaces"); let Some((workspaces, force_reload_crate_graph)) = @@ -357,15 +365,13 @@ impl GlobalState { return; }; - if let Err(_) = self.fetch_workspace_error() { - if !self.workspaces.is_empty() { - if *force_reload_crate_graph { - self.recreate_crate_graph(cause); - } - // It only makes sense to switch to a partially broken workspace - // if we don't have any workspace at all yet. - return; + if self.fetch_workspace_error().is_err() && !self.workspaces.is_empty() { + if *force_reload_crate_graph { + self.recreate_crate_graph(cause); } + // It only makes sense to switch to a partially broken workspace + // if we don't have any workspace at all yet. + return; } let workspaces = @@ -447,27 +453,27 @@ impl GlobalState { let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); - if self.proc_macro_clients.is_empty() || !same_workspaces { - if self.config.expand_proc_macros() { - tracing::info!("Spawning proc-macro servers"); - - self.proc_macro_clients = Arc::from_iter(self.workspaces.iter().map(|ws| { - let path = match self.config.proc_macro_srv() { - Some(path) => path, - None => ws.find_sysroot_proc_macro_srv()?, - }; - - tracing::info!("Using proc-macro server at {path}"); - ProcMacroServer::spawn(path.clone()).map_err(|err| { - tracing::error!( - "Failed to run proc-macro server from path {path}, error: {err:?}", - ); - anyhow::format_err!( - "Failed to run proc-macro server from path {path}, error: {err:?}", - ) - }) - })) - }; + if (self.proc_macro_clients.is_empty() || !same_workspaces) + && self.config.expand_proc_macros() + { + tracing::info!("Spawning proc-macro servers"); + + self.proc_macro_clients = Arc::from_iter(self.workspaces.iter().map(|ws| { + let path = match self.config.proc_macro_srv() { + Some(path) => path, + None => ws.find_sysroot_proc_macro_srv()?, + }; + + tracing::info!("Using proc-macro server at {path}"); + ProcMacroServer::spawn(path.clone()).map_err(|err| { + tracing::error!( + "Failed to run proc-macro server from path {path}, error: {err:?}", + ); + anyhow::format_err!( + "Failed to run proc-macro server from path {path}, error: {err:?}", + ) + }) + })) } let watch = match files_config.watcher { @@ -497,7 +503,7 @@ impl GlobalState { let mut crate_graph_file_dependencies = FxHashSet::default(); let mut load = |path: &AbsPath| { - let _p = profile::span("switch_workspaces::load"); + let _p = tracing::span!(tracing::Level::INFO, "switch_workspaces::load").entered(); let vfs_path = vfs::VfsPath::from(path.to_path_buf()); crate_graph_file_dependencies.insert(vfs_path.clone()); match vfs.file_id(&vfs_path) { @@ -515,8 +521,8 @@ impl GlobalState { let mut proc_macros = Vec::default(); for ws in &**self.workspaces { let (other, mut crate_proc_macros) = - ws.to_crate_graph(&mut load, &self.config.extra_env()); - crate_graph.extend(other, &mut crate_proc_macros); + ws.to_crate_graph(&mut load, self.config.extra_env()); + crate_graph.extend(other, &mut crate_proc_macros, |_| {}); proc_macros.push(crate_proc_macros); } (crate_graph, proc_macros, crate_graph_file_dependencies) @@ -562,10 +568,11 @@ impl GlobalState { for ws in &self.fetch_build_data_queue.last_op_result().1 { match ws { - Ok(data) => match data.error() { - Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr), - _ => (), - }, + Ok(data) => { + if let Some(stderr) = data.error() { + stdx::format_to!(buf, "{:#}\n", stderr) + } + } // io errors Err(err) => stdx::format_to!(buf, "{:#}\n", err), } @@ -579,7 +586,7 @@ impl GlobalState { } fn reload_flycheck(&mut self) { - let _p = profile::span("GlobalState::reload_flycheck"); + let _p = tracing::span!(tracing::Level::INFO, "GlobalState::reload_flycheck").entered(); let config = self.config.flycheck(); let sender = self.flycheck_sender.clone(); let invocation_strategy = match config { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs new file mode 100644 index 0000000000000..fcdbd1e6d9b56 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -0,0 +1,108 @@ +//! Simple logger that logs either to stderr or to a file, using `tracing_subscriber` +//! filter syntax and `tracing_appender` for non blocking output. + +use std::io; + +use anyhow::Context; +use tracing::{level_filters::LevelFilter, Level}; +use tracing_subscriber::{ + filter::{self, Targets}, + fmt::{format::FmtSpan, MakeWriter}, + layer::SubscriberExt, + util::SubscriberInitExt, + Layer, Registry, +}; +use tracing_tree::HierarchicalLayer; + +use crate::tracing::hprof; + +pub struct Config { + pub writer: T, + pub filter: String, + /// The meaning of CHALK_DEBUG is to tell chalk crates + /// (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing + /// logs. But now we can only have just one filter, which means we have to + /// merge chalk filter to our main filter (from RA_LOG env). + /// + /// The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. + /// As the value should only affect chalk crates, we'd better manually + /// specify the target. And for simplicity, CHALK_DEBUG only accept the value + /// that specify level. + pub chalk_filter: Option, + /// Filtering syntax, set in a shell: + /// ``` + /// env RA_PROFILE=* // dump everything + /// env RA_PROFILE=foo|bar|baz // enabled only selected entries + /// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 + /// ``` + pub profile_filter: Option, +} + +impl Config +where + T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, +{ + pub fn init(self) -> anyhow::Result<()> { + let filter: Targets = self + .filter + .parse() + .with_context(|| format!("invalid log filter: `{}`", self.filter))?; + + let writer = self.writer; + + let ra_fmt_layer = tracing_subscriber::fmt::layer() + .with_span_events(FmtSpan::CLOSE) + .with_writer(writer) + .with_filter(filter); + + let mut chalk_layer = None; + if let Some(chalk_filter) = self.chalk_filter { + let level: LevelFilter = + chalk_filter.parse().with_context(|| "invalid chalk log filter")?; + + let chalk_filter = Targets::new() + .with_target("chalk_solve", level) + .with_target("chalk_ir", level) + .with_target("chalk_recursive", level); + chalk_layer = Some( + HierarchicalLayer::default() + .with_indent_lines(true) + .with_ansi(false) + .with_indent_amount(2) + .with_writer(io::stderr) + .with_filter(chalk_filter), + ); + }; + + let mut profiler_layer = None; + if let Some(spec) = self.profile_filter { + let (write_filter, allowed_names) = hprof::WriteFilter::from_spec(&spec); + + // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like + // span depth or duration are not filtered here: that only occurs at write time. + let profile_filter = filter::filter_fn(move |metadata| { + let allowed = match &allowed_names { + Some(names) => names.contains(metadata.name()), + None => true, + }; + + metadata.is_span() + && allowed + && metadata.level() >= &Level::INFO + && !metadata.target().starts_with("salsa") + && !metadata.target().starts_with("chalk") + }); + + let layer = hprof::SpanTree::default() + .aggregate(true) + .spec_filter(write_filter) + .with_filter(profile_filter); + + profiler_layer = Some(layer); + } + + Registry::default().with(ra_fmt_layer).with(chalk_layer).with(profiler_layer).try_init()?; + + Ok(()) + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs new file mode 100644 index 0000000000000..c99b551df8526 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs @@ -0,0 +1,272 @@ +//! Consumer of `tracing` data, which prints a hierarchical profile. +//! +//! Based on https://github.com/davidbarsky/tracing-tree, but does less, while +//! actually printing timings for spans by default. The code here is vendored from +//! https://github.com/matklad/tracing-span-tree. +//! +//! Usage: +//! +//! ```rust +//! let layer = hprof::SpanTree::default(); +//! Registry::default().with(layer).init(); +//! ``` +//! +//! Example output: +//! +//! ```text +//! 8.37ms top_level +//! 1.09ms middle +//! 1.06ms leaf +//! 1.06ms middle +//! 3.12ms middle +//! 1.06ms leaf +//! 3.06ms middle +//! ``` +//! +//! Same data, but with `.aggregate(true)`: +//! +//! ```text +//! 8.39ms top_level +//! 8.35ms 4 middle +//! 2.13ms 2 leaf +//! ``` + +use std::{ + fmt::Write, + mem, + time::{Duration, Instant}, +}; + +use rustc_hash::FxHashSet; +use tracing::{ + field::{Field, Visit}, + span::Attributes, + Event, Id, Level, Subscriber, +}; +use tracing_subscriber::{ + filter, + layer::{Context, SubscriberExt}, + registry::LookupSpan, + Layer, Registry, +}; + +use crate::tracing::hprof; + +pub fn init(spec: &str) { + let (write_filter, allowed_names) = WriteFilter::from_spec(spec); + + // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like + // span depth or duration are not filtered here: that only occurs at write time. + let profile_filter = filter::filter_fn(move |metadata| { + let allowed = match &allowed_names { + Some(names) => names.contains(metadata.name()), + None => true, + }; + + metadata.is_span() + && allowed + && metadata.level() >= &Level::INFO + && !metadata.target().starts_with("salsa") + && !metadata.target().starts_with("chalk") + }); + + let layer = hprof::SpanTree::default() + .aggregate(true) + .spec_filter(write_filter) + .with_filter(profile_filter); + + let subscriber = Registry::default().with(layer); + tracing::subscriber::set_global_default(subscriber).unwrap(); +} + +#[derive(Default, Debug)] +pub(crate) struct SpanTree { + aggregate: bool, + write_filter: WriteFilter, +} + +impl SpanTree { + /// Merge identical sibling spans together. + pub(crate) fn aggregate(self, yes: bool) -> SpanTree { + SpanTree { aggregate: yes, ..self } + } + + /// Add a write-time filter for span duration or tree depth. + pub(crate) fn spec_filter(self, write_filter: WriteFilter) -> SpanTree { + SpanTree { write_filter, ..self } + } +} + +struct Data { + start: Instant, + children: Vec, + fields: String, +} + +impl Data { + fn new(attrs: &Attributes<'_>) -> Self { + let mut data = Self { start: Instant::now(), children: Vec::new(), fields: String::new() }; + + let mut visitor = DataVisitor { string: &mut data.fields }; + attrs.record(&mut visitor); + data + } + + fn into_node(self, name: &'static str) -> Node { + Node { + name, + fields: self.fields, + count: 1, + duration: self.start.elapsed(), + children: self.children, + } + } +} + +pub struct DataVisitor<'a> { + string: &'a mut String, +} + +impl<'a> Visit for DataVisitor<'a> { + fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { + write!(self.string, "{} = {:?} ", field.name(), value).unwrap(); + } +} + +impl Layer for SpanTree +where + S: Subscriber + for<'span> LookupSpan<'span>, +{ + fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) { + let span = ctx.span(id).unwrap(); + + let data = Data::new(attrs); + span.extensions_mut().insert(data); + } + + fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {} + + fn on_close(&self, id: Id, ctx: Context<'_, S>) { + let span = ctx.span(&id).unwrap(); + let data = span.extensions_mut().remove::().unwrap(); + let mut node = data.into_node(span.name()); + + match span.parent() { + Some(parent_span) => { + parent_span.extensions_mut().get_mut::().unwrap().children.push(node); + } + None => { + if self.aggregate { + node.aggregate() + } + node.print(&self.write_filter) + } + } + } +} + +#[derive(Default)] +struct Node { + name: &'static str, + fields: String, + count: u32, + duration: Duration, + children: Vec, +} + +impl Node { + fn print(&self, filter: &WriteFilter) { + self.go(0, filter) + } + + fn go(&self, level: usize, filter: &WriteFilter) { + if self.duration > filter.longer_than && level < filter.depth { + let duration = ms(self.duration); + let current_indent = level * 2; + + let mut out = String::new(); + let _ = write!(out, "{:current_indent$} {duration} {:<6}", "", self.name); + + if !self.fields.is_empty() { + let _ = write!(out, " @ {}", self.fields); + } + + if self.count > 1 { + let _ = write!(out, " ({} calls)", self.count); + } + + eprintln!("{}", out); + + for child in &self.children { + child.go(level + 1, filter) + } + } + } + + fn aggregate(&mut self) { + if self.children.is_empty() { + return; + } + + self.children.sort_by_key(|it| it.name); + let mut idx = 0; + for i in 1..self.children.len() { + if self.children[idx].name == self.children[i].name { + let child = mem::take(&mut self.children[i]); + self.children[idx].duration += child.duration; + self.children[idx].count += child.count; + self.children[idx].children.extend(child.children); + } else { + idx += 1; + assert!(idx <= i); + self.children.swap(idx, i); + } + } + self.children.truncate(idx + 1); + for child in &mut self.children { + child.aggregate() + } + } +} + +#[derive(Default, Clone, Debug)] +pub(crate) struct WriteFilter { + depth: usize, + longer_than: Duration, +} + +impl WriteFilter { + pub(crate) fn from_spec(mut spec: &str) -> (WriteFilter, Option>) { + let longer_than = if let Some(idx) = spec.rfind('>') { + let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than"); + spec = &spec[..idx]; + Duration::from_millis(longer_than) + } else { + Duration::new(0, 0) + }; + + let depth = if let Some(idx) = spec.rfind('@') { + let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); + spec = &spec[..idx]; + depth + } else { + 999 + }; + let allowed = if spec == "*" { + None + } else { + Some(FxHashSet::from_iter(spec.split('|').map(String::from))) + }; + (WriteFilter { depth, longer_than }, allowed) + } +} + +#[allow(non_camel_case_types)] +struct ms(Duration); + +impl std::fmt::Display for ms { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let n = self.0.as_millis(); + write!(f, "{n:5}ms") + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 78411e2d58d09..19890110d53db 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -31,6 +31,7 @@ use lsp_types::{ }; use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams}; use serde_json::json; +use stdx::format_to_acc; use test_utils::skip_slow_tests; use crate::{ @@ -38,9 +39,6 @@ use crate::{ testdir::TestDir, }; -const PROFILE: &str = ""; -// const PROFILE: &'static str = "*@3>100"; - #[test] fn completes_items_from_standard_library() { if skip_slow_tests() { @@ -594,8 +592,10 @@ fn diagnostics_dont_block_typing() { return; } - let librs: String = (0..10).map(|i| format!("mod m{i};")).collect(); - let libs: String = (0..10).map(|i| format!("//- /src/m{i}.rs\nfn foo() {{}}\n\n")).collect(); + let librs: String = (0..10).fold(String::new(), |mut acc, i| format_to_acc!(acc, "mod m{i};")); + let libs: String = (0..10).fold(String::new(), |mut acc, i| { + format_to_acc!(acc, "//- /src/m{i}.rs\nfn foo() {{}}\n\n") + }); let server = Project::with_fixture(&format!( r#" //- /Cargo.toml @@ -682,13 +682,12 @@ version = \"0.0.0\" ); } -#[test] -fn out_dirs_check() { +fn out_dirs_check_impl(root_contains_symlink: bool) { if skip_slow_tests() { return; } - let server = Project::with_fixture( + let mut server = Project::with_fixture( r###" //- /Cargo.toml [package] @@ -745,20 +744,26 @@ fn main() { let another_str = include_str!("main.rs"); } "###, - ) - .with_config(serde_json::json!({ - "cargo": { - "buildScripts": { - "enable": true - }, - "sysroot": null, - "extraEnv": { - "RUSTC_BOOTSTRAP": "1" + ); + + if root_contains_symlink { + server = server.with_root_dir_contains_symlink(); + } + + let server = server + .with_config(serde_json::json!({ + "cargo": { + "buildScripts": { + "enable": true + }, + "sysroot": null, + "extraEnv": { + "RUSTC_BOOTSTRAP": "1" + } } - } - })) - .server() - .wait_until_workspace_is_loaded(); + })) + .server() + .wait_until_workspace_is_loaded(); let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( @@ -831,6 +836,16 @@ fn main() { ); } +#[test] +fn out_dirs_check() { + out_dirs_check_impl(false); +} + +#[test] +fn root_contains_symlink_out_dirs_check() { + out_dirs_check_impl(true); +} + #[test] #[cfg(any(feature = "sysroot-abi", rust_analyzer))] fn resolve_proc_macro() { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 106b99cb9352f..d699374f9cde6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -9,11 +9,11 @@ use std::{ use crossbeam_channel::{after, select, Receiver}; use lsp_server::{Connection, Message, Notification, Request}; use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url}; -use rust_analyzer::{config::Config, lsp, main_loop}; +use rust_analyzer::{config::Config, lsp, main_loop, tracing}; use serde::Serialize; use serde_json::{json, to_string_pretty, Value}; use test_utils::FixtureWithProjectMeta; -use tracing_subscriber::{prelude::*, Layer}; +use tracing_subscriber::fmt::TestWriter; use vfs::AbsPathBuf; use crate::testdir::TestDir; @@ -23,6 +23,7 @@ pub(crate) struct Project<'a> { tmp_dir: Option, roots: Vec, config: serde_json::Value, + root_dir_contains_symlink: bool, } impl Project<'_> { @@ -45,6 +46,7 @@ impl Project<'_> { "enable": false, } }), + root_dir_contains_symlink: false, } } @@ -58,6 +60,11 @@ impl Project<'_> { self } + pub(crate) fn with_root_dir_contains_symlink(mut self) -> Self { + self.root_dir_contains_symlink = true; + self + } + pub(crate) fn with_config(mut self, config: serde_json::Value) -> Self { fn merge(dst: &mut serde_json::Value, src: serde_json::Value) { match (dst, src) { @@ -74,15 +81,24 @@ impl Project<'_> { } pub(crate) fn server(self) -> Server { - let tmp_dir = self.tmp_dir.unwrap_or_else(TestDir::new); + let tmp_dir = self.tmp_dir.unwrap_or_else(|| { + if self.root_dir_contains_symlink { + TestDir::new_symlink() + } else { + TestDir::new() + } + }); + static INIT: Once = Once::new(); INIT.call_once(|| { - let filter: tracing_subscriber::filter::Targets = - std::env::var("RA_LOG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); - let layer = - tracing_subscriber::fmt::Layer::new().with_test_writer().with_filter(filter); - tracing_subscriber::Registry::default().with(layer).init(); - profile::init_from(crate::PROFILE); + let _ = tracing::Config { + writer: TestWriter::default(), + // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually + // useful information in there for debugging. + filter: std::env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_string()), + chalk_filter: std::env::var("CHALK_DEBUG").ok(), + profile_filter: std::env::var("RA_PROFILE").ok(), + }; }); let FixtureWithProjectMeta { fixture, mini_core, proc_macro_names, toolchain } = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs index f7fceb5888696..b3ee7fa3d03fe 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs @@ -11,6 +11,14 @@ pub(crate) struct TestDir { impl TestDir { pub(crate) fn new() -> TestDir { + TestDir::new_dir(false) + } + + pub(crate) fn new_symlink() -> TestDir { + TestDir::new_dir(true) + } + + fn new_dir(symlink: bool) -> TestDir { let temp_dir = std::env::temp_dir(); // On MacOS builders on GitHub actions, the temp dir is a symlink, and // that causes problems down the line. Specifically: @@ -33,10 +41,24 @@ impl TestDir { continue; } fs::create_dir_all(&path).unwrap(); + + #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] + if symlink { + let symlink_path = base.join(format!("{pid}_{cnt}_symlink")); + #[cfg(any(target_os = "macos", target_os = "linux"))] + std::os::unix::fs::symlink(path, &symlink_path).unwrap(); + + #[cfg(target_os = "windows")] + std::os::windows::fs::symlink_dir(path, &symlink_path).unwrap(); + + return TestDir { path: symlink_path, keep: false }; + } + return TestDir { path, keep: false }; } panic!("Failed to create a temporary directory") } + #[allow(unused)] pub(crate) fn keep(mut self) -> TestDir { self.keep = true; @@ -52,9 +74,22 @@ impl Drop for TestDir { if self.keep { return; } + + let filetype = fs::symlink_metadata(&self.path).unwrap().file_type(); + let actual_path = filetype.is_symlink().then(|| fs::read_link(&self.path).unwrap()); + + if let Some(actual_path) = actual_path { + remove_dir_all(&actual_path).unwrap_or_else(|err| { + panic!( + "failed to remove temporary link to directory {}: {err}", + actual_path.display() + ) + }) + } + remove_dir_all(&self.path).unwrap_or_else(|err| { panic!("failed to remove temporary directory {}: {err}", self.path.display()) - }) + }); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs index dba336ea7d6dc..d3146ab7671cc 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -154,6 +154,7 @@ fn check_licenses() { Apache-2.0 Apache-2.0 OR BSL-1.0 Apache-2.0 OR MIT +Apache-2.0 WITH LLVM-exception Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT Apache-2.0/MIT BSD-3-Clause @@ -379,7 +380,7 @@ impl TidyDocs { ) } - for path in self.contains_fixme { + if let Some(path) = self.contains_fixme.first() { panic!("FIXME doc in a fully-documented crate: {}", path.display()) } } diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index 7617acde64a27..6796dc41886f5 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -1,8 +1,5 @@ //! File and span related types. -// FIXME: This should be moved into its own crate to get rid of the dependency inversion, base-db -// has business depending on tt, tt should depend on a span crate only (which unforunately will have -// to depend on salsa) -use std::fmt; +use std::fmt::{self, Write}; use salsa::InternId; @@ -37,6 +34,8 @@ pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = // is required to be stable for the proc-macro-server la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(!0 - 1)); +pub type Span = SpanData; + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct SpanData { /// The text range of this span, relative to the anchor. @@ -47,6 +46,7 @@ pub struct SpanData { /// The syntax context of the span. pub ctx: Ctx, } + impl Span { #[deprecated = "dummy spans will panic if surfaced incorrectly, as such they should be replaced appropriately"] pub const DUMMY: Self = SpanData { @@ -56,7 +56,17 @@ impl Span { }; } -pub type Span = SpanData; +impl fmt::Display for Span { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.anchor.file_id.index(), f)?; + f.write_char(':')?; + fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?; + f.write_char('@')?; + fmt::Debug::fmt(&self.range, f)?; + f.write_char('#')?; + self.ctx.fmt(f) + } +} #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContextId(InternId); @@ -212,6 +222,7 @@ impl fmt::Debug for HirFileIdRepr { } impl From for HirFileId { + #[allow(clippy::let_unit_value)] fn from(id: FileId) -> Self { _ = Self::ASSERT_MAX_FILE_ID_IS_SAME; assert!(id.index() <= Self::MAX_HIR_FILE_ID, "FileId index {} is too large", id.index()); @@ -220,6 +231,7 @@ impl From for HirFileId { } impl From for HirFileId { + #[allow(clippy::let_unit_value)] fn from(MacroFileId { macro_call_id: MacroCallId(id) }: MacroFileId) -> Self { _ = Self::ASSERT_MAX_FILE_ID_IS_SAME; let id = id.as_u32(); diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs index d69df91b63ef4..9f8101c816e5f 100644 --- a/src/tools/rust-analyzer/crates/span/src/map.rs +++ b/src/tools/rust-analyzer/crates/span/src/map.rs @@ -75,7 +75,7 @@ impl SpanMap { let (start, end) = (range.start(), range.end()); let start_entry = self.spans.partition_point(|&(it, _)| it <= start); let end_entry = self.spans[start_entry..].partition_point(|&(it, _)| it <= end); // FIXME: this might be wrong? - (&self.spans[start_entry..][..end_entry]).iter().map(|&(_, s)| s) + self.spans[start_entry..][..end_entry].iter().map(|&(_, s)| s) } pub fn iter(&self) -> impl Iterator + '_ { diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml index e6014cf812e56..2e3f9113b066a 100644 --- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml +++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] backtrace = { version = "0.3.67", optional = true } -always-assert = { version = "0.1.2", features = ["log"] } +always-assert = { version = "0.2.0", features = ["tracing"] } jod-thread = "0.1.2" libc.workspace = true crossbeam-channel = "0.5.5" diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 43909fff02cbc..07b7827228182 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -6,13 +6,13 @@ use std::io as sio; use std::process::Command; use std::{cmp::Ordering, ops, time::Instant}; +pub mod anymap; mod macros; -pub mod process; -pub mod panic_context; pub mod non_empty_vec; +pub mod panic_context; +pub mod process; pub mod rand; pub mod thread; -pub mod anymap; pub use always_assert::{always, never}; pub use itertools; @@ -171,6 +171,10 @@ pub fn char_has_case(c: char) -> bool { c.is_lowercase() || c.is_uppercase() } +pub fn is_upper_snake_case(s: &str) -> bool { + s.chars().all(|c| c.is_uppercase() || c == '_' || c.is_numeric()) +} + pub fn replace(buf: &mut String, from: char, to: &str) { if !buf.contains(from) { return; diff --git a/src/tools/rust-analyzer/crates/stdx/src/macros.rs b/src/tools/rust-analyzer/crates/stdx/src/macros.rs index d71e418c89bc6..85d9008fe123e 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/macros.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/macros.rs @@ -1,15 +1,5 @@ //! Convenience macros. -#[macro_export] -macro_rules! eprintln { - ($($tt:tt)*) => {{ - if $crate::is_ci() { - panic!("Forgot to remove debug-print?") - } - std::eprintln!($($tt)*) - }} -} - /// Appends formatted string to a `String`. #[macro_export] macro_rules! format_to { @@ -24,6 +14,22 @@ macro_rules! format_to { }; } +/// Appends formatted string to a `String` and returns the `String`. +/// +/// Useful for folding iterators into a `String`. +#[macro_export] +macro_rules! format_to_acc { + ($buf:expr, $lit:literal $($arg:tt)*) => { + { + use ::std::fmt::Write as _; + // We can't do ::std::fmt::Write::write_fmt($buf, format_args!($lit $($arg)*)) + // unfortunately, as that loses out on autoref behavior. + _ = $buf.write_fmt(format_args!($lit $($arg)*)); + $buf + } + }; +} + /// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums /// /// # Example diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index 9f78614bba66b..a0fd73ee13f57 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -22,6 +22,7 @@ once_cell = "1.17.0" indexmap.workspace = true smol_str.workspace = true triomphe.workspace = true +tracing.workspace = true ra-ap-rustc_lexer.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs index c402a7bceaebc..01f2af419ed89 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs @@ -120,7 +120,7 @@ pub struct TreeDiff { impl TreeDiff { pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { - let _p = profile::span("into_text_edit"); + let _p = tracing::span!(tracing::Level::INFO, "into_text_edit").entered(); for (anchor, to) in &self.insertions { let offset = match anchor { @@ -149,7 +149,7 @@ impl TreeDiff { /// /// This function tries to find a fine-grained diff. pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { - let _p = profile::span("diff"); + let _p = tracing::span!(tracing::Level::INFO, "diff").entered(); let mut diff = TreeDiff { replacements: FxHashMap::default(), @@ -207,7 +207,7 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) } }; - diff.insertions.entry(insert_pos).or_insert_with(Vec::new).push(element); + diff.insertions.entry(insert_pos).or_default().push(element); } (Some(element), None) => { cov_mark::hit!(diff_delete); @@ -239,7 +239,7 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) }; - diff.insertions.entry(insert_pos).or_insert_with(Vec::new).extend(drain); + diff.insertions.entry(insert_pos).or_default().extend(drain); rhs_children = rhs_children_clone; } else { go(diff, lhs_ele, rhs_ele); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index cc90d2dd1d55b..e9ab7a4320b0c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -1,15 +1,15 @@ //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s -mod generated; -mod traits; -mod token_ext; -mod node_ext; -mod expr_ext; -mod operators; pub mod edit; pub mod edit_in_place; +mod expr_ext; +mod generated; pub mod make; +mod node_ext; +mod operators; pub mod prec; +mod token_ext; +mod traits; use std::marker::PhantomData; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index aa56f10d6095c..c9944b75b0964 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -1,6 +1,6 @@ //! Structural editing for ast. -use std::iter::{empty, successors}; +use std::iter::{empty, once, successors}; use parser::{SyntaxKind, T}; @@ -530,6 +530,30 @@ impl ast::UseTree { Some(()) } } + + /// Wraps the use tree in use tree list with no top level path (if it isn't already). + /// + /// # Examples + /// + /// `foo::bar` -> `{foo::bar}` + /// + /// `{foo::bar}` -> `{foo::bar}` + pub fn wrap_in_tree_list(&self) -> Option<()> { + if self.use_tree_list().is_some() + && self.path().is_none() + && self.star_token().is_none() + && self.rename().is_none() + { + return None; + } + let subtree = self.clone_subtree().clone_for_update(); + ted::remove_all_iter(self.syntax().children_with_tokens()); + ted::append_child( + self.syntax(), + make::use_tree_list(once(subtree)).clone_for_update().syntax(), + ); + Some(()) + } } impl ast::UseTreeList { @@ -941,10 +965,10 @@ impl ast::IdentPat { } pub trait HasVisibilityEdit: ast::HasVisibility { - fn set_visibility(&self, visbility: ast::Visibility) { + fn set_visibility(&self, visibility: ast::Visibility) { match self.visibility() { Some(current_visibility) => { - ted::replace(current_visibility.syntax(), visbility.syntax()) + ted::replace(current_visibility.syntax(), visibility.syntax()) } None => { let vis_before = self @@ -953,7 +977,7 @@ pub trait HasVisibilityEdit: ast::HasVisibility { .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) .unwrap_or_else(|| self.syntax().first_child_or_token().unwrap()); - ted::insert(ted::Position::before(vis_before), visbility.syntax()); + ted::insert(ted::Position::before(vis_before), visibility.syntax()); } } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index b1dd1fe8c829a..d5eda8f15e4a0 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -9,10 +9,11 @@ //! API should require to assemble every node piecewise. The trick of //! `parse(format!())` we use internally is an implementation detail -- long //! term, it will be replaced with direct tree manipulation. + use itertools::Itertools; use parser::T; use rowan::NodeOrToken; -use stdx::{format_to, never}; +use stdx::{format_to, format_to_acc, never}; use crate::{ast, utils::is_raw_identifier, AstNode, SourceFile, SyntaxKind, SyntaxToken}; @@ -595,6 +596,9 @@ pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr { expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") }) } +pub fn expr_reborrow(expr: ast::Expr) -> ast::Expr { + expr_from_text(&format!("&mut *{expr}")) +} pub fn expr_closure(pats: impl IntoIterator, expr: ast::Expr) -> ast::Expr { let params = pats.into_iter().join(", "); expr_from_text(&format!("|{params}| {expr}")) @@ -756,15 +760,12 @@ pub fn match_arm_with_guard( } pub fn match_arm_list(arms: impl IntoIterator) -> ast::MatchArmList { - let arms_str = arms - .into_iter() - .map(|arm| { - let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like()); - let comma = if needs_comma { "," } else { "" }; - let arm = arm.syntax(); - format!(" {arm}{comma}\n") - }) - .collect::(); + let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| { + let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like()); + let comma = if needs_comma { "," } else { "" }; + let arm = arm.syntax(); + format_to_acc!(acc, " {arm}{comma}\n") + }); return from_text(&arms_str); fn from_text(text: &str) -> ast::MatchArmList { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 1c6157de55958..6e5e4127f4d43 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -53,6 +53,12 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> { } } +impl ast::Abi { + pub fn abi_string(&self) -> Option { + support::token(&self.syntax, SyntaxKind::STRING).and_then(ast::String::cast) + } +} + impl ast::HasModuleItem for ast::StmtList {} impl ast::BlockExpr { @@ -327,6 +333,14 @@ impl ast::UseTree { pub fn parent_use_tree_list(&self) -> Option { self.syntax().parent().and_then(ast::UseTreeList::cast) } + + pub fn top_use_tree(&self) -> ast::UseTree { + let mut this = self.clone(); + while let Some(use_tree_list) = this.parent_use_tree_list() { + this = use_tree_list.parent_use_tree(); + } + this + } } impl ast::UseTreeList { @@ -356,8 +370,12 @@ impl ast::UseTreeList { let remove_brace_in_use_tree_list = |u: &ast::UseTreeList| { let use_tree_count = u.use_trees().count(); if use_tree_count == 1 { - u.l_curly_token().map(ted::remove); - u.r_curly_token().map(ted::remove); + if let Some(a) = u.l_curly_token() { + ted::remove(a) + } + if let Some(a) = u.r_curly_token() { + ted::remove(a) + } u.comma().for_each(ted::remove); } }; @@ -366,7 +384,7 @@ impl ast::UseTreeList { // the below remove the innermost {}, got `use crate::{{{A}}}` remove_brace_in_use_tree_list(&self); - // the below remove othe unnecessary {}, got `use crate::A` + // the below remove other unnecessary {}, got `use crate::A` while let Some(parent_use_tree_list) = self.parent_use_tree().parent_use_tree_list() { remove_brace_in_use_tree_list(&parent_use_tree_list); self = parent_use_tree_list; @@ -440,6 +458,12 @@ impl ast::Struct { } } +impl ast::Union { + pub fn kind(&self) -> StructKind { + StructKind::from_node(self) + } +} + impl ast::RecordExprField { pub fn for_field_name(field_name: &ast::NameRef) -> Option { let candidate = Self::for_name_ref(field_name)?; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index ede392fc62a2c..7cd1f1550b988 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -1,9 +1,12 @@ //! There are many AstNodes, but only a few tokens, so we hand-write them here. -use std::borrow::Cow; +use std::{ + borrow::Cow, + num::{ParseFloatError, ParseIntError}, +}; use rustc_lexer::unescape::{ - unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode, + unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode, }; use crate::{ @@ -190,7 +193,7 @@ pub trait IsString: AstToken { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; - unescape_literal(text, Self::MODE, &mut |range, unescaped_char| { + unescape_unicode(text, Self::MODE, &mut |range, unescaped_char| { let text_range = TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); cb(text_range + offset, unescaped_char); @@ -223,7 +226,7 @@ impl ast::String { let mut buf = String::new(); let mut prev_end = 0; let mut has_error = false; - unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match ( + unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { @@ -267,7 +270,7 @@ impl ast::ByteString { let mut buf: Vec = Vec::new(); let mut prev_end = 0; let mut has_error = false; - unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match ( + unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { @@ -308,7 +311,7 @@ impl IsString for ast::CString { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; - unescape_c_string(text, Self::MODE, &mut |range, unescaped_char| { + unescape_mixed(text, Self::MODE, &mut |range, unescaped_char| { let text_range = TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); // XXX: This method should only be used for highlighting ranges. The unescaped @@ -333,12 +336,11 @@ impl ast::CString { let mut buf = Vec::new(); let mut prev_end = 0; let mut has_error = false; - let mut char_buf = [0u8; 4]; - let mut extend_unit = |buf: &mut Vec, unit: CStrUnit| match unit { - CStrUnit::Byte(b) => buf.push(b), - CStrUnit::Char(c) => buf.extend(c.encode_utf8(&mut char_buf).as_bytes()), + let extend_unit = |buf: &mut Vec, unit: MixedUnit| match unit { + MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()), + MixedUnit::HighByte(b) => buf.push(b), }; - unescape_c_string(text, Self::MODE, &mut |char_range, unescaped| match ( + unescape_mixed(text, Self::MODE, &mut |char_range, unescaped| match ( unescaped, buf.capacity() == 0, ) { @@ -391,10 +393,9 @@ impl ast::IntNumber { (prefix, text, suffix) } - pub fn value(&self) -> Option { + pub fn value(&self) -> Result { let (_, text, _) = self.split_into_parts(); - let value = u128::from_str_radix(&text.replace('_', ""), self.radix() as u32).ok()?; - Some(value) + u128::from_str_radix(&text.replace('_', ""), self.radix() as u32) } pub fn suffix(&self) -> Option<&str> { @@ -445,9 +446,14 @@ impl ast::FloatNumber { } } - pub fn value(&self) -> Option { + pub fn value(&self) -> Result { let (text, _) = self.split_into_parts(); - text.replace('_', "").parse::().ok() + text.replace('_', "").parse::() + } + + pub fn value_f32(&self) -> Result { + let (text, _) = self.split_into_parts(); + text.replace('_', "").parse::() } } @@ -471,6 +477,38 @@ impl Radix { } } +impl ast::Char { + pub fn value(&self) -> Option { + let mut text = self.text(); + if text.starts_with('\'') { + text = &text[1..]; + } else { + return None; + } + if text.ends_with('\'') { + text = &text[0..text.len() - 1]; + } + + unescape_char(text).ok() + } +} + +impl ast::Byte { + pub fn value(&self) -> Option { + let mut text = self.text(); + if text.starts_with("b\'") { + text = &text[2..]; + } else { + return None; + } + if text.ends_with('\'') { + text = &text[0..text.len() - 1]; + } + + unescape_byte(text).ok() + } +} + #[cfg(test)] mod tests { use crate::ast::{self, make, FloatNumber, IntNumber}; @@ -484,12 +522,15 @@ mod tests { } fn check_float_value(lit: &str, expected: impl Into> + Copy) { - assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + assert_eq!( + FloatNumber { syntax: make::tokens::literal(lit) }.value().ok(), + expected.into() + ); assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into()); } fn check_int_value(lit: &str, expected: impl Into>) { - assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value().ok(), expected.into()); } #[test] @@ -569,35 +610,3 @@ bcde", b"abcde", check_int_value("1_1_1_1_1_1", 111111); } } - -impl ast::Char { - pub fn value(&self) -> Option { - let mut text = self.text(); - if text.starts_with('\'') { - text = &text[1..]; - } else { - return None; - } - if text.ends_with('\'') { - text = &text[0..text.len() - 1]; - } - - unescape_char(text).ok() - } -} - -impl ast::Byte { - pub fn value(&self) -> Option { - let mut text = self.text(); - if text.starts_with("b\'") { - text = &text[2..]; - } else { - return None; - } - if text.ends_with('\'') { - text = &text[0..text.len() - 1]; - } - - unescape_byte(text).ok() - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index 1b41596a5f27b..62a0261d7a459 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -32,22 +32,22 @@ macro_rules! eprintln { ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; } -mod syntax_node; -mod syntax_error; mod parsing; -mod validation; mod ptr; -mod token_text; +mod syntax_error; +mod syntax_node; #[cfg(test)] mod tests; +mod token_text; +mod validation; pub mod algo; pub mod ast; #[doc(hidden)] pub mod fuzz; -pub mod utils; -pub mod ted; pub mod hacks; +pub mod ted; +pub mod utils; use std::marker::PhantomData; @@ -70,7 +70,7 @@ pub use rowan::{ api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent, }; -pub use smol_str::SmolStr; +pub use smol_str::{format_smolstr, SmolStr}; /// `Parse` is the result of the parsing: a syntax tree and a collection of /// errors. diff --git a/src/tools/rust-analyzer/crates/syntax/src/ptr.rs b/src/tools/rust-analyzer/crates/syntax/src/ptr.rs index 8750147ee11af..b716d3670667e 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ptr.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ptr.rs @@ -36,7 +36,7 @@ impl std::fmt::Debug for AstPtr { impl Copy for AstPtr {} impl Clone for AstPtr { fn clone(&self) -> AstPtr { - AstPtr { raw: self.raw.clone(), _ty: PhantomData } + AstPtr { raw: self.raw, _ty: PhantomData } } } @@ -65,7 +65,7 @@ impl AstPtr { } pub fn syntax_node_ptr(&self) -> SyntaxNodePtr { - self.raw.clone() + self.raw } pub fn text_range(&self) -> TextRange { diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests.rs b/src/tools/rust-analyzer/crates/syntax/src/tests.rs index 8ae1242cf7fd4..4c0a538f712f5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests.rs @@ -11,6 +11,7 @@ use std::{ use ast::HasName; use expect_test::expect_file; use rayon::prelude::*; +use stdx::format_to_acc; use test_utils::{bench, bench_fixture, project_root}; use crate::{ast, fuzz, AstNode, SourceFile, SyntaxError}; @@ -104,10 +105,9 @@ fn self_hosting_parsing() { .collect::>(); if !errors.is_empty() { - let errors = errors - .into_iter() - .map(|(path, err)| format!("{}: {:?}\n", path.display(), err[0])) - .collect::(); + let errors = errors.into_iter().fold(String::new(), |mut acc, (path, err)| { + format_to_acc!(acc, "{}: {:?}\n", path.display(), err[0]) + }); panic!("Parsing errors:\n{errors}\n"); } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 69dffbf79f191..5c5b26f525f66 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -5,7 +5,7 @@ mod block; use rowan::Direction; -use rustc_lexer::unescape::{self, unescape_literal, Mode}; +use rustc_lexer::unescape::{self, unescape_mixed, unescape_unicode, Mode}; use crate::{ algo, @@ -140,7 +140,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { ast::LiteralKind::String(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 1, '"') { - unescape_literal(without_quotes, Mode::Str, &mut |range, char| { + unescape_unicode(without_quotes, Mode::Str, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -151,7 +151,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { ast::LiteralKind::ByteString(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| { + unescape_unicode(without_quotes, Mode::ByteStr, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -162,7 +162,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { ast::LiteralKind::CString(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| { + unescape_mixed(without_quotes, Mode::CStr, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -172,7 +172,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { } ast::LiteralKind::Char(_) => { if let Some(without_quotes) = unquote(text, 1, '\'') { - unescape_literal(without_quotes, Mode::Char, &mut |range, char| { + unescape_unicode(without_quotes, Mode::Char, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -181,7 +181,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { } ast::LiteralKind::Byte(_) => { if let Some(without_quotes) = unquote(text, 2, '\'') { - unescape_literal(without_quotes, Mode::Byte, &mut |range, char| { + unescape_unicode(without_quotes, Mode::Byte, &mut |range, char| { if let Err(err) = char { push_err(2, range.start, err); } diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 1a042b2dea20c..b5ff7a1bf51bf 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -354,7 +354,7 @@ impl ChangeFixture { files, change: Change { source_change, - proc_macros: proc_macros.is_empty().not().then(|| proc_macros), + proc_macros: proc_macros.is_empty().not().then_some(proc_macros), }, } } diff --git a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml index 56067d8341789..2ff1fad6c29d9 100644 --- a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml +++ b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml @@ -15,10 +15,11 @@ doctest = false # Avoid adding deps here, this crate is widely used in tests it should compile fast! dissimilar = "1.0.7" text-size.workspace = true +tracing.workspace = true rustc-hash.workspace = true stdx.workspace = true profile.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 140bb08042785..9c25d88cb8428 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -28,11 +28,11 @@ //! env: option //! eq: sized //! error: fmt -//! fmt: result, transmute, coerce_unsized +//! fmt: option, result, transmute, coerce_unsized //! fn: //! from: sized //! future: pin -//! generator: pin +//! coroutine: pin //! hash: //! include: //! index: sized @@ -798,26 +798,26 @@ pub mod ops { // endregion:builtin_impls // endregion:add - // region:generator - mod generator { + // region:coroutine + mod coroutine { use crate::pin::Pin; - #[lang = "generator"] - pub trait Generator { + #[lang = "coroutine"] + pub trait Coroutine { type Yield; - #[lang = "generator_return"] + #[lang = "coroutine_return"] type Return; - fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState; + fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState; } - #[lang = "generator_state"] - pub enum GeneratorState { + #[lang = "coroutine_state"] + pub enum CoroutineState { Yielded(Y), Complete(R), } } - pub use self::generator::{Generator, GeneratorState}; - // endregion:generator + pub use self::coroutine::{Coroutine, CoroutineState}; + // endregion:coroutine } // region:eq @@ -987,6 +987,10 @@ pub mod fmt { Arguments { pieces, fmt: None, args } } + pub const fn new_const(pieces: &'a [&'static str]) -> Arguments<'a> { + Arguments { pieces, fmt: None, args: &[] } + } + pub fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], @@ -1166,6 +1170,7 @@ pub mod future { task::{Context, Poll}, }; + #[doc(notable_trait)] #[lang = "future_trait"] pub trait Future { type Output; @@ -1264,6 +1269,7 @@ pub mod iter { mod traits { mod iterator { + #[doc(notable_trait)] pub trait Iterator { type Item; #[lang = "next"] @@ -1344,6 +1350,9 @@ pub mod iter { // region:panic mod panic { pub macro panic_2021 { + () => ( + $crate::panicking::panic("explicit panic") + ), ($($t:tt)+) => ( $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) ), @@ -1355,6 +1364,11 @@ mod panicking { pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! { loop {} } + + #[lang = "panic"] + pub const fn panic(expr: &'static str) -> ! { + panic_fmt(crate::fmt::Arguments::new_const(&[expr])) + } } // endregion:panic diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index 19b34ffe6b9d7..15a0ea5409a15 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -103,7 +103,12 @@ impl NotifyActor { let config_version = config.version; let n_total = config.load.len(); - self.send(loader::Message::Progress { n_total, n_done: 0, config_version }); + self.send(loader::Message::Progress { + n_total, + n_done: None, + config_version, + dir: None, + }); self.watched_entries.clear(); @@ -112,12 +117,19 @@ impl NotifyActor { if watch { self.watched_entries.push(entry.clone()); } - let files = self.load_entry(entry, watch); + let files = + self.load_entry(entry, watch, |file| loader::Message::Progress { + n_total, + n_done: Some(i), + dir: Some(file), + config_version, + }); self.send(loader::Message::Loaded { files }); self.send(loader::Message::Progress { n_total, - n_done: i + 1, + n_done: Some(i + 1), config_version, + dir: None, }); } } @@ -170,6 +182,7 @@ impl NotifyActor { &mut self, entry: loader::Entry, watch: bool, + make_message: impl Fn(AbsPathBuf) -> loader::Message, ) -> Vec<(AbsPathBuf, Option>)> { match entry { loader::Entry::Files(files) => files @@ -186,6 +199,7 @@ impl NotifyActor { let mut res = Vec::new(); for root in &dirs.include { + self.send(make_message(root.clone())); let walkdir = WalkDir::new(root).follow_links(true).into_iter().filter_entry(|entry| { if !entry.file_type().is_dir() { @@ -197,9 +211,13 @@ impl NotifyActor { }); let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| { + let depth = entry.depth(); let is_dir = entry.file_type().is_dir(); let is_file = entry.file_type().is_file(); let abs_path = AbsPathBuf::assert(entry.into_path()); + if depth < 2 && is_dir { + self.send(make_message(abs_path.clone())); + } if is_dir && watch { self.watch(abs_path.clone()); } diff --git a/src/tools/rust-analyzer/crates/vfs/src/loader.rs b/src/tools/rust-analyzer/crates/vfs/src/loader.rs index 89a544c81d8c9..e49849d230776 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/loader.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/loader.rs @@ -48,7 +48,16 @@ pub enum Message { /// Indicate a gradual progress. /// /// This is supposed to be the number of loaded files. - Progress { n_total: usize, n_done: usize, config_version: u32 }, + Progress { + /// The total files to be loaded. + n_total: usize, + /// The files that have been loaded successfully. + n_done: Option, + /// The dir being loaded, `None` if its for a file. + dir: Option, + /// The [`Config`] version. + config_version: u32, + }, /// The handle loaded the following files' content. Loaded { files: Vec<(AbsPathBuf, Option>)> }, /// The handle loaded the following files' content. @@ -204,10 +213,11 @@ impl fmt::Debug for Message { Message::Changed { files } => { f.debug_struct("Changed").field("n_files", &files.len()).finish() } - Message::Progress { n_total, n_done, config_version } => f + Message::Progress { n_total, n_done, dir, config_version } => f .debug_struct("Progress") .field("n_total", n_total) .field("n_done", n_done) + .field("dir", dir) .field("config_version", config_version) .finish(), } diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 3251dd752682e..bc558c202472e 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -239,13 +239,13 @@ The primary goal of `onEnter` is to handle automatic indentation when opening a This is not yet implemented. The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals. -As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTextEdit`. +As proper cursor positioning is raison d'être for `onEnter`, it uses `SnippetTextEdit`. ### Unresolved Question * How to deal with synchronicity of the request? One option is to require the client to block until the server returns the response. - Another option is to do a OT-style merging of edits from client and server. + Another option is to do a operational transforms style merging of edits from client and server. A third option is to do a record-replay: client applies heuristic on enter immediately, then applies all user's keypresses. When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response. * How to deal with multiple carets? diff --git a/src/tools/rust-analyzer/docs/dev/style.md b/src/tools/rust-analyzer/docs/dev/style.md index 786127639ce75..4c5299bde3e91 100644 --- a/src/tools/rust-analyzer/docs/dev/style.md +++ b/src/tools/rust-analyzer/docs/dev/style.md @@ -99,14 +99,7 @@ Including a description and GIF suitable for the changelog means less work for t ## Clippy -We don't enforce Clippy. -A number of default lints have high false positive rate. -Selectively patching false-positives with `allow(clippy)` is probably worse than entirely disabling a problematic lint. -There's a `cargo lint` command which runs a subset of low-FPR lints. -Careful tweaking of `lint` is welcome. -Of course, applying Clippy suggestions is welcome as long as they indeed improve the code. - -**Rationale:** see [rust-lang/clippy#5537](https://github.com/rust-lang/rust-clippy/issues/5537). +We use Clippy to improve the code, but if some lints annoy you, allow them in the [Cargo.toml](../../Cargo.toml) [workspace.lints.clippy] section. # Code diff --git a/src/tools/rust-analyzer/docs/dev/syntax.md b/src/tools/rust-analyzer/docs/dev/syntax.md index fd6f220f4fa90..6c4daecc58ff7 100644 --- a/src/tools/rust-analyzer/docs/dev/syntax.md +++ b/src/tools/rust-analyzer/docs/dev/syntax.md @@ -128,7 +128,7 @@ Interior nodes are shared as well (for example in `(1 + 1) * (1 + 1)`). Note that, the result of the interning is an `Arc`. That is, it's not an index into interning table, so you don't have to have the table around to do anything with the tree. Each tree is fully self-contained (although different trees might share parts). -Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-contex one. +Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-context one. We use a `TextSize`, a newtyped `u32`, to store the length of the text. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index ecc90abff1353..cfa7503d73900 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -121,6 +121,16 @@ Unsetting this disables sysroot loading. This option does not take effect until rust-analyzer is restarted. -- +[[rust-analyzer.cargo.sysrootQueryMetadata]]rust-analyzer.cargo.sysrootQueryMetadata (default: `false`):: ++ +-- +Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze +third-party dependencies of the standard libraries. + +This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer +will attempt to clean up afterwards, but nevertheless requires the location to be +writable to. +-- [[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`):: + -- @@ -767,6 +777,16 @@ Internal config, path to proc-macro server executable. -- Exclude imports from find-all-references. -- +[[rust-analyzer.references.excludeTests]]rust-analyzer.references.excludeTests (default: `false`):: ++ +-- +Exclude tests from find-all-references. +-- +[[rust-analyzer.rename.allowExternalItems]]rust-analyzer.rename.allowExternalItems (default: `false`):: ++ +-- +Allow renaming of items not belonging to the loaded workspaces. +-- [[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index fa8413c19ae07..9e9ea25779047 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -369,7 +369,7 @@ EOF See https://sharksforarms.dev/posts/neovim-rust/ for more tips on getting started. -Check out https://github.com/simrat39/rust-tools.nvim for a batteries included rust-analyzer setup for Neovim. +Check out https://github.com/mrcjkb/rustaceanvim for a batteries included rust-analyzer setup for Neovim. ==== vim-lsp @@ -512,7 +512,8 @@ https://docs.helix-editor.com/[Helix] supports LSP by default. However, it won't install `rust-analyzer` automatically. You can follow instructions for installing <>. -=== Visual Studio 2022 +[#visual-studio] +=== [[visual-studio-2022]]Visual Studio 2022 There are multiple rust-analyzer extensions for Visual Studio 2022 on Windows: diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 8307f6833e6fb..841e364ed8457 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -648,6 +648,11 @@ "string" ] }, + "rust-analyzer.cargo.sysrootQueryMetadata": { + "markdownDescription": "Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze\nthird-party dependencies of the standard libraries.\n\nThis will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer\nwill attempt to clean up afterwards, but nevertheless requires the location to be\nwritable to.", + "default": false, + "type": "boolean" + }, "rust-analyzer.cargo.sysrootSrc": { "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.", "default": null, @@ -1115,13 +1120,15 @@ "preserve", "crate", "module", - "item" + "item", + "one" ], "enumDescriptions": [ "Do not change the granularity of any imports and preserve the original structure written by the developer.", "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", - "Flatten imports so that each has its own use statement." + "Flatten imports so that each has its own use statement.", + "Merge all imports into a single use statement as long as they have the same visibility and attributes." ] }, "rust-analyzer.imports.group.enable": { @@ -1498,6 +1505,16 @@ "default": false, "type": "boolean" }, + "rust-analyzer.references.excludeTests": { + "markdownDescription": "Exclude tests from find-all-references.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.rename.allowExternalItems": { + "markdownDescription": "Allow renaming of items not belonging to the loaded workspaces.", + "default": false, + "type": "boolean" + }, "rust-analyzer.runnables.command": { "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", "default": null, diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 599cfb4ff77a1..c386b9e5d8fb5 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -25,16 +25,7 @@ export async function deactivate() { export async function activate( context: vscode.ExtensionContext, ): Promise { - if (vscode.extensions.getExtension("rust-lang.rust")) { - vscode.window - .showWarningMessage( - `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + - "plugins enabled. These are known to conflict and cause various functions of " + - "both plugins to not work correctly. You should disable one of them.", - "Got it", - ) - .then(() => {}, console.error); - } + checkConflictingExtensions(); const ctx = new Ctx(context, createCommands(), fetchWorkspace()); // VS Code doesn't show a notification when an extension fails to activate @@ -200,3 +191,26 @@ function createCommands(): Record { revealDependency: { enabled: commands.revealDependency }, }; } + +function checkConflictingExtensions() { + if (vscode.extensions.getExtension("rust-lang.rust")) { + vscode.window + .showWarningMessage( + `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + + "plugins enabled. These are known to conflict and cause various functions of " + + "both plugins to not work correctly. You should disable one of them.", + "Got it", + ) + .then(() => {}, console.error); + } + + if (vscode.extensions.getExtension("panicbit.cargo")) { + vscode.window + .showWarningMessage( + `You have both the rust-analyzer (rust-lang.rust-analyzer) and Cargo (panicbit.cargo) plugins enabled` + + 'you can disable it or set {"cargo.automaticCheck": false} in settings.json to avoid invoking cargo twice', + "Got it", + ) + .then(() => {}, console.error); + } +} diff --git a/src/tools/rust-analyzer/lib/la-arena/src/map.rs b/src/tools/rust-analyzer/lib/la-arena/src/map.rs index 750f345b5398d..c6a43d8f9a68a 100644 --- a/src/tools/rust-analyzer/lib/la-arena/src/map.rs +++ b/src/tools/rust-analyzer/lib/la-arena/src/map.rs @@ -252,6 +252,8 @@ where { /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference /// to the value in the entry. + // BUG this clippy lint is a false positive + #[allow(clippy::unwrap_or_default)] pub fn or_default(self) -> &'a mut V { self.or_insert_with(Default::default) } diff --git a/src/tools/rust-analyzer/lib/line-index/src/lib.rs b/src/tools/rust-analyzer/lib/line-index/src/lib.rs index 58f266d67f629..1ab62e99235f6 100644 --- a/src/tools/rust-analyzer/lib/line-index/src/lib.rs +++ b/src/tools/rust-analyzer/lib/line-index/src/lib.rs @@ -227,6 +227,22 @@ fn analyze_source_file_dispatch( } } +#[cfg(target_arch = "aarch64")] +fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut IntMap>, +) { + if std::arch::is_aarch64_feature_detected!("neon") { + // SAFETY: NEON support was checked + unsafe { + analyze_source_file_neon(src, lines, multi_byte_chars); + } + } else { + analyze_source_file_generic(src, src.len(), TextSize::from(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 @@ -322,7 +338,102 @@ unsafe fn analyze_source_file_sse2( } } -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +#[target_feature(enable = "neon")] +#[cfg(target_arch = "aarch64")] +#[inline] +// See https://community.arm.com/arm-community-blogs/b/infrastructure-solutions-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon +// +// The mask is a 64-bit integer, where each 4-bit corresponds to a u8 in the +// input vector. The least significant 4 bits correspond to the first byte in +// the vector. +unsafe fn move_mask(v: std::arch::aarch64::uint8x16_t) -> u64 { + use std::arch::aarch64::*; + + let nibble_mask = vshrn_n_u16(vreinterpretq_u16_u8(v), 4); + vget_lane_u64(vreinterpret_u64_u8(nibble_mask), 0) +} + +#[target_feature(enable = "neon")] +#[cfg(target_arch = "aarch64")] +unsafe fn analyze_source_file_neon( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut IntMap>, +) { + use std::arch::aarch64::*; + + const CHUNK_SIZE: usize = 16; + + let src_bytes = src.as_bytes(); + + let chunk_count = src.len() / CHUNK_SIZE; + + let newline = vdupq_n_s8(b'\n' as i8); + + // 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 i8; + let chunk = vld1q_s8(ptr.add(chunk_index * CHUNK_SIZE)); + + // 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 = vcltzq_s8(chunk); + // Create a bit mask from the comparison results. + let multibyte_mask = move_mask(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 = vceqq_s8(chunk, newline); + let mut newlines_mask = move_mask(newlines_test); + + // If the bit mask is not all zero, there are newlines in this chunk. + if newlines_mask != 0 { + let output_offset = TextSize::from((chunk_index * CHUNK_SIZE + 1) as u32); + + while newlines_mask != 0 { + let trailing_zeros = newlines_mask.trailing_zeros(); + let index = trailing_zeros / 4; + + lines.push(TextSize::from(index) + output_offset); + + // Clear the current 4-bit, so we can find the next one. + newlines_mask &= (!0xF) << trailing_zeros; + } + } + continue; + } + + 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, + TextSize::from(scan_start as u32), + lines, + multi_byte_chars, + ); + } + + 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, + TextSize::from(tail_start as u32), + lines, + multi_byte_chars, + ); + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] // The target (or compiler version) does not support SSE2 ... fn analyze_source_file_dispatch( src: &str, diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/error.rs b/src/tools/rust-analyzer/lib/lsp-server/src/error.rs index ebdd153b5b317..da55393339028 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/error.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/error.rs @@ -14,7 +14,7 @@ impl ProtocolError { ProtocolError("disconnected channel".into(), true) } - /// Whether this error occured due to a disconnected channel. + /// Whether this error occurred due to a disconnected channel. pub fn channel_is_disconnected(&self) -> bool { self.1 } diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs index 6b732d4702940..e476f8c2d1345 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs @@ -6,11 +6,11 @@ #![warn(rust_2018_idioms, unused_lifetimes)] -mod msg; -mod stdio; mod error; -mod socket; +mod msg; mod req_queue; +mod socket; +mod stdio; use std::{ io, @@ -184,9 +184,9 @@ impl Connection { }; } - return Err(ProtocolError::new(String::from( + Err(ProtocolError::new(String::from( "Initialization has been aborted during initialization", - ))); + ))) } /// Finishes the initialization process by sending an `InitializeResult` to the client @@ -244,9 +244,9 @@ impl Connection { } } - return Err(ProtocolError::new(String::from( + Err(ProtocolError::new(String::from( "Initialization has been aborted during initialization", - ))); + ))) } /// Initialize the connection. Sends the server capabilities @@ -358,12 +358,14 @@ impl Connection { ))) } Err(RecvTimeoutError::Timeout) => { - return Err(ProtocolError::new(format!("timed out waiting for exit notification"))) + return Err(ProtocolError::new( + "timed out waiting for exit notification".to_string(), + )) } Err(RecvTimeoutError::Disconnected) => { - return Err(ProtocolError::new(format!( - "channel disconnected waiting for exit notification" - ))) + return Err(ProtocolError::new( + "channel disconnected waiting for exit notification".to_string(), + )) } } Ok(true) diff --git a/src/tools/rust-analyzer/rustfmt.toml b/src/tools/rust-analyzer/rustfmt.toml index 71007de81b9f6..20bf59547b86a 100644 --- a/src/tools/rust-analyzer/rustfmt.toml +++ b/src/tools/rust-analyzer/rustfmt.toml @@ -1,2 +1,2 @@ -reorder_modules = false +reorder_modules = true use_small_heuristics = "Max" diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs index 49f8ae79baf0e..2d40ceb737dff 100644 --- a/src/tools/rust-analyzer/xtask/src/main.rs +++ b/src/tools/rust-analyzer/xtask/src/main.rs @@ -12,11 +12,11 @@ mod flags; -mod install; -mod release; mod dist; -mod publish; +mod install; mod metrics; +mod publish; +mod release; use anyhow::bail; use std::{ diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs index 845928432c4fd..c05874a0ccac4 100644 --- a/src/tools/rust-analyzer/xtask/src/metrics.rs +++ b/src/tools/rust-analyzer/xtask/src/metrics.rs @@ -113,7 +113,13 @@ impl Metrics { ) -> anyhow::Result<()> { assert!(Path::new(path).exists(), "unable to find bench in {path}"); eprintln!("\nMeasuring analysis-stats/{name}"); - let output = cmd!(sh, "./target/release/rust-analyzer -q analysis-stats {path}").read()?; + let output = cmd!( + sh, + "./target/release/rust-analyzer -q analysis-stats {path} --query-sysroot-metadata" + ) + // the sysroot uses `public-dependency`, so we make cargo think it's a nightly + .env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly") + .read()?; for (metric, value, unit) in parse_metrics(&output) { self.report(&format!("analysis-stats/{name}/{metric}"), value, unit.into()); } diff --git a/src/tools/rust-installer/test.sh b/src/tools/rust-installer/test.sh index 4f69bfc63e973..16b05c66197c8 100755 --- a/src/tools/rust-installer/test.sh +++ b/src/tools/rust-installer/test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e -u diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 2dd2622174f81..a9f9ea1826ae5 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -1,7 +1,7 @@ -use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ast, ptr}; -use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::parser::{ForceCollect, Parser, Recovery}; use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{self, kw}; @@ -15,7 +15,7 @@ pub(crate) mod cfg_if; pub(crate) mod lazy_static; fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> { - stream_to_parser(sess, tokens, MACRO_ARGUMENTS) + stream_to_parser(sess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden) } fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> { @@ -24,45 +24,51 @@ fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { macro_rules! parse_macro_arg { - ($macro_arg:ident, $parser:expr, $f:expr) => { + ($macro_arg:ident, $nt_kind:expr, $try_parse:expr, $then:expr) => { let mut cloned_parser = (*parser).clone(); - match $parser(&mut cloned_parser) { - Ok(x) => { - if parser.sess.dcx.has_errors().is_some() { + if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) { + match $try_parse(&mut cloned_parser) { + Ok(x) => { + if parser.sess.dcx.has_errors().is_some() { + parser.sess.dcx.reset_err_count(); + } else { + // Parsing succeeded. + *parser = cloned_parser; + return Some(MacroArg::$macro_arg($then(x)?)); + } + } + Err(e) => { + e.cancel(); parser.sess.dcx.reset_err_count(); - } else { - // Parsing succeeded. - *parser = cloned_parser; - return Some(MacroArg::$macro_arg($f(x)?)); } } - Err(e) => { - e.cancel(); - parser.sess.dcx.reset_err_count(); - } } }; } parse_macro_arg!( Expr, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(), + NonterminalKind::Expr, + |parser: &mut Parser<'b>| parser.parse_expr(), |x: ptr::P| Some(x) ); parse_macro_arg!( Ty, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(), + NonterminalKind::Ty, + |parser: &mut Parser<'b>| parser.parse_ty(), |x: ptr::P| Some(x) ); parse_macro_arg!( Pat, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None, None), + NonterminalKind::PatParam { inferred: false }, + |parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None), |x: ptr::P| Some(x) ); // `parse_item` returns `Option>`. parse_macro_arg!( Item, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No), + NonterminalKind::Item, + |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No), |x: Option>| x ); diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 6dc3eac44d43d..f0af401d3da4b 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -47,7 +47,7 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, _db: &Diagnostic) {} + fn emit_diagnostic(&mut self, _db: Diagnostic) {} } fn silent_emitter() -> Box { @@ -64,7 +64,7 @@ struct SilentOnIgnoredFilesEmitter { } impl SilentOnIgnoredFilesEmitter { - fn handle_non_ignoreable_error(&mut self, db: &Diagnostic) { + fn handle_non_ignoreable_error(&mut self, db: Diagnostic) { self.has_non_ignorable_parser_errors = true; self.can_reset.store(false, Ordering::Release); self.emitter.emit_diagnostic(db); @@ -86,7 +86,7 @@ impl Emitter for SilentOnIgnoredFilesEmitter { None } - fn emit_diagnostic(&mut self, db: &Diagnostic) { + fn emit_diagnostic(&mut self, db: Diagnostic) { if db.level() == DiagnosticLevel::Fatal { return self.handle_non_ignoreable_error(db); } @@ -365,7 +365,7 @@ mod tests { None } - fn emit_diagnostic(&mut self, _db: &Diagnostic) { + fn emit_diagnostic(&mut self, _db: Diagnostic) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } } @@ -424,7 +424,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span)); - emitter.emit_diagnostic(&fatal_diagnostic); + emitter.emit_diagnostic(fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } @@ -449,7 +449,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); - emitter.emit_diagnostic(&non_fatal_diagnostic); + emitter.emit_diagnostic(non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0); assert_eq!(can_reset_errors.load(Ordering::Acquire), true); } @@ -473,7 +473,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); - emitter.emit_diagnostic(&non_fatal_diagnostic); + emitter.emit_diagnostic(non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } @@ -512,9 +512,9 @@ mod tests { let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span)); let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span)); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None); - emitter.emit_diagnostic(&bar_diagnostic); - emitter.emit_diagnostic(&foo_diagnostic); - emitter.emit_diagnostic(&fatal_diagnostic); + emitter.emit_diagnostic(bar_diagnostic); + emitter.emit_diagnostic(foo_diagnostic); + emitter.emit_diagnostic(fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } diff --git a/src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs b/src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs new file mode 100644 index 0000000000000..3db2c26ab5aa7 --- /dev/null +++ b/src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs @@ -0,0 +1 @@ +m!(const N: usize = 0;); diff --git a/src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs b/src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs new file mode 100644 index 0000000000000..f7ebaf7827726 --- /dev/null +++ b/src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs @@ -0,0 +1,3 @@ +m!( + const N: usize = 0; +); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b03811e5efda5..acb70328ba210 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -132,6 +132,7 @@ const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ ("dissimilar", "Apache-2.0"), ("notify", "CC0-1.0"), ("pulldown-cmark-to-cmark", "Apache-2.0"), + ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 ("scip", "Apache-2.0"), ("snap", "BSD-3-Clause"), @@ -340,8 +341,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "termize", "thin-vec", "thiserror", - "thiserror-core", - "thiserror-core-impl", "thiserror-impl", "thorin-dwp", "thread_local", @@ -460,13 +459,17 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "mach", "memchr", "object", + "proc-macro2", + "quote", "regalloc2", "region", "rustc-hash", "slice-group-by", "smallvec", "stable_deref_trait", + "syn", "target-lexicon", + "unicode-ident", "version_check", "wasmtime-jit-icache-coherence", "winapi", @@ -481,6 +484,8 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", + "zerocopy", + "zerocopy-derive", // tidy-alphabetical-end ]; diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 094efa981d3e3..6fc65e56901a7 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -2,7 +2,7 @@ //! //! Overview of check: //! -//! 1. We create a list of error codes used by the compiler. Error codes are extracted from `compiler/rustc_error_codes/src/error_codes.rs`. +//! 1. We create a list of error codes used by the compiler. Error codes are extracted from `compiler/rustc_error_codes/src/lib.rs`. //! //! 2. We check that the error code has a long-form explanation in `compiler/rustc_error_codes/src/error_codes/`. //! - The explanation is expected to contain a `doctest` that fails with the correct error code. (`EXEMPT_FROM_DOCTEST` *currently* bypasses this check) @@ -22,7 +22,7 @@ use regex::Regex; use crate::walk::{filter_dirs, walk, walk_many}; -const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/error_codes.rs"; +const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/lib.rs"; const ERROR_DOCS_PATH: &str = "compiler/rustc_error_codes/src/error_codes/"; const ERROR_TESTS_PATH: &str = "tests/ui/error-codes/"; @@ -80,13 +80,14 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec) -> Vec) -> Vec, pub has_gate_test: bool, pub tracking_issue: Option, + pub file: PathBuf, + pub line: usize, } impl Feature { fn tracking_issue_display(&self) -> impl fmt::Display { @@ -184,23 +186,25 @@ pub fn check( .chain(lib_features.iter().map(|feat| (feat, "lib"))); for ((feature_name, feature), kind) in all_features_iter { let since = if let Some(since) = feature.since { since } else { continue }; + let file = feature.file.display(); + let line = feature.line; if since > version && since != Version::CurrentPlaceholder { tidy_error!( bad, - "The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}" + "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}" ); } if channel == "nightly" && since == version { tidy_error!( bad, - "The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}", + "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}", version::VERSION_PLACEHOLDER ); } if channel != "nightly" && since == Version::CurrentPlaceholder { tidy_error!( bad, - "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel", + "{file}:{line}: The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel", ); } } @@ -433,7 +437,14 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba ); } Entry::Vacant(e) => { - e.insert(Feature { level, since, has_gate_test: false, tracking_issue }); + e.insert(Feature { + level, + since, + has_gate_test: false, + tracking_issue, + file: path.to_path_buf(), + line: line_number, + }); } } } @@ -559,6 +570,8 @@ fn map_lib_features( since: None, has_gate_test: false, tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none), + file: file.to_path_buf(), + line: i + 1, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -588,7 +601,14 @@ fn map_lib_features( }; let tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none); - let feature = Feature { level, since, has_gate_test: false, tracking_issue }; + let feature = Feature { + level, + since, + has_gate_test: false, + tracking_issue, + file: file.to_path_buf(), + line: i + 1, + }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); } else { diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 95cf9f8cb13ad..e7b1ccf6a0299 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -8,9 +8,13 @@ use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; +// FIXME: GitHub's UI truncates file lists that exceed 1000 entries, so these +// should all be 1000 or lower. Limits significantly smaller than 1000 are also +// desirable, because large numbers of files are unwieldy in general. See issue +// #73494. const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1849; +const ISSUES_ENTRY_LIMIT: usize = 1819; const ROOT_ENTRY_LIMIT: usize = 870; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ @@ -24,9 +28,10 @@ const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint - "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs - "tests/ui/commandline-argfile-badutf8.args", // passing args via a file - "tests/ui/commandline-argfile.args", // passing args via a file + "tests/ui/codegen/mismatched-data-layout.json", // testing mismatched data layout w/ custom targets + "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs + "tests/ui/commandline-argfile-badutf8.args", // passing args via a file + "tests/ui/commandline-argfile.args", // passing args via a file "tests/ui/crate-loading/auxiliary/libfoo.rlib", // testing loading a manually created rlib "tests/ui/include-macros/data.bin", // testing including data with the include macros "tests/ui/include-macros/file.txt", // testing including data with the include macros diff --git a/src/version b/src/version index 79e15fd49370a..54227249d1ff9 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.77.0 +1.78.0 diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 72a35f38ecadb..41f5df0fba001 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -1,29 +1,5 @@ // assembly-output: emit-asm // ignore-tidy-linelength -// revisions: aarch64_apple_darwin -// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin -// [aarch64_apple_darwin] needs-llvm-components: aarch64 -// revisions: aarch64_apple_ios -// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios -// [aarch64_apple_ios] needs-llvm-components: aarch64 -// revisions: aarch64_apple_ios_macabi -// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi -// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 -// revisions: aarch64_apple_ios_sim -// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim -// [aarch64_apple_ios_sim] needs-llvm-components: aarch64 -// revisions: aarch64_apple_tvos -// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos -// [aarch64_apple_tvos] needs-llvm-components: aarch64 -// revisions: aarch64_apple_tvos_sim -// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim -// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 -// revisions: aarch64_apple_watchos -// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos -// [aarch64_apple_watchos] needs-llvm-components: aarch64 -// revisions: aarch64_apple_watchos_sim -// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim -// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 // revisions: aarch64_be_unknown_linux_gnu // [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu // [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 @@ -93,15 +69,6 @@ // revisions: aarch64_wrs_vxworks // [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks // [aarch64_wrs_vxworks] needs-llvm-components: aarch64 -// revisions: arm64_32_apple_watchos -// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos -// [arm64_32_apple_watchos] needs-llvm-components: aarch64 -// revisions: arm64e_apple_darwin -// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin -// [arm64e_apple_darwin] needs-llvm-components: aarch64 -// revisions: arm64e_apple_ios -// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios -// [arm64e_apple_ios] needs-llvm-components: aarch64 // revisions: arm_linux_androideabi // [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi // [arm_linux_androideabi] needs-llvm-components: arm @@ -201,18 +168,12 @@ // revisions: armv7a_none_eabihf // [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf // [armv7a_none_eabihf] needs-llvm-components: arm -// revisions: armv7k_apple_watchos -// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos -// [armv7k_apple_watchos] needs-llvm-components: arm // revisions: armv7r_none_eabi // [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi // [armv7r_none_eabi] needs-llvm-components: arm // revisions: armv7r_none_eabihf // [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf // [armv7r_none_eabihf] needs-llvm-components: arm -// revisions: armv7s_apple_ios -// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios -// [armv7s_apple_ios] needs-llvm-components: arm // FIXME: disabled since it fails on CI saying the csky component is missing /* revisions: csky_unknown_linux_gnuabiv2 @@ -228,9 +189,6 @@ // revisions: hexagon_unknown_none_elf // [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf // [hexagon_unknown_none_elf] needs-llvm-components: hexagon -// revisions: i386_apple_ios -// [i386_apple_ios] compile-flags: --target i386-apple-ios -// [i386_apple_ios] needs-llvm-components: x86 // revisions: i586_pc_nto_qnx700 // [i586_pc_nto_qnx700] compile-flags: --target i586-pc-nto-qnx700 // [i586_pc_nto_qnx700] needs-llvm-components: x86 @@ -243,9 +201,6 @@ // revisions: i586_unknown_netbsd // [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd // [i586_unknown_netbsd] needs-llvm-components: x86 -// revisions: i686_apple_darwin -// [i686_apple_darwin] compile-flags: --target i686-apple-darwin -// [i686_apple_darwin] needs-llvm-components: x86 // revisions: i686_linux_android // [i686_linux_android] compile-flags: --target i686-linux-android // [i686_linux_android] needs-llvm-components: x86 @@ -402,6 +357,9 @@ // revisions: riscv32i_unknown_none_elf // [riscv32i_unknown_none_elf] compile-flags: --target riscv32i-unknown-none-elf // [riscv32i_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32im_risc0_zkvm_elf +// [riscv32im_risc0_zkvm_elf] compile-flags: --target riscv32im-risc0-zkvm-elf +// [riscv32im_risc0_zkvm_elf] needs-llvm-components: riscv // revisions: riscv32im_unknown_none_elf // [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf // [riscv32im_unknown_none_elf] needs-llvm-components: riscv @@ -531,21 +489,6 @@ // revisions: wasm64_unknown_unknown // [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown // [wasm64_unknown_unknown] needs-llvm-components: webassembly -// revisions: x86_64_apple_darwin -// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin -// [x86_64_apple_darwin] needs-llvm-components: x86 -// revisions: x86_64_apple_ios -// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios -// [x86_64_apple_ios] needs-llvm-components: x86 -// revisions: x86_64_apple_ios_macabi -// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi -// [x86_64_apple_ios_macabi] needs-llvm-components: x86 -// revisions: x86_64_apple_tvos -// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos -// [x86_64_apple_tvos] needs-llvm-components: x86 -// revisions: x86_64_apple_watchos_sim -// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim -// [x86_64_apple_watchos_sim] needs-llvm-components: x86 // revisions: x86_64_fortanix_unknown_sgx // [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx // [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86 @@ -612,9 +555,6 @@ // revisions: x86_64_wrs_vxworks // [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks // [x86_64_wrs_vxworks] needs-llvm-components: x86 -// revisions: x86_64h_apple_darwin -// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin -// [x86_64h_apple_darwin] needs-llvm-components: x86 // Sanity-check that each target can produce assembly code. @@ -630,4 +570,4 @@ pub fn test() -> u8 { 42 } -// CHECK: .section +// CHECK: .text diff --git a/tests/assembly/targets/targets-macho.rs b/tests/assembly/targets/targets-macho.rs new file mode 100644 index 0000000000000..ead9ccfc8e74e --- /dev/null +++ b/tests/assembly/targets/targets-macho.rs @@ -0,0 +1,81 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: aarch64_apple_darwin +// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin +// [aarch64_apple_darwin] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios +// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios +// [aarch64_apple_ios] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_macabi +// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi +// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_sim +// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim +// [aarch64_apple_ios_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos +// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos +// [aarch64_apple_tvos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos_sim +// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim +// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos +// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos +// [aarch64_apple_watchos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos_sim +// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim +// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 +// revisions: arm64_32_apple_watchos +// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos +// [arm64_32_apple_watchos] needs-llvm-components: aarch64 +// revisions: arm64e_apple_darwin +// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin +// [arm64e_apple_darwin] needs-llvm-components: aarch64 +// revisions: arm64e_apple_ios +// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios +// [arm64e_apple_ios] needs-llvm-components: aarch64 +// revisions: armv7k_apple_watchos +// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos +// [armv7k_apple_watchos] needs-llvm-components: arm +// revisions: armv7s_apple_ios +// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios +// [armv7s_apple_ios] needs-llvm-components: arm +// revisions: i386_apple_ios +// [i386_apple_ios] compile-flags: --target i386-apple-ios +// [i386_apple_ios] needs-llvm-components: x86 +// revisions: i686_apple_darwin +// [i686_apple_darwin] compile-flags: --target i686-apple-darwin +// [i686_apple_darwin] needs-llvm-components: x86 +// revisions: x86_64_apple_darwin +// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin +// [x86_64_apple_darwin] needs-llvm-components: x86 +// revisions: x86_64_apple_ios +// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios +// [x86_64_apple_ios] needs-llvm-components: x86 +// revisions: x86_64_apple_ios_macabi +// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi +// [x86_64_apple_ios_macabi] needs-llvm-components: x86 +// revisions: x86_64_apple_tvos +// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos +// [x86_64_apple_tvos] needs-llvm-components: x86 +// revisions: x86_64_apple_watchos_sim +// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim +// [x86_64_apple_watchos_sim] needs-llvm-components: x86 +// revisions: x86_64h_apple_darwin +// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin +// [x86_64h_apple_darwin] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .section __TEXT,__text diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs index e78226d4083a4..41edab7f8793a 100644 --- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs @@ -26,7 +26,9 @@ fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] //~ MONO_ITEM fn as Trait>::foo //~ MONO_ITEM fn as Trait>::bar - let _ = &s1 as &Trait; + let r1 = &s1 as &Trait; + r1.foo(); + r1.bar(); let s1 = Struct { _a: 0u64 }; //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs index d953582cce9b6..c8a4552b11ac6 100644 --- a/tests/codegen-units/item-collection/trait-method-default-impl.rs +++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs @@ -57,5 +57,8 @@ fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn >::bar::<()> 0u32.bar(0i16, ()); + 0i8.foo(); + 0i32.foo(); + 0 } diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs index 34f52ce4e619e..f578b00f27668 100644 --- a/tests/codegen-units/item-collection/unsizing.rs +++ b/tests/codegen-units/item-collection/unsizing.rs @@ -75,5 +75,7 @@ fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn ::foo let _wrapper_sized = wrapper_sized as Wrapper; + false.foo(); + 0 } diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs index f88d695d87e1e..900eb687a45bb 100644 --- a/tests/codegen/alloc-optimisation.rs +++ b/tests/codegen/alloc-optimisation.rs @@ -1,5 +1,3 @@ -// -// no-system-llvm // compile-flags: -O #![crate_type = "lib"] diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs index 4d218e6a951b2..9846cc7f5c836 100644 --- a/tests/codegen/array-map.rs +++ b/tests/codegen/array-map.rs @@ -1,5 +1,4 @@ // compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3 -// no-system-llvm // only-x86_64 // ignore-debug (the extra assertions get in the way) @@ -10,7 +9,7 @@ pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] { // CHECK: load <8 x i32> // CHECK: shl <8 x i32> - // CHECK: or <8 x i32> + // CHECK: or{{( disjoint)?}} <8 x i32> // CHECK: store <8 x i32> x.map(|x| 2 * x + 1) } diff --git a/tests/codegen/cffi/ffi-returns-twice.rs b/tests/codegen/cffi/ffi-returns-twice.rs deleted file mode 100644 index 0fbe03f0bb6f1..0000000000000 --- a/tests/codegen/cffi/ffi-returns-twice.rs +++ /dev/null @@ -1,11 +0,0 @@ -// compile-flags: -C no-prepopulate-passes -#![crate_type = "lib"] -#![feature(ffi_returns_twice)] - -pub fn bar() { unsafe { foo() } } - -extern "C" { - // CHECK: declare{{( dso_local)?}} void @foo(){{.*}}[[ATTRS:#[0-9]+]] - // CHECK: attributes [[ATTRS]] = { {{.*}}returns_twice{{.*}} } - #[ffi_returns_twice] pub fn foo(); -} diff --git a/tests/codegen/dealloc-no-unwind.rs b/tests/codegen/dealloc-no-unwind.rs index 3812ef44ff2ac..c2656908f16d7 100644 --- a/tests/codegen/dealloc-no-unwind.rs +++ b/tests/codegen/dealloc-no-unwind.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O #![crate_type="lib"] diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index df1080bff2b1c..05643fab96a1d 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -Coverflow-checks=no -O // revisions: YES NO // [YES]compile-flags: -Zfewer-names=yes diff --git a/tests/codegen/i128-x86-align.rs b/tests/codegen/i128-x86-align.rs new file mode 100644 index 0000000000000..aaf5785dc9ff3 --- /dev/null +++ b/tests/codegen/i128-x86-align.rs @@ -0,0 +1,103 @@ +// only-x86_64 +// compile-flags: -O -C no-prepopulate-passes --crate-type=lib + +// On LLVM 17 and earlier LLVM's own data layout specifies that i128 has 8 byte alignment, +// while rustc wants it to have 16 byte alignment. This test checks that we handle this +// correctly. + +// CHECK: %ScalarPair = type { i32, [3 x i32], i128 } +// CHECK: %Struct = type { i32, i32, [2 x i32], i128 } + +#![feature(core_intrinsics)] + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ScalarPair { + a: i32, + b: i128, +} + +#[no_mangle] +pub fn load(x: &ScalarPair) -> ScalarPair { + // CHECK-LABEL: @load( + // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK: [[A:%.*]] = load i32, ptr %x, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 + // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16 + // CHECK-NEXT: [[IV1:%.*]] = insertvalue { i32, i128 } poison, i32 [[A]], 0 + // CHECK-NEXT: [[IV2:%.*]] = insertvalue { i32, i128 } [[IV1]], i128 [[B]], 1 + // CHECK-NEXT: ret { i32, i128 } [[IV2]] + *x +} + +#[no_mangle] +pub fn store(x: &mut ScalarPair) { + // CHECK-LABEL: @store( + // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK: store i32 1, ptr %x, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 + // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 + *x = ScalarPair { a: 1, b: 2 }; +} + +#[no_mangle] +pub fn alloca() { + // CHECK-LABEL: @alloca( + // CHECK: [[X:%.*]] = alloca %ScalarPair, align 16 + // CHECK: store i32 1, ptr %x, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 + // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 + let mut x = ScalarPair { a: 1, b: 2 }; + store(&mut x); +} + +#[no_mangle] +pub fn load_volatile(x: &ScalarPair) -> ScalarPair { + // CHECK-LABEL: @load_volatile( + // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK: [[TMP:%.*]] = alloca %ScalarPair, align 16 + // CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16 + // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr [[TMP]], align 16 + // CHECK-NEXT: [[A:%.*]] = load i32, ptr [[TMP]], align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16 + // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16 + unsafe { std::intrinsics::volatile_load(x) } +} + +#[no_mangle] +pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit, i128) { + // CHECK-LABEL: define { i128, i128 } @transmute(i32 noundef %x.0, i128 noundef %x.1) + // CHECK: [[TMP:%.*]] = alloca { i128, i128 }, align 16 + // CHECK-NEXT: store i32 %x.0, ptr [[TMP]], align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16 + // CHECK-NEXT: store i128 %x.1, ptr [[GEP]], align 16 + // CHECK-NEXT: [[LOAD1:%.*]] = load i128, ptr %_0, align 16 + // CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16 + // CHECK-NEXT: [[LOAD2:%.*]] = load i128, ptr [[GEP2]], align 16 + // CHECK-NEXT: [[IV1:%.*]] = insertvalue { i128, i128 } poison, i128 [[LOAD1]], 0 + // CHECK-NEXT: [[IV2:%.*]] = insertvalue { i128, i128 } [[IV1]], i128 [[LOAD2]], 1 + // CHECK-NEXT: ret { i128, i128 } [[IV2]] + unsafe { std::mem::transmute(x) } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Struct { + a: i32, + b: i32, + c: i128, +} + +#[no_mangle] +pub fn store_struct(x: &mut Struct) { + // CHECK-LABEL: @store_struct( + // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK: [[TMP:%.*]] = alloca %Struct, align 16 + // CHECK: store i32 1, ptr [[TMP]], align 16 + // CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds %Struct, ptr [[TMP]], i32 0, i32 1 + // CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4 + // CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds %Struct, ptr [[TMP]], i32 0, i32 3 + // CHECK-NEXT: store i128 3, ptr [[GEP2]], align 16 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %x, ptr align 16 [[TMP]], i64 32, i1 false) + *x = Struct { a: 1, b: 2, c: 3 }; +} diff --git a/tests/codegen/infallible-unwrap-in-opt-z.rs b/tests/codegen/infallible-unwrap-in-opt-z.rs index 5c57b41532fbb..e8ab77f8d20de 100644 --- a/tests/codegen/infallible-unwrap-in-opt-z.rs +++ b/tests/codegen/infallible-unwrap-in-opt-z.rs @@ -21,6 +21,6 @@ pub fn read_up_to_8(buf: &[u8]) -> u64 { // CHECK-LABEL: @checking_unwrap_expectation( #[no_mangle] pub fn checking_unwrap_expectation(buf: &[u8]) -> &[u8; 4] { - // CHECK: call void @_ZN4core6result13unwrap_failed17h + // CHECK: call void @{{.*core6result13unwrap_failed}} buf.try_into().unwrap() } diff --git a/tests/codegen/integer-overflow.rs b/tests/codegen/integer-overflow.rs index 183de56db9685..b5c351b5e35de 100644 --- a/tests/codegen/integer-overflow.rs +++ b/tests/codegen/integer-overflow.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O -C overflow-checks=on #![crate_type = "lib"] diff --git a/tests/codegen/is_val_statically_known.rs b/tests/codegen/is_val_statically_known.rs new file mode 100644 index 0000000000000..8f084f6c54bdc --- /dev/null +++ b/tests/codegen/is_val_statically_known.rs @@ -0,0 +1,86 @@ +// compile-flags: --crate-type=lib -Zmerge-functions=disabled -O + +#![feature(core_intrinsics)] + +use std::intrinsics::is_val_statically_known; + +pub struct A(u32); +pub enum B { + Ye(u32), +} + +#[inline] +pub fn _u32(a: u32) -> i32 { + if unsafe { is_val_statically_known(a) } { 1 } else { 0 } +} + +// CHECK-LABEL: @_u32_true( +#[no_mangle] +pub fn _u32_true() -> i32 { + // CHECK: ret i32 1 + _u32(1) +} + +// CHECK-LABEL: @_u32_false( +#[no_mangle] +pub fn _u32_false(a: u32) -> i32 { + // CHECK: ret i32 0 + _u32(a) +} + +#[inline] +pub fn _bool(b: bool) -> i32 { + if unsafe { is_val_statically_known(b) } { 3 } else { 2 } +} + +// CHECK-LABEL: @_bool_true( +#[no_mangle] +pub fn _bool_true() -> i32 { + // CHECK: ret i32 3 + _bool(true) +} + +// CHECK-LABEL: @_bool_false( +#[no_mangle] +pub fn _bool_false(b: bool) -> i32 { + // CHECK: ret i32 2 + _bool(b) +} + +#[inline] +pub fn _iref(a: &u8) -> i32 { + if unsafe { is_val_statically_known(a) } { 5 } else { 4 } +} + +// CHECK-LABEL: @_iref_borrow( +#[no_mangle] +pub fn _iref_borrow() -> i32 { + // CHECK: ret i32 4 + _iref(&0) +} + +// CHECK-LABEL: @_iref_arg( +#[no_mangle] +pub fn _iref_arg(a: &u8) -> i32 { + // CHECK: ret i32 4 + _iref(a) +} + +#[inline] +pub fn _slice_ref(a: &[u8]) -> i32 { + if unsafe { is_val_statically_known(a) } { 7 } else { 6 } +} + +// CHECK-LABEL: @_slice_ref_borrow( +#[no_mangle] +pub fn _slice_ref_borrow() -> i32 { + // CHECK: ret i32 6 + _slice_ref(&[0;3]) +} + +// CHECK-LABEL: @_slice_ref_arg( +#[no_mangle] +pub fn _slice_ref_arg(a: &[u8]) -> i32 { + // CHECK: ret i32 6 + _slice_ref(a) +} diff --git a/tests/codegen/issues/issue-116878.rs b/tests/codegen/issues/issue-116878.rs index d5f679459f731..5864f53232493 100644 --- a/tests/codegen/issues/issue-116878.rs +++ b/tests/codegen/issues/issue-116878.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs index 1a3923f1bb1ab..44aa9766d3c0d 100644 --- a/tests/codegen/issues/issue-44056-macos-tls-align.rs +++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs @@ -1,6 +1,5 @@ // // only-macos -// no-system-llvm // compile-flags: -O #![crate_type = "rlib"] diff --git a/tests/codegen/issues/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs index a3aca3a2912a6..655de45fd51e9 100644 --- a/tests/codegen/issues/issue-69101-bounds-check.rs +++ b/tests/codegen/issues/issue-69101-bounds-check.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/match-optimizes-away.rs b/tests/codegen/match-optimizes-away.rs index 8f66c518ccf48..400606b42d550 100644 --- a/tests/codegen/match-optimizes-away.rs +++ b/tests/codegen/match-optimizes-away.rs @@ -1,5 +1,4 @@ // -// no-system-llvm // compile-flags: -O #![crate_type="lib"] diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs index 73d1db6df277b..94152ed11ba13 100644 --- a/tests/codegen/ptr-read-metadata.rs +++ b/tests/codegen/ptr-read-metadata.rs @@ -1,5 +1,4 @@ // compile-flags: -O -Z merge-functions=disabled -// no-system-llvm // ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/slice-as_chunks.rs b/tests/codegen/slice-as_chunks.rs index efac9f3d68da8..e832f90d07a52 100644 --- a/tests/codegen/slice-as_chunks.rs +++ b/tests/codegen/slice-as_chunks.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O // only-64bit (because the LLVM type of i64 for usize shows up) // ignore-debug: the debug assertions get in the way diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs index c7515ce35a35f..77febf5170da7 100644 --- a/tests/codegen/slice-iter-len-eq-zero.rs +++ b/tests/codegen/slice-iter-len-eq-zero.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O // ignore-debug: the debug assertions add extra comparisons #![crate_type = "lib"] diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs index 1e691cc34c995..93c8828ccd336 100644 --- a/tests/codegen/slice-iter-nonnull.rs +++ b/tests/codegen/slice-iter-nonnull.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O // ignore-debug (these add extra checks that make it hard to verify) #![crate_type = "lib"] diff --git a/tests/codegen/slice-position-bounds-check.rs b/tests/codegen/slice-position-bounds-check.rs index b494f42b2965d..57904e5e49999 100644 --- a/tests/codegen/slice-position-bounds-check.rs +++ b/tests/codegen/slice-position-bounds-check.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -O -C panic=abort #![crate_type = "lib"] diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs index 27bc00bc3abb8..2c67517447988 100644 --- a/tests/codegen/swap-small-types.rs +++ b/tests/codegen/swap-small-types.rs @@ -26,12 +26,15 @@ pub fn swap_rgb48_manually(x: &mut RGB48, y: &mut RGB48) { // CHECK-LABEL: @swap_rgb48 #[no_mangle] pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { - // FIXME: See #115212 for why this has an alloca again + // CHECK-NOT: alloca - // CHECK: alloca [3 x i16], align 2 - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) + // Whether `i8` is the best for this is unclear, but + // might as well record what's actually happening right now. + + // CHECK: load i8 + // CHECK: load i8 + // CHECK: store i8 + // CHECK: store i8 swap(x, y) } @@ -41,10 +44,39 @@ type RGBA64 = [u16; 4]; #[no_mangle] pub fn swap_rgba64(x: &mut RGBA64, y: &mut RGBA64) { // CHECK-NOT: alloca - // CHECK-DAG: %[[XVAL:.+]] = load <4 x i16>, ptr %x, align 2 - // CHECK-DAG: %[[YVAL:.+]] = load <4 x i16>, ptr %y, align 2 - // CHECK-DAG: store <4 x i16> %[[YVAL]], ptr %x, align 2 - // CHECK-DAG: store <4 x i16> %[[XVAL]], ptr %y, align 2 + // CHECK-DAG: %[[XVAL:.+]] = load i64, ptr %x, align 2 + // CHECK-DAG: %[[YVAL:.+]] = load i64, ptr %y, align 2 + // CHECK-DAG: store i64 %[[YVAL]], ptr %x, align 2 + // CHECK-DAG: store i64 %[[XVAL]], ptr %y, align 2 + swap(x, y) +} + +// CHECK-LABEL: @swap_vecs +#[no_mangle] +pub fn swap_vecs(x: &mut Vec, y: &mut Vec) { + // CHECK-NOT: alloca + // There are plenty more loads and stores than just these, + // but at least one sure better be 64-bit (for size or capacity). + // CHECK: load i64 + // CHECK: load i64 + // CHECK: store i64 + // CHECK: store i64 + // CHECK: ret void + swap(x, y) +} + +// CHECK-LABEL: @swap_slices +#[no_mangle] +pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) { + // CHECK-NOT: alloca + // CHECK: load ptr + // CHECK: load i64 + // CHECK: load ptr + // CHECK: load i64 + // CHECK: store ptr + // CHECK: store i64 + // CHECK: store ptr + // CHECK: store i64 swap(x, y) } @@ -55,9 +87,9 @@ type RGB24 = [u8; 3]; // CHECK-LABEL: @swap_rgb24_slices #[no_mangle] pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) { -// CHECK-NOT: alloca -// CHECK: load <{{[0-9]+}} x i8> -// CHECK: store <{{[0-9]+}} x i8> + // CHECK-NOT: alloca + // CHECK: load <{{[0-9]+}} x i8> + // CHECK: store <{{[0-9]+}} x i8> if x.len() == y.len() { x.swap_with_slice(y); } @@ -69,9 +101,9 @@ type RGBA32 = [u8; 4]; // CHECK-LABEL: @swap_rgba32_slices #[no_mangle] pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) { -// CHECK-NOT: alloca -// CHECK: load <{{[0-9]+}} x i32> -// CHECK: store <{{[0-9]+}} x i32> + // CHECK-NOT: alloca + // CHECK: load <{{[0-9]+}} x i32> + // CHECK: store <{{[0-9]+}} x i32> if x.len() == y.len() { x.swap_with_slice(y); } @@ -84,10 +116,24 @@ const _: () = assert!(!std::mem::size_of::().is_power_of_two()); // CHECK-LABEL: @swap_string_slices #[no_mangle] pub fn swap_string_slices(x: &mut [String], y: &mut [String]) { -// CHECK-NOT: alloca -// CHECK: load <{{[0-9]+}} x i64> -// CHECK: store <{{[0-9]+}} x i64> + // CHECK-NOT: alloca + // CHECK: load <{{[0-9]+}} x i64> + // CHECK: store <{{[0-9]+}} x i64> if x.len() == y.len() { x.swap_with_slice(y); } } + +#[repr(C, packed)] +pub struct Packed { + pub first: bool, + pub second: usize, +} + +// CHECK-LABEL: @swap_packed_structs +#[no_mangle] +pub fn swap_packed_structs(x: &mut Packed, y: &mut Packed) { + // CHECK-NOT: alloca + // CHECK: ret void + swap(x, y) +} diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs index 73348ddd063dc..3a0d6c3091927 100644 --- a/tests/codegen/vec-iter-collect-len.rs +++ b/tests/codegen/vec-iter-collect-len.rs @@ -1,5 +1,4 @@ // ignore-debug: the debug assertions get in the way -// no-system-llvm // compile-flags: -O #![crate_type="lib"] diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs index 6f477a796b65d..3be342dabeb62 100644 --- a/tests/codegen/vec-optimizes-away.rs +++ b/tests/codegen/vec-optimizes-away.rs @@ -1,5 +1,4 @@ // ignore-debug: the debug assertions get in the way -// no-system-llvm // compile-flags: -O #![crate_type = "lib"] diff --git a/tests/codegen/vec-reserve-extend.rs b/tests/codegen/vec-reserve-extend.rs index d95220104c229..395373ff4f10a 100644 --- a/tests/codegen/vec-reserve-extend.rs +++ b/tests/codegen/vec-reserve-extend.rs @@ -1,4 +1,6 @@ // compile-flags: -O +// ignore-debug +// (with debug assertions turned on, `assert_unchecked` generates a real assertion) #![crate_type = "lib"] diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs index 8bc7b68a816ec..d9293f2b75de5 100644 --- a/tests/codegen/vec_pop_push_noop.rs +++ b/tests/codegen/vec_pop_push_noop.rs @@ -1,4 +1,6 @@ // compile-flags: -O +// ignore-debug +// (with debug assertions turned on, `assert_unchecked` generates a real assertion) #![crate_type = "lib"] diff --git a/tests/coverage-run-rustdoc/doctest.coverage b/tests/coverage-run-rustdoc/doctest.coverage index 5797784f411cc..5125dc075ee2c 100644 --- a/tests/coverage-run-rustdoc/doctest.coverage +++ b/tests/coverage-run-rustdoc/doctest.coverage @@ -34,8 +34,7 @@ $DIR/doctest.rs: LL| |//! LL| |//! doctest returning a result: LL| 1|//! ``` - LL| 2|//! #[derive(Debug, PartialEq)] - ^1 + LL| 1|//! #[derive(Debug, PartialEq)] LL| 1|//! struct SomeError { LL| 1|//! msg: String, LL| 1|//! } @@ -63,7 +62,7 @@ $DIR/doctest.rs: LL| 1|//! println!("called some_func()"); LL| 1|//! } LL| |//! - LL| 0|//! #[derive(Debug)] + LL| |//! #[derive(Debug)] LL| |//! struct SomeError; LL| |//! LL| |//! extern crate doctest_crate; diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 45d3795eff8f3..1c36f2871dd18 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,5 +1,5 @@ Function name: abort::main -Raw bytes (105): 0x[01, 01, 12, 01, 47, 05, 09, 03, 0d, 42, 11, 03, 0d, 11, 3e, 42, 11, 03, 0d, 3b, 15, 11, 3e, 42, 11, 03, 0d, 15, 36, 3b, 15, 11, 3e, 42, 11, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 42, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 3e, 02, 0a, 00, 0b, 3b, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 36, 00, 31, 00, 32, 33, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 47, 01, 09, 00, 17, 0d, 02, 05, 01, 02] +Raw bytes (105): 0x[01, 01, 12, 01, 47, 05, 09, 03, 0d, 42, 11, 03, 0d, 11, 3e, 42, 11, 03, 0d, 3b, 15, 11, 3e, 42, 11, 03, 0d, 15, 36, 3b, 15, 11, 3e, 42, 11, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 42, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 3e, 02, 0a, 00, 0b, 3b, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 36, 00, 31, 00, 32, 33, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 47, 01, 09, 00, 17, 0d, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 18 @@ -22,7 +22,7 @@ Number of expressions: 18 - expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 17 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) +- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 27) - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24) = (c0 + (c1 + c2)) - Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25) diff --git a/tests/coverage/abort.coverage b/tests/coverage/abort.coverage index ceef638678070..b658a65625912 100644 --- a/tests/coverage/abort.coverage +++ b/tests/coverage/abort.coverage @@ -10,6 +10,7 @@ LL| 12| } LL| 12|} LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() -> Result<(), u8> { LL| 1| let mut countdown = 10; LL| 11| while countdown > 0 { diff --git a/tests/coverage/abort.rs b/tests/coverage/abort.rs index 98264bdc1afe5..649e8e52a490e 100644 --- a/tests/coverage/abort.rs +++ b/tests/coverage/abort.rs @@ -10,6 +10,7 @@ extern "C" fn might_abort(should_abort: bool) { } } +#[rustfmt::skip] fn main() -> Result<(), u8> { let mut countdown = 10; while countdown > 0 { diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 6bdcca40ed66f..e06d1676358fb 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -1,20 +1,20 @@ Function name: async::c -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 01, 00, 19] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 25) +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 25) Function name: async::c::{closure#0} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 07, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 09, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 7, 25) to (start + 1, 14) +- Code(Counter(0)) at (prev + 9, 25) to (start + 1, 14) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) @@ -22,84 +22,84 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: async::d -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 14] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 20) Function name: async::d::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 14, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 14, 00, 19] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 15, 20) to (start + 0, 25) +- Code(Counter(0)) at (prev + 17, 20) to (start + 0, 25) Function name: async::e (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 13, 01, 00, 14] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 1) to (start + 0, 20) +- Code(Zero) at (prev + 19, 1) to (start + 0, 20) Function name: async::e::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 14, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 13, 14, 00, 19] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 20) to (start + 0, 25) +- Code(Zero) at (prev + 19, 20) to (start + 0, 25) Function name: async::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 14] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 20) Function name: async::f::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 14, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 14, 00, 19] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 20) to (start + 0, 25) +- Code(Counter(0)) at (prev + 21, 20) to (start + 0, 25) Function name: async::foo (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1e] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 01, 00, 1e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 0, 30) +- Code(Zero) at (prev + 23, 1) to (start + 0, 30) Function name: async::foo::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 1e, 00, 2d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 1e, 00, 2d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 30) to (start + 0, 45) +- Code(Zero) at (prev + 23, 30) to (start + 0, 45) Function name: async::g -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 19, 01, 00, 17] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 23) Function name: async::g::{closure#0} (unused) -Raw bytes (69): 0x[01, 01, 00, 0d, 00, 17, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 00, 19, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 13 -- Code(Zero) at (prev + 23, 23) to (start + 1, 12) +- Code(Zero) at (prev + 25, 23) to (start + 1, 12) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 17) - Code(Zero) at (prev + 0, 18) to (start + 0, 23) @@ -114,20 +114,20 @@ Number of file 0 mappings: 13 - Code(Zero) at (prev + 2, 1) to (start + 0, 2) Function name: async::h -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 00, 16] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 00, 16] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 22) Function name: async::h::{closure#0} (unused) -Raw bytes (44): 0x[01, 01, 00, 08, 00, 1f, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 13, 00, 00, 14, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 00, 21, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 13, 00, 00, 14, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 8 -- Code(Zero) at (prev + 31, 22) to (start + 3, 12) +- Code(Zero) at (prev + 33, 22) to (start + 3, 12) - Code(Zero) at (prev + 4, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 19) - Code(Zero) at (prev + 0, 20) to (start + 0, 25) @@ -137,22 +137,22 @@ Number of file 0 mappings: 8 - Code(Zero) at (prev + 2, 1) to (start + 0, 2) Function name: async::i -Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 01, 00, 13] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2a, 01, 00, 13] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 40, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 42, 1) to (start + 0, 19) Function name: async::i::{closure#0} -Raw bytes (78): 0x[01, 01, 02, 07, 21, 19, 1d, 0e, 01, 28, 13, 04, 0c, 0d, 05, 09, 00, 0a, 01, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 0d, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 1d, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 03, 02, 01, 00, 02] +Raw bytes (78): 0x[01, 01, 02, 07, 21, 19, 1d, 0e, 01, 2a, 13, 04, 0c, 0d, 05, 09, 00, 0a, 01, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 0d, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 1d, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 03, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(8) - expression 1 operands: lhs = Counter(6), rhs = Counter(7) Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 40, 19) to (start + 4, 12) +- Code(Counter(0)) at (prev + 42, 19) to (start + 4, 12) - Code(Counter(3)) at (prev + 5, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24) @@ -169,14 +169,14 @@ Number of file 0 mappings: 14 = ((c6 + c7) + c8) Function name: async::j -Raw bytes (53): 0x[01, 01, 02, 07, 0d, 05, 09, 09, 01, 33, 01, 13, 0c, 05, 14, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02] +Raw bytes (53): 0x[01, 01, 02, 07, 0d, 05, 09, 09, 01, 35, 01, 13, 0c, 05, 14, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 51, 1) to (start + 19, 12) +- Code(Counter(0)) at (prev + 53, 1) to (start + 19, 12) - Code(Counter(1)) at (prev + 20, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 27) - Code(Counter(1)) at (prev + 0, 31) to (start + 0, 39) @@ -188,14 +188,14 @@ Number of file 0 mappings: 9 = ((c1 + c2) + c3) Function name: async::j::c -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 35, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 53, 5) to (start + 1, 18) +- Code(Counter(0)) at (prev + 55, 5) to (start + 1, 18) - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14) - Code(Expression(0, Sub)) at (prev + 10, 13) to (start + 0, 14) = (c0 - c1) @@ -203,35 +203,35 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: async::j::d -Raw bytes (9): 0x[01, 01, 00, 01, 01, 44, 05, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 46, 05, 00, 17] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 68, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 70, 5) to (start + 0, 23) Function name: async::j::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 45, 05, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 47, 05, 00, 17] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 69, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 71, 5) to (start + 0, 23) Function name: async::k (unused) -Raw bytes (29): 0x[01, 01, 00, 05, 00, 4d, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 4f, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 5 -- Code(Zero) at (prev + 77, 1) to (start + 1, 12) +- Code(Zero) at (prev + 79, 1) to (start + 1, 12) - Code(Zero) at (prev + 2, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) Function name: async::l -Raw bytes (37): 0x[01, 01, 04, 01, 07, 05, 09, 0f, 02, 09, 05, 05, 01, 55, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] +Raw bytes (37): 0x[01, 01, 04, 01, 07, 05, 09, 0f, 02, 09, 05, 05, 01, 57, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -240,7 +240,7 @@ Number of expressions: 4 - expression 2 operands: lhs = Expression(3, Add), rhs = Expression(0, Sub) - expression 3 operands: lhs = Counter(2), rhs = Counter(1) Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 85, 1) to (start + 1, 12) +- Code(Counter(0)) at (prev + 87, 1) to (start + 1, 12) - Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16) = (c0 - (c1 + c2)) - Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16) @@ -249,26 +249,26 @@ Number of file 0 mappings: 5 = ((c2 + c1) + (c0 - (c1 + c2))) Function name: async::m -Raw bytes (9): 0x[01, 01, 00, 01, 01, 5d, 01, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 5f, 01, 00, 19] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 93, 1) to (start + 0, 25) +- Code(Counter(0)) at (prev + 95, 1) to (start + 0, 25) Function name: async::m::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 5d, 19, 00, 22] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 5f, 19, 00, 22] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 93, 25) to (start + 0, 34) +- Code(Zero) at (prev + 95, 25) to (start + 0, 34) Function name: async::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 5f, 01, 08, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 61, 01, 08, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 95, 1) to (start + 8, 2) +- Code(Counter(0)) at (prev + 97, 1) to (start + 8, 2) diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage index 015e03d5165fa..b4f6fc3a8a214 100644 --- a/tests/coverage/async.coverage +++ b/tests/coverage/async.coverage @@ -1,6 +1,8 @@ LL| |#![feature(coverage_attribute)] + LL| |#![feature(custom_inner_attributes)] // for #![rustfmt::skip] LL| |#![feature(noop_waker)] LL| |#![allow(unused_assignments, dead_code)] + LL| |#![rustfmt::skip] LL| |// edition: 2018 LL| |// compile-flags: -Copt-level=1 LL| | @@ -117,8 +119,7 @@ LL| | #[coverage(off)] LL| | pub fn block_on(mut future: F) -> F::Output { LL| | let mut future = pin!(future); - LL| | let waker = Waker::noop(); - LL| | let mut context = Context::from_waker(&waker); + LL| | let mut context = Context::from_waker(Waker::noop()); LL| | LL| | loop { LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/async.rs b/tests/coverage/async.rs index abc9e5f7f6467..6047cb79fb1bd 100644 --- a/tests/coverage/async.rs +++ b/tests/coverage/async.rs @@ -1,6 +1,8 @@ #![feature(coverage_attribute)] +#![feature(custom_inner_attributes)] // for #![rustfmt::skip] #![feature(noop_waker)] #![allow(unused_assignments, dead_code)] +#![rustfmt::skip] // edition: 2018 // compile-flags: -Copt-level=1 @@ -110,8 +112,7 @@ mod executor { #[coverage(off)] pub fn block_on(mut future: F) -> F::Output { let mut future = pin!(future); - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); loop { if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/async2.coverage b/tests/coverage/async2.coverage index acd83de94934d..a69eefe72cbcf 100644 --- a/tests/coverage/async2.coverage +++ b/tests/coverage/async2.coverage @@ -41,8 +41,7 @@ LL| | #[coverage(off)] LL| | pub fn block_on(mut future: F) -> F::Output { LL| | let mut future = pin!(future); - LL| | let waker = Waker::noop(); - LL| | let mut context = Context::from_waker(&waker); + LL| | let mut context = Context::from_waker(Waker::noop()); LL| | LL| | loop { LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/async2.rs b/tests/coverage/async2.rs index 393573f7dc955..ae83f0103e64d 100644 --- a/tests/coverage/async2.rs +++ b/tests/coverage/async2.rs @@ -39,8 +39,7 @@ mod executor { #[coverage(off)] pub fn block_on(mut future: F) -> F::Output { let mut future = pin!(future); - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); loop { if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/async_block.coverage b/tests/coverage/async_block.coverage index 297397ca26c8d..0e24b80124f48 100644 --- a/tests/coverage/async_block.coverage +++ b/tests/coverage/async_block.coverage @@ -24,8 +24,7 @@ LL| | #[coverage(off)] LL| | pub fn block_on(mut future: F) -> F::Output { LL| | let mut future = pin!(future); - LL| | let waker = Waker::noop(); - LL| | let mut context = Context::from_waker(&waker); + LL| | let mut context = Context::from_waker(Waker::noop()); LL| | LL| | loop { LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/async_block.rs b/tests/coverage/async_block.rs index 9d8647bf1f208..f94bcfe319371 100644 --- a/tests/coverage/async_block.rs +++ b/tests/coverage/async_block.rs @@ -23,8 +23,7 @@ mod executor { #[coverage(off)] pub fn block_on(mut future: F) -> F::Output { let mut future = pin!(future); - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); loop { if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index 0b8081acfa6d8..7eff7f5f02f3c 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -1,97 +1,81 @@ -Function name: ::eq -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 11, 00, 1a] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 17) to (start + 0, 26) - -Function name: ::fmt -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 0a, 00, 0f] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 10) to (start + 0, 15) - Function name: bad_counter_ids::eq_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 23, 01, 02, 1f, 00, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 1f, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 35, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 31) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) Function name: bad_counter_ids::eq_bad_message -Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 28, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 29, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 40, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15) - Code(Expression(0, Sub)) at (prev + 2, 32) to (start + 0, 43) = (c0 - Zero) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Function name: bad_counter_ids::eq_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 01, 02, 1f, 05, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 1f, 05, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 31) - Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) Function name: bad_counter_ids::eq_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 14, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) - Code(Zero) at (prev + 2, 32) to (start + 0, 43) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Function name: bad_counter_ids::ne_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 2d, 01, 02, 1f, 00, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 1f, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 45, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 31) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) Function name: bad_counter_ids::ne_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 32, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 50, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) - Code(Counter(1)) at (prev + 2, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Function name: bad_counter_ids::ne_good -Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 19, 01, 02, 1f, 02, 03, 01, 00, 02] +Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 1a, 01, 02, 1f, 02, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 25, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 31) - Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - Zero) Function name: bad_counter_ids::ne_good_message -Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1e, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15) - Code(Zero) at (prev + 2, 32) to (start + 0, 43) - Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c0 - Zero) diff --git a/tests/coverage/bad_counter_ids.coverage b/tests/coverage/bad_counter_ids.coverage index d69ebf160ea64..39e6cae11ddac 100644 --- a/tests/coverage/bad_counter_ids.coverage +++ b/tests/coverage/bad_counter_ids.coverage @@ -1,5 +1,6 @@ LL| |#![feature(coverage_attribute)] - LL| |// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3 + LL| |// edition: 2021 + LL| |// compile-flags: -Copt-level=0 -Zmir-opt-level=3 LL| | LL| |// Regression test for . LL| |// @@ -9,7 +10,7 @@ LL| |// a too-large counter ID and silently discard the entire function from its LL| |// coverage reports. LL| | - LL| 8|#[derive(Debug, PartialEq, Eq)] + LL| |#[derive(Debug, PartialEq, Eq)] LL| |struct Foo(u32); LL| | LL| 1|fn eq_good() { diff --git a/tests/coverage/bad_counter_ids.rs b/tests/coverage/bad_counter_ids.rs index ef5460102b70c..e22b96468abd3 100644 --- a/tests/coverage/bad_counter_ids.rs +++ b/tests/coverage/bad_counter_ids.rs @@ -1,5 +1,6 @@ #![feature(coverage_attribute)] -// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3 +// edition: 2021 +// compile-flags: -Copt-level=0 -Zmir-opt-level=3 // Regression test for . // diff --git a/tests/coverage/bench.cov-map b/tests/coverage/bench.cov-map new file mode 100644 index 0000000000000..aa702a4868185 --- /dev/null +++ b/tests/coverage/bench.cov-map @@ -0,0 +1,8 @@ +Function name: bench::my_bench +Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 00, 27] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39) + diff --git a/tests/coverage/bench.coverage b/tests/coverage/bench.coverage new file mode 100644 index 0000000000000..64945dc641502 --- /dev/null +++ b/tests/coverage/bench.coverage @@ -0,0 +1,9 @@ + LL| |#![feature(test)] + LL| |// edition: 2021 + LL| |// compile-flags: --test + LL| | + LL| |extern crate test; + LL| | + LL| |#[bench] + LL| 1|fn my_bench(_b: &mut test::Bencher) {} + diff --git a/tests/coverage/bench.rs b/tests/coverage/bench.rs new file mode 100644 index 0000000000000..2dcd7355b2f79 --- /dev/null +++ b/tests/coverage/bench.rs @@ -0,0 +1,8 @@ +#![feature(test)] +// edition: 2021 +// compile-flags: --test + +extern crate test; + +#[bench] +fn my_bench(_b: &mut test::Bencher) {} diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index c5ac17600cd2a..921ca6cf4e1ad 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,12 +1,12 @@ Function name: closure::main -Raw bytes (128): 0x[01, 01, 02, 01, 05, 05, 02, 18, 01, 08, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 07, 01, 05, 03, 02] +Raw bytes (128): 0x[01, 01, 02, 01, 05, 05, 02, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 07, 01, 05, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 24 -- Code(Counter(0)) at (prev + 8, 1) to (start + 15, 13) +- Code(Counter(0)) at (prev + 9, 1) to (start + 15, 13) - Code(Counter(0)) at (prev + 22, 14) to (start + 6, 10) - Code(Counter(0)) at (prev + 16, 5) to (start + 19, 13) - Code(Counter(0)) at (prev + 26, 14) to (start + 6, 10) @@ -34,14 +34,14 @@ Number of file 0 mappings: 24 = (c1 + (c0 - c1)) Function name: closure::main::{closure#0} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 27, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 39, 5) to (start + 2, 20) +- Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) = (c0 - c1) @@ -49,46 +49,46 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#10} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 9a, 01, 07, 00, 21] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 154, 7) to (start + 0, 33) +- Code(Zero) at (prev + 155, 7) to (start + 0, 33) Function name: closure::main::{closure#11} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 9e, 01, 07, 00, 21] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 9f, 01, 07, 00, 21] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 158, 7) to (start + 0, 33) +- Code(Zero) at (prev + 159, 7) to (start + 0, 33) Function name: closure::main::{closure#12} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, a6, 01, 01, 00, 17] +Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 01, 00, 17] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 166, 1) to (start + 0, 23) +- Code(Zero) at (prev + 167, 1) to (start + 0, 23) Function name: closure::main::{closure#13} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, ab, 01, 0d, 02, 0e] +Raw bytes (10): 0x[01, 01, 00, 01, 00, ac, 01, 0d, 02, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 171, 13) to (start + 2, 14) +- Code(Zero) at (prev + 172, 13) to (start + 2, 14) Function name: closure::main::{closure#14} -Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, b2, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 178, 13) to (start + 2, 27) +- Code(Counter(0)) at (prev + 179, 13) to (start + 2, 27) - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) @@ -96,7 +96,7 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#15} -Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, ba, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a] +Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -104,7 +104,7 @@ Number of expressions: 3 - expression 1 operands: lhs = Counter(0), rhs = Counter(1) - expression 2 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 186, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 187, 9) to (start + 0, 10) - Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21) = (c1 + (c0 - c1)) - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) @@ -115,14 +115,14 @@ Number of file 0 mappings: 6 = (c1 + (c0 - c1)) Function name: closure::main::{closure#16} -Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, c4, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 196, 13) to (start + 2, 27) +- Code(Counter(0)) at (prev + 197, 13) to (start + 2, 27) - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) @@ -130,7 +130,7 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#17} -Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, cc, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a] +Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -138,7 +138,7 @@ Number of expressions: 3 - expression 1 operands: lhs = Counter(0), rhs = Counter(1) - expression 2 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 204, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 205, 9) to (start + 0, 10) - Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21) = (c1 + (c0 - c1)) - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) @@ -149,14 +149,14 @@ Number of file 0 mappings: 6 = (c1 + (c0 - c1)) Function name: closure::main::{closure#18} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 13) to (start + 2, 28) +- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) - Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) - Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) = (c0 - c1) @@ -164,14 +164,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#19} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 42, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 66, 13) to (start + 2, 28) +- Code(Counter(0)) at (prev + 67, 13) to (start + 2, 28) - Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) - Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) = (c0 - c1) @@ -179,14 +179,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#1} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 51, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 81, 5) to (start + 2, 20) +- Code(Counter(0)) at (prev + 82, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) = (c0 - c1) @@ -194,14 +194,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#2} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 67, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 103, 5) to (start + 2, 20) +- Code(Counter(0)) at (prev + 104, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) = (c0 - c1) @@ -209,61 +209,61 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure::main::{closure#3} (unused) -Raw bytes (25): 0x[01, 01, 00, 04, 00, 80, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Zero) at (prev + 128, 5) to (start + 1, 20) +- Code(Zero) at (prev + 129, 5) to (start + 1, 20) - Code(Zero) at (prev + 1, 21) to (start + 2, 10) - Code(Zero) at (prev + 2, 10) to (start + 0, 11) - Code(Zero) at (prev + 1, 9) to (start + 1, 6) Function name: closure::main::{closure#4} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 88, 01, 35, 00, 43] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 89, 01, 35, 00, 43] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 136, 53) to (start + 0, 67) +- Code(Zero) at (prev + 137, 53) to (start + 0, 67) Function name: closure::main::{closure#5} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8b, 01, 3d, 00, 4f] +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 3d, 00, 4f] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 139, 61) to (start + 0, 79) +- Code(Counter(0)) at (prev + 140, 61) to (start + 0, 79) Function name: closure::main::{closure#6} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 41, 00, 57] +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 41, 00, 57] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 140, 65) to (start + 0, 87) +- Code(Counter(0)) at (prev + 141, 65) to (start + 0, 87) Function name: closure::main::{closure#7} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 8d, 01, 3b, 00, 51] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 3b, 00, 51] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 141, 59) to (start + 0, 81) +- Code(Zero) at (prev + 142, 59) to (start + 0, 81) Function name: closure::main::{closure#8} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 92, 01, 3b, 00, 55] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 93, 01, 3b, 00, 55] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 146, 59) to (start + 0, 85) +- Code(Zero) at (prev + 147, 59) to (start + 0, 85) Function name: closure::main::{closure#9} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 94, 01, 38, 02, 06] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 95, 01, 38, 02, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 148, 56) to (start + 2, 6) +- Code(Zero) at (prev + 149, 56) to (start + 2, 6) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 67014f792c818..58224eeaf626f 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -5,6 +5,7 @@ LL| |// `rustc_middle/mir/mono.rs`, but those hacks were later cleaned up by LL| |// . LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/closure.rs b/tests/coverage/closure.rs index 16a2c4e33bd48..4be78062f3f5d 100644 --- a/tests/coverage/closure.rs +++ b/tests/coverage/closure.rs @@ -5,6 +5,7 @@ // `rustc_middle/mir/mono.rs`, but those hacks were later cleaned up by // . +#[rustfmt::skip] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 90eeb1a6686f3..160b348bd6320 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -1,5 +1,5 @@ Function name: closure_bug::main -Raw bytes (201): 0x[01, 01, 26, 01, 05, 05, 02, 05, 02, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 82, 01, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 01, 06, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 97, 01, 02, 09, 00, 0a, 97, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 92, 01, 00, 17, 00, 18, 8f, 01, 02, 09, 00, 0a, 8f, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 8a, 01, 00, 17, 00, 18, 87, 01, 02, 09, 00, 0a, 87, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 82, 01, 00, 17, 00, 18, 7f, 01, 01, 00, 02] +Raw bytes (201): 0x[01, 01, 26, 01, 05, 05, 02, 05, 02, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 82, 01, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 97, 01, 02, 09, 00, 0a, 97, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 92, 01, 00, 17, 00, 18, 8f, 01, 02, 09, 00, 0a, 8f, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 8a, 01, 00, 17, 00, 18, 87, 01, 02, 09, 00, 0a, 87, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 82, 01, 00, 17, 00, 18, 7f, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 38 @@ -42,7 +42,7 @@ Number of expressions: 38 - expression 36 operands: lhs = Expression(37, Add), rhs = Counter(2) - expression 37 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 17 -- Code(Counter(0)) at (prev + 6, 1) to (start + 3, 10) +- Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10) - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14) - Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23) - Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 24) @@ -72,14 +72,14 @@ Number of file 0 mappings: 17 = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) Function name: closure_bug::main::{closure#0} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0d, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 13, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 14, 9) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -87,14 +87,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure_bug::main::{closure#1} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 23, 9) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -102,14 +102,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure_bug::main::{closure#2} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1f, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 31, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 32, 9) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -117,14 +117,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: closure_bug::main::{closure#3} -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 40, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 41, 9) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) diff --git a/tests/coverage/closure_bug.coverage b/tests/coverage/closure_bug.coverage index f3299834bce19..3bf19f28072f5 100644 --- a/tests/coverage/closure_bug.coverage +++ b/tests/coverage/closure_bug.coverage @@ -3,6 +3,7 @@ LL| |// the coverage report. However, an unstable sort was causing them to be treated LL| |// inconsistently when preparing coverage spans. LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| let truthy = std::env::args().len() == 1; LL| 1| diff --git a/tests/coverage/closure_bug.rs b/tests/coverage/closure_bug.rs index 739bc5f0b51c9..6c94b90c656e4 100644 --- a/tests/coverage/closure_bug.rs +++ b/tests/coverage/closure_bug.rs @@ -3,6 +3,7 @@ // the coverage report. However, an unstable sort was causing them to be treated // inconsistently when preparing coverage spans. +#[rustfmt::skip] fn main() { let truthy = std::env::args().len() == 1; diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index b02c7e2e4c66b..571e5564b659c 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -27,10 +27,19 @@ Number of file 0 mappings: 7 = (c1 + (c0 - c1)) Function name: closure_macro::main::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 12, 00, 54] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 35, 18) to (start + 0, 84) +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) +- expression 2 operands: lhs = Counter(2), rhs = Zero +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) +- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) +- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) + = (c0 - c1) +- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) + = (c1 + (c2 + Zero)) diff --git a/tests/coverage/closure_macro.coverage b/tests/coverage/closure_macro.coverage index 0f2c917e09000..716d75cb8d754 100644 --- a/tests/coverage/closure_macro.coverage +++ b/tests/coverage/closure_macro.coverage @@ -1,5 +1,4 @@ - LL| |// compile-flags: --edition=2018 - LL| |#![feature(coverage_attribute)] + LL| |// edition: 2018 LL| | LL| |macro_rules! bail { LL| | ($msg:literal $(,)?) => { @@ -14,15 +13,16 @@ LL| | LL| |macro_rules! on_error { LL| | ($value:expr, $error_message:expr) => { - LL| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - LL| | let message = format!($error_message, e); - LL| | if message.len() > 0 { - LL| | println!("{}", message); - LL| | Ok(String::from("ok")) + LL| 0| $value.or_else(|e| { + LL| 0| // This closure, which is declared in a macro, should be instrumented. + LL| 0| let message = format!($error_message, e); + LL| 0| if message.len() > 0 { + LL| 0| println!("{}", message); + LL| 0| Ok(String::from("ok")) LL| | } else { - LL| | bail!("error"); + LL| 0| bail!("error"); LL| | } - LL| | }) + LL| 0| }) LL| | }; LL| |} LL| | diff --git a/tests/coverage/closure_macro.rs b/tests/coverage/closure_macro.rs index 9b289141c2e54..6fe1212de8d0b 100644 --- a/tests/coverage/closure_macro.rs +++ b/tests/coverage/closure_macro.rs @@ -1,5 +1,4 @@ -// compile-flags: --edition=2018 -#![feature(coverage_attribute)] +// edition: 2018 macro_rules! bail { ($msg:literal $(,)?) => { @@ -14,7 +13,8 @@ macro_rules! bail { macro_rules! on_error { ($value:expr, $error_message:expr) => { - $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + $value.or_else(|e| { + // This closure, which is declared in a macro, should be instrumented. let message = format!($error_message, e); if message.len() > 0 { println!("{}", message); diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 14b1525ca0e6c..49ec767eab33e 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -1,28 +1,28 @@ Function name: closure_macro_async::load_configuration_files -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2) +- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 2) Function name: closure_macro_async::test -Raw bytes (9): 0x[01, 01, 00, 01, 01, 22, 01, 00, 2b] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 2b] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 43) +- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43) Function name: closure_macro_async::test::{closure#0} -Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 22, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] +Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 34, 43) to (start + 1, 33) +- Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) @@ -35,10 +35,19 @@ Number of file 0 mappings: 7 = (c1 + (c0 - c1)) Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 24, 12, 00, 54] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 36, 18) to (start + 0, 84) +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) +- expression 2 operands: lhs = Counter(2), rhs = Zero +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 18, 28) to (start + 3, 33) +- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) +- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) + = (c0 - c1) +- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) + = (c1 + (c2 + Zero)) diff --git a/tests/coverage/closure_macro_async.coverage b/tests/coverage/closure_macro_async.coverage index 2c9bd4ac97a10..1032e027cd97d 100644 --- a/tests/coverage/closure_macro_async.coverage +++ b/tests/coverage/closure_macro_async.coverage @@ -15,15 +15,16 @@ LL| | LL| |macro_rules! on_error { LL| | ($value:expr, $error_message:expr) => { - LL| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - LL| | let message = format!($error_message, e); - LL| | if message.len() > 0 { - LL| | println!("{}", message); - LL| | Ok(String::from("ok")) + LL| 0| $value.or_else(|e| { + LL| 0| // This closure, which is declared in a macro, should be instrumented. + LL| 0| let message = format!($error_message, e); + LL| 0| if message.len() > 0 { + LL| 0| println!("{}", message); + LL| 0| Ok(String::from("ok")) LL| | } else { - LL| | bail!("error"); + LL| 0| bail!("error"); LL| | } - LL| | }) + LL| 0| }) LL| | }; LL| |} LL| | @@ -54,8 +55,7 @@ LL| | #[coverage(off)] LL| | pub fn block_on(mut future: F) -> F::Output { LL| | let mut future = pin!(future); - LL| | let waker = Waker::noop(); - LL| | let mut context = Context::from_waker(&waker); + LL| | let mut context = Context::from_waker(Waker::noop()); LL| | LL| | loop { LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/closure_macro_async.rs b/tests/coverage/closure_macro_async.rs index a7f0cabb4c239..db656fca19836 100644 --- a/tests/coverage/closure_macro_async.rs +++ b/tests/coverage/closure_macro_async.rs @@ -15,7 +15,8 @@ macro_rules! bail { macro_rules! on_error { ($value:expr, $error_message:expr) => { - $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + $value.or_else(|e| { + // This closure, which is declared in a macro, should be instrumented. let message = format!($error_message, e); if message.len() > 0 { println!("{}", message); @@ -53,8 +54,7 @@ mod executor { #[coverage(off)] pub fn block_on(mut future: F) -> F::Output { let mut future = pin!(future); - let waker = Waker::noop(); - let mut context = Context::from_waker(&waker); + let mut context = Context::from_waker(Waker::noop()); loop { if let Poll::Ready(val) = future.as_mut().poll(&mut context) { diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index cfee55ed31a4a..a6a427aca007f 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,5 +1,5 @@ Function name: conditions::main -Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, 31, ab, 04, 2d, 25, 29, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 03, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02] +Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, 31, ab, 04, 2d, 25, 29, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 04, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 142 @@ -197,7 +197,7 @@ Number of file 0 mappings: 68 - Code(Expression(56, Add)) at (prev + 2, 12) to (start + 0, 25) = (c24 + Zero) - Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(55, Sub)) at (prev + 3, 17) to (start + 0, 30) +- Code(Expression(55, Sub)) at (prev + 4, 17) to (start + 0, 30) = ((c24 + Zero) - c25) - Code(Expression(54, Sub)) at (prev + 1, 16) to (start + 0, 29) = (((c24 + Zero) - c25) - c11) diff --git a/tests/coverage/conditions.coverage b/tests/coverage/conditions.coverage index 473335ff641a1..48516217592e7 100644 --- a/tests/coverage/conditions.coverage +++ b/tests/coverage/conditions.coverage @@ -49,6 +49,7 @@ LL| 1| if countdown > 7 { LL| 1| countdown -= 4; LL| 1| } + LL| | // LL| 0| else if countdown > 2 { LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 { LL| 0| countdown = 0; diff --git a/tests/coverage/conditions.rs b/tests/coverage/conditions.rs index fa7f2a116c21e..e18e7191e6129 100644 --- a/tests/coverage/conditions.rs +++ b/tests/coverage/conditions.rs @@ -45,6 +45,7 @@ fn main() { if countdown > 7 { countdown -= 4; } + // else if countdown > 2 { if countdown < 1 || countdown > 5 || countdown != 9 { countdown = 0; diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 8dd03acc2f4dd..ef9faab590b33 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -1,5 +1,5 @@ Function name: coroutine::get_u32 -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 01, 01, 0b, 05, 01, 0e, 00, 13, 02, 00, 1d, 00, 3c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 07, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -7,14 +7,14 @@ Number of expressions: 2 - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 11, 1) to (start + 1, 11) -- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 19) -- Code(Expression(0, Sub)) at (prev + 0, 29) to (start + 0, 60) +- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 40) = (c0 - c1) -- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) +- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2) = (c1 + (c0 - c1)) Function name: coroutine::main -Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 0f, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -27,7 +27,7 @@ Number of expressions: 8 - expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(6) - expression 7 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 22) +- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) - Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) - Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53) @@ -43,11 +43,11 @@ Number of file 0 mappings: 9 = ((c4 - c5) - c6) Function name: coroutine::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 1c, 01, 1f, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 1c, 01, 1f, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 17, 28) to (start + 1, 31) +- Code(Counter(0)) at (prev + 21, 28) to (start + 1, 31) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/coroutine.coverage index 3a9791a0dbd8e..bd3d4e4688019 100644 --- a/tests/coverage/coroutine.coverage +++ b/tests/coverage/coroutine.coverage @@ -9,8 +9,11 @@ LL| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic LL| |// to handle this condition, and still report dead block coverage. LL| 1|fn get_u32(val: bool) -> Result { - LL| 1| if val { Ok(1) } else { Err(String::from("some error")) } - ^0 + LL| 1| if val { + LL| 1| Ok(1) + LL| | } else { + LL| 0| Err(String::from("some error")) + LL| | } LL| 1|} LL| | LL| 1|fn main() { diff --git a/tests/coverage/coroutine.rs b/tests/coverage/coroutine.rs index 86d19af6f4f08..2aa689466fc3e 100644 --- a/tests/coverage/coroutine.rs +++ b/tests/coverage/coroutine.rs @@ -9,7 +9,11 @@ use std::pin::Pin; // drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic // to handle this condition, and still report dead block coverage. fn get_u32(val: bool) -> Result { - if val { Ok(1) } else { Err(String::from("some error")) } + if val { + Ok(1) + } else { + Err(String::from("some error")) + } } fn main() { diff --git a/tests/coverage/coverage_attr_closure.cov-map b/tests/coverage/coverage_attr_closure.cov-map new file mode 100644 index 0000000000000..2208b28fd4149 --- /dev/null +++ b/tests/coverage/coverage_attr_closure.cov-map @@ -0,0 +1,34 @@ +Function name: coverage_attr_closure::GLOBAL_CLOSURE_ON::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 0f, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 6, 15) to (start + 2, 2) + +Function name: coverage_attr_closure::contains_closures_off::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 13, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 29, 19) to (start + 2, 6) + +Function name: coverage_attr_closure::contains_closures_on +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 02, 05, 01, 04, 06, 02, 05, 01, 04, 06, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 5) +- Code(Counter(0)) at (prev + 4, 6) to (start + 2, 5) +- Code(Counter(0)) at (prev + 4, 6) to (start + 1, 2) + +Function name: coverage_attr_closure::contains_closures_on::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 13, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 17, 19) to (start + 2, 6) + diff --git a/tests/coverage/coverage_attr_closure.coverage b/tests/coverage/coverage_attr_closure.coverage new file mode 100644 index 0000000000000..32c75b40d83c0 --- /dev/null +++ b/tests/coverage/coverage_attr_closure.coverage @@ -0,0 +1,43 @@ + LL| |#![feature(coverage_attribute, stmt_expr_attributes)] + LL| |#![allow(dead_code)] + LL| |// edition: 2021 + LL| | + LL| |static GLOBAL_CLOSURE_ON: fn(&str) = #[coverage(on)] + LL| 0||input: &str| { + LL| 0| println!("{input}"); + LL| 0|}; + LL| |static GLOBAL_CLOSURE_OFF: fn(&str) = #[coverage(off)] + LL| ||input: &str| { + LL| | println!("{input}"); + LL| |}; + LL| | + LL| |#[coverage(on)] + LL| 1|fn contains_closures_on() { + LL| 1| let _local_closure_on = #[coverage(on)] + LL| 1| |input: &str| { + LL| 0| println!("{input}"); + LL| 1| }; + LL| 1| let _local_closure_off = #[coverage(off)] + LL| 1| |input: &str| { + LL| | println!("{input}"); + LL| 1| }; + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn contains_closures_off() { + LL| | let _local_closure_on = #[coverage(on)] + LL| 0| |input: &str| { + LL| 0| println!("{input}"); + LL| 0| }; + LL| | let _local_closure_off = #[coverage(off)] + LL| | |input: &str| { + LL| | println!("{input}"); + LL| | }; + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | contains_closures_on(); + LL| | contains_closures_off(); + LL| |} + diff --git a/tests/coverage/coverage_attr_closure.rs b/tests/coverage/coverage_attr_closure.rs new file mode 100644 index 0000000000000..1904c89c9204d --- /dev/null +++ b/tests/coverage/coverage_attr_closure.rs @@ -0,0 +1,42 @@ +#![feature(coverage_attribute, stmt_expr_attributes)] +#![allow(dead_code)] +// edition: 2021 + +static GLOBAL_CLOSURE_ON: fn(&str) = #[coverage(on)] +|input: &str| { + println!("{input}"); +}; +static GLOBAL_CLOSURE_OFF: fn(&str) = #[coverage(off)] +|input: &str| { + println!("{input}"); +}; + +#[coverage(on)] +fn contains_closures_on() { + let _local_closure_on = #[coverage(on)] + |input: &str| { + println!("{input}"); + }; + let _local_closure_off = #[coverage(off)] + |input: &str| { + println!("{input}"); + }; +} + +#[coverage(off)] +fn contains_closures_off() { + let _local_closure_on = #[coverage(on)] + |input: &str| { + println!("{input}"); + }; + let _local_closure_off = #[coverage(off)] + |input: &str| { + println!("{input}"); + }; +} + +#[coverage(off)] +fn main() { + contains_closures_on(); + contains_closures_off(); +} diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map index 6e26c61aac9fb..c3969f8ce9990 100644 --- a/tests/coverage/fn_sig_into_try.cov-map +++ b/tests/coverage/fn_sig_into_try.cov-map @@ -1,51 +1,51 @@ Function name: fn_sig_into_try::a -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 04, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2) +- Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2) Function name: fn_sig_into_try::b -Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 10, 01, 02, 0f, 00, 02, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Zero - expression 1 operands: lhs = Zero, rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 17, 1) to (start + 3, 15) +- Code(Zero) at (prev + 3, 15) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - Zero) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = (Zero + (c0 - Zero)) Function name: fn_sig_into_try::c -Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 16, 01, 02, 17, 00, 02, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Zero - expression 1 operands: lhs = Zero, rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 23) -- Code(Zero) at (prev + 2, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 24, 1) to (start + 3, 23) +- Code(Zero) at (prev + 3, 23) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - Zero) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = (Zero + (c0 - Zero)) Function name: fn_sig_into_try::d -Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 1c, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Zero - expression 1 operands: lhs = Zero, rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 28, 1) to (start + 3, 15) -- Code(Zero) at (prev + 3, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 31, 1) to (start + 4, 15) +- Code(Zero) at (prev + 4, 15) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - Zero) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) diff --git a/tests/coverage/fn_sig_into_try.coverage b/tests/coverage/fn_sig_into_try.coverage index f1ddb1da78022..aac5c9d9a94ee 100644 --- a/tests/coverage/fn_sig_into_try.coverage +++ b/tests/coverage/fn_sig_into_try.coverage @@ -1,5 +1,5 @@ LL| |#![feature(coverage_attribute)] - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| |// Regression test for inconsistent handling of function signature spans that LL| |// are followed by code using the `?` operator. @@ -8,12 +8,14 @@ LL| |// signature should be handled in the same way. LL| | LL| 1|fn a() -> Option + LL| 1|// LL| 1|{ LL| 1| Some(7i32); LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn b() -> Option + LL| 1|// LL| 1|{ LL| 1| Some(7i32)?; ^0 @@ -21,6 +23,7 @@ LL| 1|} LL| | LL| 1|fn c() -> Option + LL| 1|// LL| 1|{ LL| 1| let _ = Some(7i32)?; ^0 @@ -28,6 +31,7 @@ LL| 1|} LL| | LL| 1|fn d() -> Option + LL| 1|// LL| 1|{ LL| 1| let _: () = (); LL| 1| Some(7i32)?; diff --git a/tests/coverage/fn_sig_into_try.rs b/tests/coverage/fn_sig_into_try.rs index 92850c8a188fc..5d8e7929ef975 100644 --- a/tests/coverage/fn_sig_into_try.rs +++ b/tests/coverage/fn_sig_into_try.rs @@ -1,5 +1,5 @@ #![feature(coverage_attribute)] -// compile-flags: --edition=2021 +// edition: 2021 // Regression test for inconsistent handling of function signature spans that // are followed by code using the `?` operator. @@ -8,24 +8,28 @@ // signature should be handled in the same way. fn a() -> Option +// { Some(7i32); Some(0) } fn b() -> Option +// { Some(7i32)?; Some(0) } fn c() -> Option +// { let _ = Some(7i32)?; Some(0) } fn d() -> Option +// { let _: () = (); Some(7i32)?; diff --git a/tests/coverage/generics.coverage b/tests/coverage/generics.coverage index 0983918356634..c68c0be80b150 100644 --- a/tests/coverage/generics.coverage +++ b/tests/coverage/generics.coverage @@ -1,11 +1,11 @@ LL| |#![allow(unused_assignments)] LL| |// failure-status: 1 LL| | - LL| |struct Firework where T: Copy + std::fmt::Display { + LL| |struct Firework { LL| | strength: T, LL| |} LL| | - LL| |impl Firework where T: Copy + std::fmt::Display { + LL| |impl Firework { LL| | #[inline(always)] LL| 3| fn set_strength(&mut self, new_strength: T) { LL| 3| self.strength = new_strength; @@ -23,7 +23,7 @@ ------------------ LL| |} LL| | - LL| |impl Drop for Firework where T: Copy + std::fmt::Display { + LL| |impl Drop for Firework { LL| | #[inline(always)] LL| 2| fn drop(&mut self) { LL| 2| println!("BOOM times {}!!!", self.strength); diff --git a/tests/coverage/generics.rs b/tests/coverage/generics.rs index bf4c2d8d68532..fd3811b6937b7 100644 --- a/tests/coverage/generics.rs +++ b/tests/coverage/generics.rs @@ -1,18 +1,18 @@ #![allow(unused_assignments)] // failure-status: 1 -struct Firework where T: Copy + std::fmt::Display { +struct Firework { strength: T, } -impl Firework where T: Copy + std::fmt::Display { +impl Firework { #[inline(always)] fn set_strength(&mut self, new_strength: T) { self.strength = new_strength; } } -impl Drop for Firework where T: Copy + std::fmt::Display { +impl Drop for Firework { #[inline(always)] fn drop(&mut self) { println!("BOOM times {}!!!", self.strength); diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index 391a69e0e821d..d7122f4b1a030 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -1,12 +1,12 @@ Function name: if::main -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 03, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 3, 1) to (start + 18, 16) +- Code(Counter(0)) at (prev + 4, 1) to (start + 18, 16) - Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) = (c0 - c1) diff --git a/tests/coverage/if.coverage b/tests/coverage/if.coverage index 2e6845190aabf..77db24ef51bf3 100644 --- a/tests/coverage/if.coverage +++ b/tests/coverage/if.coverage @@ -1,5 +1,6 @@ LL| |#![allow(unused_assignments, unused_variables)] LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/if.rs b/tests/coverage/if.rs index 8ad5042ff7baf..e8c0e7a7a2250 100644 --- a/tests/coverage/if.rs +++ b/tests/coverage/if.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments, unused_variables)] +#[rustfmt::skip] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map index da692ca3aa2a7..7163681d3a049 100644 --- a/tests/coverage/if_else.cov-map +++ b/tests/coverage/if_else.cov-map @@ -1,5 +1,5 @@ Function name: if_else::main -Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 1b, 06, 09, 00, 10, 09, 01, 05, 05, 06, 16, 07, 05, 05, 06, 13, 06, 01, 00, 02] +Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 1b, 06, 09, 00, 10, 09, 01, 05, 05, 06, 16, 07, 05, 05, 06, 13, 06, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -11,7 +11,7 @@ Number of expressions: 7 - expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2) - expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 3, 1) to (start + 8, 16) +- Code(Counter(0)) at (prev + 4, 1) to (start + 8, 16) - Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16) = (c0 - c1) diff --git a/tests/coverage/if_else.coverage b/tests/coverage/if_else.coverage index 0274401f0047c..2bf93487cec29 100644 --- a/tests/coverage/if_else.coverage +++ b/tests/coverage/if_else.coverage @@ -1,5 +1,6 @@ LL| |#![allow(unused_assignments, unused_variables)] LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/if_else.rs b/tests/coverage/if_else.rs index 3244e1e3afd2b..a0687925d636e 100644 --- a/tests/coverage/if_else.rs +++ b/tests/coverage/if_else.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments, unused_variables)] +#[rustfmt::skip] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index fb893e3796061..3c660551dea15 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -1,5 +1,5 @@ Function name: if_not::if_not -Raw bytes (86): 0x[01, 01, 10, 01, 05, 05, 02, 3f, 09, 05, 02, 09, 3a, 3f, 09, 05, 02, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0d, 32, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0a, 01, 04, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 3f, 03, 09, 01, 0d, 3a, 02, 05, 02, 06, 09, 02, 06, 00, 07, 37, 03, 09, 01, 0d, 32, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 2f, 03, 01, 00, 02] +Raw bytes (86): 0x[01, 01, 10, 01, 05, 05, 02, 3f, 09, 05, 02, 09, 3a, 3f, 09, 05, 02, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0d, 32, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 3f, 03, 09, 01, 0d, 3a, 02, 05, 02, 06, 09, 02, 06, 00, 07, 37, 03, 09, 01, 0d, 32, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 2f, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 16 @@ -20,7 +20,7 @@ Number of expressions: 16 - expression 14 operands: lhs = Expression(15, Add), rhs = Counter(2) - expression 15 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 13) +- Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13) - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 6) to (start + 0, 7) diff --git a/tests/coverage/if_not.coverage b/tests/coverage/if_not.coverage index 41838b8513f6a..86ff7fc4f07da 100644 --- a/tests/coverage/if_not.coverage +++ b/tests/coverage/if_not.coverage @@ -1,6 +1,7 @@ LL| |#![feature(coverage_attribute)] LL| |// edition: 2021 LL| | + LL| |#[rustfmt::skip] LL| 12|fn if_not(cond: bool) { LL| 12| if LL| 12| ! diff --git a/tests/coverage/if_not.rs b/tests/coverage/if_not.rs index 4f45ae0b3d447..7b166662b5d03 100644 --- a/tests/coverage/if_not.rs +++ b/tests/coverage/if_not.rs @@ -1,6 +1,7 @@ #![feature(coverage_attribute)] // edition: 2021 +#[rustfmt::skip] fn if_not(cond: bool) { if ! diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index ab04e746b9165..c669b7245ead8 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -1,20 +1,20 @@ Function name: inline_dead::dead (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 01, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 1) to (start + 2, 2) +- Code(Zero) at (prev + 23, 1) to (start + 2, 2) Function name: inline_dead::live:: -Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 10, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 0e, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Zero - expression 1 operands: lhs = Zero, rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 9) +- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) - Code(Zero) at (prev + 2, 9) to (start + 0, 15) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - Zero) @@ -22,16 +22,16 @@ Number of file 0 mappings: 4 = (Zero + (c0 - Zero)) Function name: inline_dead::main -Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0d, 01, 07, 06, 02, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0d, 01, 05, 06, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 4, 1) to (start + 3, 13) -- Code(Counter(0)) at (prev + 7, 6) to (start + 2, 2) +- Code(Counter(0)) at (prev + 5, 6) to (start + 2, 2) Function name: inline_dead::main::{closure#0} -Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 01, 16, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06] +Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 01, 16, 00, 01, 17, 00, 18, 03, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -39,7 +39,7 @@ Number of expressions: 2 - expression 1 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 7, 23) to (start + 1, 22) -- Code(Zero) at (prev + 2, 13) to (start + 0, 14) -- Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6) +- Code(Zero) at (prev + 1, 23) to (start + 0, 24) +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 6) = (Zero + (c0 - Zero)) diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage index 7c201f482db31..a643332bce1fd 100644 --- a/tests/coverage/inline-dead.coverage +++ b/tests/coverage/inline-dead.coverage @@ -5,9 +5,8 @@ LL| 1| println!("{}", live::()); LL| 1| LL| 1| let f = |x: bool| { - LL| 1| debug_assert!( - LL| 0| x - LL| | ); + LL| 1| debug_assert!(x); + ^0 LL| 1| }; LL| 1| f(false); LL| 1|} diff --git a/tests/coverage/inline-dead.rs b/tests/coverage/inline-dead.rs index 854fa06296752..a854c17f6d597 100644 --- a/tests/coverage/inline-dead.rs +++ b/tests/coverage/inline-dead.rs @@ -5,9 +5,7 @@ fn main() { println!("{}", live::()); let f = |x: bool| { - debug_assert!( - x - ); + debug_assert!(x); }; f(false); } diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index f5db3a89750c7..f2447e3c92c8a 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,19 +1,3 @@ -Function name: ::eq -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 11, 00, 1a] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 17) to (start + 0, 26) - -Function name: ::fmt -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 0a, 00, 0f] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 10) to (start + 0, 15) - Function name: issue_83601::main Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02] Number of files: 1 diff --git a/tests/coverage/issue-83601.coverage b/tests/coverage/issue-83601.coverage index 7995332cad339..e050106e6f0b0 100644 --- a/tests/coverage/issue-83601.coverage +++ b/tests/coverage/issue-83601.coverage @@ -1,7 +1,6 @@ LL| |// Shows that rust-lang/rust/83601 is resolved LL| | - LL| 3|#[derive(Debug, PartialEq, Eq)] - ^2 + LL| |#[derive(Debug, PartialEq, Eq)] LL| |struct Foo(u32); LL| | LL| 1|fn main() { diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 82582b309bfcf..88436964af0f7 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -1,20 +1,12 @@ -Function name: ::eq -Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 0a, 00, 13] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19) - Function name: ::fmt -Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 88, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 136, 5) to (start + 1, 37) +- Code(Counter(0)) at (prev + 138, 5) to (start + 1, 37) - Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) @@ -22,15 +14,15 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: issue_84561::main -Raw bytes (10): 0x[01, 01, 00, 01, 01, b2, 01, 01, 04, 02] +Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 178, 1) to (start + 4, 2) +- Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2) Function name: issue_84561::test1 -Raw bytes (78): 0x[01, 01, 0e, 05, 06, 01, 05, 09, 36, 03, 09, 0d, 2e, 33, 0d, 09, 36, 03, 09, 11, 26, 2b, 11, 0d, 2e, 33, 0d, 09, 36, 03, 09, 09, 01, 98, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 03, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 33, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 2b, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 23, 01, 01, 00, 02] +Raw bytes (78): 0x[01, 01, 0e, 05, 06, 01, 05, 09, 36, 03, 09, 0d, 2e, 33, 0d, 09, 36, 03, 09, 11, 26, 2b, 11, 0d, 2e, 33, 0d, 09, 36, 03, 09, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 03, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 33, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 2b, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 23, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 14 @@ -49,7 +41,7 @@ Number of expressions: 14 - expression 12 operands: lhs = Counter(2), rhs = Expression(13, Sub) - expression 13 operands: lhs = Expression(0, Add), rhs = Counter(2) Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 152, 1) to (start + 1, 11) +- Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11) - Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30) - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 11) = (c1 + (c0 - c1)) @@ -64,28 +56,28 @@ Number of file 0 mappings: 9 = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) Function name: issue_84561::test2 -Raw bytes (24): 0x[01, 01, 02, 05, 06, 01, 05, 03, 01, ae, 01, 01, 01, 10, 05, 01, 11, 00, 23, 03, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 02, 05, 06, 01, 05, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 03, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub) - expression 1 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 174, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35) - Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2) = (c1 + (c0 - c1)) Function name: issue_84561::test2::call_print -Raw bytes (10): 0x[01, 01, 00, 01, 01, a5, 01, 09, 02, 0a] +Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 165, 9) to (start + 2, 10) +- Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10) Function name: issue_84561::test3 -Raw bytes (436): 0x[01, 01, 41, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 71, fe, 01, 82, 02, 71, 69, 6d, 69, 6d, 82, 02, 71, 69, 6d, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 33, 01, 06, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 71, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Raw bytes (436): 0x[01, 01, 41, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 71, fe, 01, 82, 02, 71, 69, 6d, 69, 6d, 82, 02, 71, 69, 6d, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 71, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 65 @@ -155,7 +147,7 @@ Number of expressions: 65 - expression 63 operands: lhs = Expression(64, Sub), rhs = Counter(28) - expression 64 operands: lhs = Counter(26), rhs = Counter(27) Number of file 0 mappings: 51 -- Code(Counter(0)) at (prev + 6, 1) to (start + 3, 28) +- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28) - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 4, 31) = (c1 - c2) diff --git a/tests/coverage/issue-84561.coverage b/tests/coverage/issue-84561.coverage index e693866e27760..90a2d069d3949 100644 --- a/tests/coverage/issue-84561.coverage +++ b/tests/coverage/issue-84561.coverage @@ -1,8 +1,10 @@ LL| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. LL| | LL| |// failure-status: 101 - LL| 21|#[derive(PartialEq, Eq)] + LL| |#[derive(PartialEq, Eq)] LL| |struct Foo(u32); + LL| | + LL| |#[rustfmt::skip] LL| 1|fn test3() { LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let bar = Foo(1); diff --git a/tests/coverage/issue-84561.rs b/tests/coverage/issue-84561.rs index facf5b5b4cfbe..9c218a37e6c41 100644 --- a/tests/coverage/issue-84561.rs +++ b/tests/coverage/issue-84561.rs @@ -3,6 +3,8 @@ // failure-status: 101 #[derive(PartialEq, Eq)] struct Foo(u32); + +#[rustfmt::skip] fn test3() { let is_true = std::env::args().len() == 1; let bar = Foo(1); diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map index c2c6e9a651673..024ef519fcffe 100644 --- a/tests/coverage/issue-93054.cov-map +++ b/tests/coverage/issue-93054.cov-map @@ -1,24 +1,24 @@ Function name: issue_93054::foo2 (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 22, 1) to (start + 0, 29) +- Code(Zero) at (prev + 21, 1) to (start + 0, 29) Function name: issue_93054::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 00, 0d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13) Function name: issue_93054::make (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 01, 02, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 26, 1) to (start + 2, 2) +- Code(Zero) at (prev + 25, 1) to (start + 2, 2) diff --git a/tests/coverage/issue-93054.coverage b/tests/coverage/issue-93054.coverage index 15f225326a427..6ae8ffb5cb4f2 100644 --- a/tests/coverage/issue-93054.coverage +++ b/tests/coverage/issue-93054.coverage @@ -1,11 +1,10 @@ LL| |#![allow(dead_code, unreachable_code)] + LL| |// edition: 2021 LL| | LL| |// Regression test for #93054: Functions using uninhabited types often only have a single, LL| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. LL| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. LL| | - LL| |// compile-flags: --edition=2021 - LL| | LL| |enum Never {} LL| | LL| |impl Never { diff --git a/tests/coverage/issue-93054.rs b/tests/coverage/issue-93054.rs index da546cfeef854..f16fc1e423962 100644 --- a/tests/coverage/issue-93054.rs +++ b/tests/coverage/issue-93054.rs @@ -1,11 +1,10 @@ #![allow(dead_code, unreachable_code)] +// edition: 2021 // Regression test for #93054: Functions using uninhabited types often only have a single, // unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. // Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. -// compile-flags: --edition=2021 - enum Never {} impl Never { diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index 2d1ff24e62d56..03dbb59d26b5c 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -1,5 +1,5 @@ Function name: lazy_boolean::main -Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 03, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 03, 09, 01, 10, ea, 04, 02, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 08, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02] +Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 03, 09, 01, 10, ea, 04, 02, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 08, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 164 @@ -168,7 +168,7 @@ Number of expressions: 164 - expression 162 operands: lhs = Expression(163, Add), rhs = Counter(2) - expression 163 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 28 -- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) +- Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6) - Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) = (c0 - c1) diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/lazy_boolean.coverage index 2d927a083560f..f058be8390082 100644 --- a/tests/coverage/lazy_boolean.coverage +++ b/tests/coverage/lazy_boolean.coverage @@ -1,5 +1,6 @@ LL| |#![allow(unused_assignments, unused_variables)] LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/lazy_boolean.rs b/tests/coverage/lazy_boolean.rs index bb6219e851c8a..47bfb1164490c 100644 --- a/tests/coverage/lazy_boolean.rs +++ b/tests/coverage/lazy_boolean.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments, unused_variables)] +#[rustfmt::skip] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/long_and_wide.coverage b/tests/coverage/long_and_wide.coverage index d7d29ca40cddd..cf4dd2811406c 100644 --- a/tests/coverage/long_and_wide.coverage +++ b/tests/coverage/long_and_wide.coverage @@ -1,4 +1,4 @@ - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| |// ignore-tidy-linelength LL| | LL| |// This file deliberately contains line and column numbers larger than 127, diff --git a/tests/coverage/long_and_wide.rs b/tests/coverage/long_and_wide.rs index a7cbcd4802791..87f2207bd7e67 100644 --- a/tests/coverage/long_and_wide.rs +++ b/tests/coverage/long_and_wide.rs @@ -1,4 +1,4 @@ -// compile-flags: --edition=2021 +// edition: 2021 // ignore-tidy-linelength // This file deliberately contains line and column numbers larger than 127, diff --git a/tests/coverage/loop_break_value.cov-map b/tests/coverage/loop_break_value.cov-map index 75018442d0757..d8dca8a85c387 100644 --- a/tests/coverage/loop_break_value.cov-map +++ b/tests/coverage/loop_break_value.cov-map @@ -1,8 +1,8 @@ Function name: loop_break_value::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 0a, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 0a, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 10, 2) +- Code(Counter(0)) at (prev + 4, 1) to (start + 10, 2) diff --git a/tests/coverage/loop_break_value.coverage b/tests/coverage/loop_break_value.coverage index 1f0630636ddfa..7d45339875946 100644 --- a/tests/coverage/loop_break_value.coverage +++ b/tests/coverage/loop_break_value.coverage @@ -1,5 +1,6 @@ LL| |#![allow(unused_assignments, unused_variables)] LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| let result LL| 1| = diff --git a/tests/coverage/loop_break_value.rs b/tests/coverage/loop_break_value.rs index dbc4fad7a2316..015365c2b3e19 100644 --- a/tests/coverage/loop_break_value.rs +++ b/tests/coverage/loop_break_value.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments, unused_variables)] +#[rustfmt::skip] fn main() { let result = diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map new file mode 100644 index 0000000000000..2feaab717b5cb --- /dev/null +++ b/tests/coverage/macro_in_closure.cov-map @@ -0,0 +1,16 @@ +Function name: macro_in_closure::NO_BLOCK::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 1c, 00, 2d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 7, 28) to (start + 0, 45) + +Function name: macro_in_closure::WITH_BLOCK::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 1e, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 9, 30) to (start + 2, 2) + diff --git a/tests/coverage/macro_in_closure.coverage b/tests/coverage/macro_in_closure.coverage new file mode 100644 index 0000000000000..7f6f873439dff --- /dev/null +++ b/tests/coverage/macro_in_closure.coverage @@ -0,0 +1,18 @@ + LL| |#![feature(coverage_attribute)] + LL| |// edition: 2021 + LL| | + LL| |// If a closure body consists entirely of a single bang-macro invocation, the + LL| |// body span ends up inside the macro-expansion, so we need to un-expand it + LL| |// back to the declaration site. + LL| 1|static NO_BLOCK: fn() = || println!("hello"); + LL| | + LL| 1|static WITH_BLOCK: fn() = || { + LL| 1| println!("hello"); + LL| 1|}; + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | NO_BLOCK(); + LL| | WITH_BLOCK(); + LL| |} + diff --git a/tests/coverage/macro_in_closure.rs b/tests/coverage/macro_in_closure.rs new file mode 100644 index 0000000000000..6948c9079c09c --- /dev/null +++ b/tests/coverage/macro_in_closure.rs @@ -0,0 +1,17 @@ +#![feature(coverage_attribute)] +// edition: 2021 + +// If a closure body consists entirely of a single bang-macro invocation, the +// body span ends up inside the macro-expansion, so we need to un-expand it +// back to the declaration site. +static NO_BLOCK: fn() = || println!("hello"); + +static WITH_BLOCK: fn() = || { + println!("hello"); +}; + +#[coverage(off)] +fn main() { + NO_BLOCK(); + WITH_BLOCK(); +} diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 3a803e3c18fbd..80670fbfa5a75 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -1,51 +1,3 @@ -Function name: ::clone (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 04, 0a, 00, 0f] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 4, 10) to (start + 0, 15) - -Function name: ::cmp (unused) -Raw bytes (14): 0x[01, 01, 00, 02, 00, 04, 33, 00, 34, 00, 00, 35, 00, 36] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Zero) at (prev + 4, 51) to (start + 0, 52) -- Code(Zero) at (prev + 0, 53) to (start + 0, 54) - -Function name: ::eq (unused) -Raw bytes (14): 0x[01, 01, 00, 02, 00, 04, 18, 00, 19, 00, 00, 20, 00, 21] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Zero) at (prev + 4, 24) to (start + 0, 25) -- Code(Zero) at (prev + 0, 32) to (start + 0, 33) - -Function name: ::partial_cmp -Raw bytes (22): 0x[01, 01, 04, 07, 0b, 00, 09, 0f, 15, 00, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 4 -- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add) -- expression 1 operands: lhs = Zero, rhs = Counter(2) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) -- expression 3 operands: lhs = Zero, rhs = Counter(4) -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40) -- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49) - = ((Zero + c2) + ((Zero + c4) + c5)) - -Function name: ::fmt -Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 4, 17) to (start + 0, 22) - Function name: ::new Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06] Number of files: 1 @@ -55,10 +7,10 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 5) to (start + 6, 6) Function name: partial_eq::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 05, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 0a, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 21, 1) to (start + 5, 2) +- Code(Counter(0)) at (prev + 21, 1) to (start + 10, 2) diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage index c6d9ad6cf27e8..9de1c933570cb 100644 --- a/tests/coverage/partial_eq.coverage +++ b/tests/coverage/partial_eq.coverage @@ -1,8 +1,7 @@ LL| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the LL| |// structure of this test. LL| | - LL| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^0 ^0 ^0 ^1 ^1 ^0^0 + LL| |#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] LL| |pub struct Version { LL| | major: usize, LL| | minor: usize, @@ -23,7 +22,12 @@ LL| 1| let version_3_2_1 = Version::new(3, 2, 1); LL| 1| let version_3_3_0 = Version::new(3, 3, 0); LL| 1| - LL| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); + LL| 1| println!( + LL| 1| "{:?} < {:?} = {}", + LL| 1| version_3_2_1, + LL| 1| version_3_3_0, + LL| 1| version_3_2_1 < version_3_3_0 + LL| 1| ); LL| 1|} LL| | LL| |/* diff --git a/tests/coverage/partial_eq.rs b/tests/coverage/partial_eq.rs index dd8b42c18cea9..825e266f111f5 100644 --- a/tests/coverage/partial_eq.rs +++ b/tests/coverage/partial_eq.rs @@ -22,7 +22,12 @@ fn main() { let version_3_2_1 = Version::new(3, 2, 1); let version_3_3_0 = Version::new(3, 3, 0); - println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); + println!( + "{:?} < {:?} = {}", + version_3_2_1, + version_3_3_0, + version_3_2_1 < version_3_3_0 + ); } /* diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index f1691ffc5e6a0..0a342cb3673a8 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -1,5 +1,5 @@ Function name: simple_loop::main -Raw bytes (57): 0x[01, 01, 09, 01, 05, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 07, 01, 03, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 1f, 05, 0d, 02, 0e, 1a, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 1a, 06, 01, 00, 02] +Raw bytes (57): 0x[01, 01, 09, 01, 05, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 1f, 05, 0d, 02, 0e, 1a, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 1a, 06, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -13,7 +13,7 @@ Number of expressions: 9 - expression 7 operands: lhs = Expression(8, Add), rhs = Counter(2) - expression 8 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 3, 1) to (start + 9, 16) +- Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16) - Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) = (c0 - c1) diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/simple_loop.coverage index 691c6cd1e7dda..b6552c62ff909 100644 --- a/tests/coverage/simple_loop.coverage +++ b/tests/coverage/simple_loop.coverage @@ -1,5 +1,6 @@ LL| |#![allow(unused_assignments)] LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/simple_loop.rs b/tests/coverage/simple_loop.rs index 6f7f23475b826..6776911563df3 100644 --- a/tests/coverage/simple_loop.rs +++ b/tests/coverage/simple_loop.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments)] +#[rustfmt::skip] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index 4a32745d29293..7c242e2c328db 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -1,5 +1,5 @@ Function name: simple_match::main -Raw bytes (78): 0x[01, 01, 0c, 01, 05, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 0a, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 27, 05, 09, 00, 0d, 22, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 22, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] +Raw bytes (78): 0x[01, 01, 0c, 01, 05, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 27, 05, 09, 00, 0d, 22, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 22, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 12 @@ -16,7 +16,7 @@ Number of expressions: 12 - expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub) - expression 11 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) +- Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/simple_match.coverage index 7f5dd3bb64630..3a4fc6743f5e0 100644 --- a/tests/coverage/simple_match.coverage +++ b/tests/coverage/simple_match.coverage @@ -1,5 +1,6 @@ LL| |#![allow(unused_assignments, unused_variables)] LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/simple_match.rs b/tests/coverage/simple_match.rs index be99e59a82685..2ad4e55b4edc0 100644 --- a/tests/coverage/simple_match.rs +++ b/tests/coverage/simple_match.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments, unused_variables)] +#[rustfmt::skip] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from diff --git a/tests/coverage/sort_groups.coverage b/tests/coverage/sort_groups.coverage index c70d7b3b28253..77cbb09c74a73 100644 --- a/tests/coverage/sort_groups.coverage +++ b/tests/coverage/sort_groups.coverage @@ -1,4 +1,4 @@ - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a LL| |// predictable order, while preserving their heterogeneous contents. diff --git a/tests/coverage/sort_groups.rs b/tests/coverage/sort_groups.rs index 5adbbc6a87d1f..17fd862ca2cad 100644 --- a/tests/coverage/sort_groups.rs +++ b/tests/coverage/sort_groups.rs @@ -1,4 +1,4 @@ -// compile-flags: --edition=2021 +// edition: 2021 // Demonstrate that `sort_subviews.py` can sort instantiation groups into a // predictable order, while preserving their heterogeneous contents. diff --git a/tests/coverage/test_harness.cov-map b/tests/coverage/test_harness.cov-map index 6940d2e282430..f75328b11c9ab 100644 --- a/tests/coverage/test_harness.cov-map +++ b/tests/coverage/test_harness.cov-map @@ -6,14 +6,6 @@ Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16) -Function name: test_harness::my_test::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 01, 00, 08] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 8) - Function name: test_harness::unused (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f] Number of files: 1 diff --git a/tests/coverage/test_harness.coverage b/tests/coverage/test_harness.coverage index ff6009f6fce43..c3f660506fbd8 100644 --- a/tests/coverage/test_harness.coverage +++ b/tests/coverage/test_harness.coverage @@ -6,6 +6,6 @@ LL| |#[allow(dead_code)] LL| 0|fn unused() {} LL| | - LL| 1|#[test] + LL| |#[test] LL| 1|fn my_test() {} diff --git a/tests/coverage/thin-lto.cov-map b/tests/coverage/thin-lto.cov-map index 7e84e398f8454..1f61b805f622b 100644 --- a/tests/coverage/thin-lto.cov-map +++ b/tests/coverage/thin-lto.cov-map @@ -1,8 +1,8 @@ Function name: thin_lto::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 01, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 11] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 17) diff --git a/tests/coverage/thin-lto.coverage b/tests/coverage/thin-lto.coverage index 21abb5dce04e1..7ece467217ac5 100644 --- a/tests/coverage/thin-lto.coverage +++ b/tests/coverage/thin-lto.coverage @@ -1,5 +1,4 @@ LL| |// compile-flags: -O -C lto=thin -C prefer-dynamic=no LL| | - LL| 1|pub fn main() { - LL| 1|} + LL| 1|pub fn main() {} diff --git a/tests/coverage/thin-lto.rs b/tests/coverage/thin-lto.rs index 050aac2631971..04e9cd0e8088b 100644 --- a/tests/coverage/thin-lto.rs +++ b/tests/coverage/thin-lto.rs @@ -1,4 +1,3 @@ // compile-flags: -O -C lto=thin -C prefer-dynamic=no -pub fn main() { -} +pub fn main() {} diff --git a/tests/coverage/trivial.coverage b/tests/coverage/trivial.coverage index 4f417979ef97d..af4be7b8f3356 100644 --- a/tests/coverage/trivial.coverage +++ b/tests/coverage/trivial.coverage @@ -1,4 +1,4 @@ - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| 1|fn main() {} diff --git a/tests/coverage/trivial.rs b/tests/coverage/trivial.rs index d0a9b44fb3605..782472739a002 100644 --- a/tests/coverage/trivial.rs +++ b/tests/coverage/trivial.rs @@ -1,3 +1,3 @@ -// compile-flags: --edition=2021 +// edition: 2021 fn main() {} diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index a9a18a180dddf..5cfb40ce52894 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -1,12 +1,12 @@ Function name: ::get_thing_2 -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 07, 02, 05, 00, 06] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 07, 02, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 40, 5) to (start + 1, 24) +- Code(Counter(0)) at (prev + 41, 5) to (start + 1, 24) - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26) = (c0 - c1) @@ -14,14 +14,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: ::call -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 33, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 07, 02, 05, 00, 06] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 07, 02, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 51, 5) to (start + 1, 24) +- Code(Counter(0)) at (prev + 52, 5) to (start + 1, 24) - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) @@ -44,14 +44,14 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: try_error_result::main -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 70, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 112, 1) to (start + 2, 12) +- Code(Counter(0)) at (prev + 115, 1) to (start + 2, 12) - Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) @@ -59,7 +59,7 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: try_error_result::test1 -Raw bytes (77): 0x[01, 01, 09, 01, 07, 05, 09, 03, 0d, 1d, 11, 16, 1d, 03, 0d, 1f, 0d, 23, 19, 11, 15, 0b, 01, 0c, 01, 02, 17, 03, 07, 09, 00, 0e, 16, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 0e, 01, 0d, 00, 2a, 15, 00, 2a, 00, 2b, 12, 04, 0d, 00, 2a, 19, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 1b, 01, 01, 00, 02] +Raw bytes (77): 0x[01, 01, 09, 01, 07, 05, 09, 03, 0d, 1d, 11, 16, 1d, 03, 0d, 1f, 0d, 23, 19, 11, 15, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 16, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 0e, 01, 0d, 00, 2a, 15, 00, 2a, 00, 2b, 12, 04, 0d, 00, 2a, 19, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 1b, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -73,7 +73,7 @@ Number of expressions: 9 - expression 7 operands: lhs = Expression(8, Add), rhs = Counter(6) - expression 8 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 12, 1) to (start + 2, 23) +- Code(Counter(0)) at (prev + 13, 1) to (start + 2, 23) - Code(Expression(0, Add)) at (prev + 7, 9) to (start + 0, 14) = (c0 + (c1 + c2)) - Code(Expression(5, Sub)) at (prev + 2, 9) to (start + 4, 26) @@ -91,7 +91,7 @@ Number of file 0 mappings: 11 = (((c4 + c5) + c6) + c3) Function name: try_error_result::test2 -Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3c, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] +Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3e, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 59 @@ -155,7 +155,7 @@ Number of expressions: 59 - expression 57 operands: lhs = Counter(12), rhs = Counter(13) - expression 58 operands: lhs = Counter(14), rhs = Counter(15) Number of file 0 mappings: 40 -- Code(Counter(0)) at (prev + 60, 1) to (start + 3, 23) +- Code(Counter(0)) at (prev + 62, 1) to (start + 3, 23) - Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14) = (c0 + (c1 + c2)) - Code(Expression(36, Sub)) at (prev + 2, 9) to (start + 4, 26) diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage index 5d48cbd62f207..418efa7fcb5cc 100644 --- a/tests/coverage/try_error_result.coverage +++ b/tests/coverage/try_error_result.coverage @@ -9,6 +9,7 @@ LL| | } LL| 6|} LL| | + LL| |#[rustfmt::skip] LL| 1|fn test1() -> Result<(), ()> { LL| 1| let mut LL| 1| countdown = 10 @@ -58,6 +59,7 @@ LL| 17| } LL| |} LL| | + LL| |#[rustfmt::skip] LL| 1|fn test2() -> Result<(), ()> { LL| 1| let thing1 = Thing1{}; LL| 1| let mut @@ -115,6 +117,7 @@ LL| 0| Ok(()) LL| 1|} LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() -> Result<(), ()> { LL| 1| test1().expect_err("test1 should fail"); LL| 1| test2() diff --git a/tests/coverage/try_error_result.rs b/tests/coverage/try_error_result.rs index 557cbf22bfad4..1acc261691232 100644 --- a/tests/coverage/try_error_result.rs +++ b/tests/coverage/try_error_result.rs @@ -9,6 +9,7 @@ fn call(return_error: bool) -> Result<(), ()> { } } +#[rustfmt::skip] fn test1() -> Result<(), ()> { let mut countdown = 10 @@ -57,6 +58,7 @@ impl Thing2 { } } +#[rustfmt::skip] fn test2() -> Result<(), ()> { let thing1 = Thing1{}; let mut @@ -109,6 +111,7 @@ fn test2() -> Result<(), ()> { Ok(()) } +#[rustfmt::skip] fn main() -> Result<(), ()> { test1().expect_err("test1 should fail"); test2() diff --git a/tests/coverage/unreachable.coverage b/tests/coverage/unreachable.coverage index 7015bb90aa38d..a58765f688be5 100644 --- a/tests/coverage/unreachable.coverage +++ b/tests/coverage/unreachable.coverage @@ -1,6 +1,6 @@ LL| |#![feature(core_intrinsics)] LL| |#![feature(coverage_attribute)] - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| |// LL| |// If we instrument a function for coverage, but all of its counter-increment diff --git a/tests/coverage/unreachable.rs b/tests/coverage/unreachable.rs index 6385bfa160d7d..6d0c7b3ca8db5 100644 --- a/tests/coverage/unreachable.rs +++ b/tests/coverage/unreachable.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] #![feature(coverage_attribute)] -// compile-flags: --edition=2021 +// edition: 2021 // // If we instrument a function for coverage, but all of its counter-increment diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map index af250f3fb710b..c6557b48e27dc 100644 --- a/tests/coverage/while.cov-map +++ b/tests/coverage/while.cov-map @@ -1,5 +1,5 @@ Function name: while::main -Raw bytes (28): 0x[01, 01, 02, 01, 00, 03, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 01, 06, 06, 02, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 00, 03, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 06, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -9,7 +9,7 @@ Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16) - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 20) = (c0 + Zero) -- Code(Zero) at (prev + 0, 21) to (start + 1, 6) -- Code(Expression(1, Sub)) at (prev + 2, 1) to (start + 0, 2) +- Code(Zero) at (prev + 0, 21) to (start + 2, 6) +- Code(Expression(1, Sub)) at (prev + 3, 1) to (start + 0, 2) = ((c0 + Zero) - Zero) diff --git a/tests/coverage/while.coverage b/tests/coverage/while.coverage index c9d497651c9f2..90c16288d668c 100644 --- a/tests/coverage/while.coverage +++ b/tests/coverage/while.coverage @@ -1,6 +1,7 @@ LL| 1|fn main() { LL| 1| let num = 9; LL| 1| while num >= 10 { + LL| 0| // loop body LL| 0| } LL| 1|} diff --git a/tests/coverage/while.rs b/tests/coverage/while.rs index 781b90b35663e..d60916a979818 100644 --- a/tests/coverage/while.rs +++ b/tests/coverage/while.rs @@ -1,5 +1,6 @@ fn main() { let num = 9; while num >= 10 { + // loop body } } diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map index 369ebe891f127..c883eb4baf200 100644 --- a/tests/coverage/while_early_ret.cov-map +++ b/tests/coverage/while_early_ret.cov-map @@ -1,5 +1,5 @@ Function name: while_early_ret::main -Raw bytes (61): 0x[01, 01, 06, 01, 05, 03, 09, 0e, 05, 03, 09, 17, 09, 0d, 11, 09, 01, 04, 01, 01, 1b, 03, 03, 09, 02, 0a, 0e, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 11, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 13, 01, 01, 00, 02] +Raw bytes (61): 0x[01, 01, 06, 01, 05, 03, 09, 0e, 05, 03, 09, 17, 09, 0d, 11, 09, 01, 05, 01, 01, 1b, 03, 03, 09, 02, 0a, 0e, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 11, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 13, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 6 @@ -10,7 +10,7 @@ Number of expressions: 6 - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(2) - expression 5 operands: lhs = Counter(3), rhs = Counter(4) Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 27) +- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 27) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 2, 10) = (c0 + c1) - Code(Expression(3, Sub)) at (prev + 5, 13) to (start + 2, 14) diff --git a/tests/coverage/while_early_ret.coverage b/tests/coverage/while_early_ret.coverage index 49d39d366038c..f4372ad282e31 100644 --- a/tests/coverage/while_early_ret.coverage +++ b/tests/coverage/while_early_ret.coverage @@ -1,6 +1,7 @@ LL| |#![allow(unused_assignments)] LL| |// failure-status: 1 LL| | + LL| |#[rustfmt::skip] LL| 1|fn main() -> Result<(), u8> { LL| 1| let mut countdown = 10; LL| | while diff --git a/tests/coverage/while_early_ret.rs b/tests/coverage/while_early_ret.rs index b2f0eee2cc0f4..a6421e797f61c 100644 --- a/tests/coverage/while_early_ret.rs +++ b/tests/coverage/while_early_ret.rs @@ -1,6 +1,7 @@ #![allow(unused_assignments)] // failure-status: 1 +#[rustfmt::skip] fn main() -> Result<(), u8> { let mut countdown = 10; while diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index d66e4c660f7b5..400e8801ca217 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -46,12 +46,12 @@ // cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] // cdb-command: dx niche128_some -// cdb-check: niche128_some : Some [Type: enum2$ >] +// cdb-check: niche128_some : Some [Type: enum2$ > >] // Note: we can't actually read the value of the field because CDB cannot handle 128 bit integers. -// cdb-check: [+0x000] __0 [...] [Type: core::num::nonzero::NonZeroI128] +// cdb-check: [+0x000] __0 [...] [Type: core::num::nonzero::NonZero] // cdb-command: dx niche128_none -// cdb-check: niche128_none : None [Type: enum2$ >] +// cdb-check: niche128_none : None [Type: enum2$ > >] // cdb-command: dx wrapping_niche128_untagged // cdb-check: wrapping_niche128_untagged : X [Type: enum2$] @@ -84,7 +84,7 @@ // cdb-command: dx niche_w_fields_2_some,d // cdb-check: niche_w_fields_2_some,d : A [Type: enum2$] -// cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZeroU32] +// cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZero] // cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] // cdb-command: dx niche_w_fields_2_none,d diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index c122112e6c77a..a1b5ae792a16b 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -3,59 +3,59 @@ // min-gdb-version: 8.1 // ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows -// Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping` and +// Tests the visualizations for `NonZero`, `Wrapping` and // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`. // === CDB TESTS ================================================================================== // cdb-command: g // cdb-command: dx nz_i8 -// cdb-check:nz_i8 : 11 [Type: core::num::nonzero::NonZeroI8] -// cdb-check: [] [Type: core::num::nonzero::NonZeroI8] +// cdb-check:nz_i8 : 11 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_i16 -// cdb-check:nz_i16 : 22 [Type: core::num::nonzero::NonZeroI16] -// cdb-check: [] [Type: core::num::nonzero::NonZeroI16] +// cdb-check:nz_i16 : 22 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_i32 -// cdb-check:nz_i32 : 33 [Type: core::num::nonzero::NonZeroI32] -// cdb-check: [] [Type: core::num::nonzero::NonZeroI32] +// cdb-check:nz_i32 : 33 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_i64 -// cdb-check:nz_i64 : 44 [Type: core::num::nonzero::NonZeroI64] -// cdb-check: [] [Type: core::num::nonzero::NonZeroI64] +// cdb-check:nz_i64 : 44 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // 128-bit integers don't seem to work in CDB // cdb-command: dx nz_i128 -// cdb-check: [] [Type: core::num::nonzero::NonZeroI128] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_isize -// cdb-check:nz_isize : 66 [Type: core::num::nonzero::NonZeroIsize] -// cdb-check: [] [Type: core::num::nonzero::NonZeroIsize] +// cdb-check:nz_isize : 66 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_u8 -// cdb-check:nz_u8 : 0x4d [Type: core::num::nonzero::NonZeroU8] -// cdb-check: [] [Type: core::num::nonzero::NonZeroU8] +// cdb-check:nz_u8 : 0x4d [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_u16 -// cdb-check:nz_u16 : 0x58 [Type: core::num::nonzero::NonZeroU16] -// cdb-check: [] [Type: core::num::nonzero::NonZeroU16] +// cdb-check:nz_u16 : 0x58 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_u32 -// cdb-check:nz_u32 : 0x63 [Type: core::num::nonzero::NonZeroU32] -// cdb-check: [] [Type: core::num::nonzero::NonZeroU32] +// cdb-check:nz_u32 : 0x63 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_u64 -// cdb-check:nz_u64 : 0x64 [Type: core::num::nonzero::NonZeroU64] -// cdb-check: [] [Type: core::num::nonzero::NonZeroU64] +// cdb-check:nz_u64 : 0x64 [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // 128-bit integers don't seem to work in CDB // cdb-command: dx nz_u128 -// cdb-check: [] [Type: core::num::nonzero::NonZeroU128] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx nz_usize -// cdb-check:nz_usize : 0x7a [Type: core::num::nonzero::NonZeroUsize] -// cdb-check: [] [Type: core::num::nonzero::NonZeroUsize] +// cdb-check:nz_usize : 0x7a [Type: core::num::nonzero::NonZero] +// cdb-check: [] [Type: core::num::nonzero::NonZero] // cdb-command: dx w_i8 // cdb-check:w_i8 : 10 [Type: core::num::wrapping::Wrapping] diff --git a/tests/incremental/commandline-args.rs b/tests/incremental/commandline-args.rs index e17e6feae0745..7a4c33d36e410 100644 --- a/tests/incremental/commandline-args.rs +++ b/tests/incremental/commandline-args.rs @@ -11,13 +11,13 @@ #![rustc_partition_codegened(module="commandline_args", cfg="rpass4")] // Between revisions 1 and 2, we are changing the debuginfo-level, which should -// invalidate the cache. Between revisions 2 and 3, we are adding `--verbose` +// invalidate the cache. Between revisions 2 and 3, we are adding `--diagnostic-width` // which should have no effect on the cache. Between revisions, we are adding // `--remap-path-prefix` which should invalidate the cache: //[rpass1] compile-flags: -C debuginfo=0 //[rpass2] compile-flags: -C debuginfo=2 -//[rpass3] compile-flags: -C debuginfo=2 --verbose -//[rpass4] compile-flags: -C debuginfo=2 --verbose --remap-path-prefix=/home/bors/rust=src +//[rpass3] compile-flags: -C debuginfo=2 --diagnostic-width=80 +//[rpass4] compile-flags: -C debuginfo=2 --diagnostic-width=80 --remap-path-prefix=/home/bors/r=src pub fn main() { // empty diff --git a/tests/incremental/dirty_clean.rs b/tests/incremental/dirty_clean.rs index 87a8696b1899f..e6379286805e1 100644 --- a/tests/incremental/dirty_clean.rs +++ b/tests/incremental/dirty_clean.rs @@ -26,11 +26,11 @@ mod y { use x; #[rustc_clean( - except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig", + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig", cfg="cfail2", )] pub fn y() { - //[cfail2]~^ ERROR `hir_owner_nodes(y)` should be dirty but is not + //[cfail2]~^ ERROR `opt_hir_owner_nodes(y)` should be dirty but is not //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not //[cfail2]~| ERROR `type_of(y)` should be dirty but is not diff --git a/tests/incremental/hash-module-order.rs b/tests/incremental/hash-module-order.rs index f9244d8adbf35..2e71884a531ae 100644 --- a/tests/incremental/hash-module-order.rs +++ b/tests/incremental/hash-module-order.rs @@ -12,14 +12,14 @@ #![feature(rustc_attrs)] #[cfg(rpass1)] -#[rustc_clean(cfg="rpass1",except="hir_owner_nodes")] +#[rustc_clean(cfg="rpass1",except="opt_hir_owner_nodes")] mod foo { struct First; struct Second; } #[cfg(rpass2)] -#[rustc_clean(cfg="rpass2",except="hir_owner_nodes")] +#[rustc_clean(cfg="rpass2",except="opt_hir_owner_nodes")] mod foo { struct Second; struct First; diff --git a/tests/incremental/hashes/call_expressions.rs b/tests/incremental/hashes/call_expressions.rs index a42cf6aa477c5..bad2e10e497d9 100644 --- a/tests/incremental/hashes/call_expressions.rs +++ b/tests/incremental/hashes/call_expressions.rs @@ -28,9 +28,9 @@ pub fn change_callee_function() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_callee_function() { callee2(1, 2) @@ -45,9 +45,9 @@ pub fn change_argument_function() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_argument_function() { callee1(1, 3) @@ -62,9 +62,9 @@ mod change_callee_indirectly_function { #[cfg(not(any(cfail1,cfail4)))] use super::callee2 as callee; - #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn change_callee_indirectly_function() { callee(1, 2) @@ -86,9 +86,9 @@ pub fn change_callee_method() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_callee_method() { let s = Struct; @@ -105,9 +105,9 @@ pub fn change_argument_method() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_argument_method() { let s = Struct; @@ -124,9 +124,9 @@ pub fn change_ufcs_callee_method() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_ufcs_callee_method() { let s = Struct; @@ -143,9 +143,9 @@ pub fn change_argument_method_ufcs() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_argument_method_ufcs() { let s = Struct; @@ -162,11 +162,11 @@ pub fn change_to_ufcs() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] -// One might think this would be expanded in the hir_owner_nodes/Mir, but it actually +// One might think this would be expanded in the opt_hir_owner_nodes/Mir, but it actually // results in slightly different hir_owner/Mir. pub fn change_to_ufcs() { let s = Struct; @@ -186,9 +186,9 @@ pub mod change_ufcs_callee_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::Struct2 as Struct; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_ufcs_callee_indirectly() { let s = Struct; diff --git a/tests/incremental/hashes/closure_expressions.rs b/tests/incremental/hashes/closure_expressions.rs index 927bcd96e6f4b..0173d129b2392 100644 --- a/tests/incremental/hashes/closure_expressions.rs +++ b/tests/incremental/hashes/closure_expressions.rs @@ -24,9 +24,9 @@ pub fn change_closure_body() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_closure_body() { let _ = || 3u32; @@ -42,9 +42,9 @@ pub fn add_parameter() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_parameter() { let x = 0u32; @@ -60,9 +60,9 @@ pub fn change_parameter_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_parameter_pattern() { let _ = |(x,): (u32,)| x; @@ -77,9 +77,9 @@ pub fn add_move() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_move() { let _ = move || 1; @@ -95,9 +95,9 @@ pub fn add_type_ascription_to_parameter() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, typeck")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg = "cfail6")] pub fn add_type_ascription_to_parameter() { let closure = |x: u32| x + 1u32; @@ -114,9 +114,9 @@ pub fn change_parameter_type() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_parameter_type() { let closure = |x: u16| (x as u64) + 1; diff --git a/tests/incremental/hashes/consts.rs b/tests/incremental/hashes/consts.rs index 7cba3c159e600..138618a982d28 100644 --- a/tests/incremental/hashes/consts.rs +++ b/tests/incremental/hashes/consts.rs @@ -19,7 +19,7 @@ const CONST_VISIBILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] pub const CONST_VISIBILITY: u8 = 0; @@ -29,7 +29,7 @@ pub const CONST_VISIBILITY: u8 = 0; const CONST_CHANGE_TYPE_1: i32 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_1: u32 = 0; @@ -39,13 +39,13 @@ const CONST_CHANGE_TYPE_1: u32 = 0; const CONST_CHANGE_TYPE_2: Option = None; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_2: Option = None; // Change value between simple literals -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_1: i16 = { #[cfg(cfail1)] @@ -57,7 +57,7 @@ const CONST_CHANGE_VALUE_1: i16 = { // Change value between expressions -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_2: i16 = { #[cfg(cfail1)] @@ -67,7 +67,7 @@ const CONST_CHANGE_VALUE_2: i16 = { { 1 + 2 } }; -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_3: i16 = { #[cfg(cfail1)] @@ -77,7 +77,7 @@ const CONST_CHANGE_VALUE_3: i16 = { { 2 * 3 } }; -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_4: i16 = { #[cfg(cfail1)] @@ -99,11 +99,11 @@ mod const_change_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as Type; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff --git a/tests/incremental/hashes/enum_constructors.rs b/tests/incremental/hashes/enum_constructors.rs index 0a88dd4e15537..1e0db8ffc9284 100644 --- a/tests/incremental/hashes/enum_constructors.rs +++ b/tests/incremental/hashes/enum_constructors.rs @@ -37,9 +37,9 @@ pub fn change_field_value_struct_like() -> Enum { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_field_value_struct_like() -> Enum { Enum::Struct { @@ -62,9 +62,9 @@ pub fn change_field_order_struct_like() -> Enum { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] // FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it // would if it were not all constants @@ -103,9 +103,9 @@ pub fn change_constructor_path_struct_like() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_struct_like() { let _ = Enum2::Struct { @@ -128,9 +128,9 @@ pub fn change_constructor_variant_struct_like() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_variant_struct_like() { let _ = Enum2::Struct2 { @@ -148,9 +148,9 @@ pub mod change_constructor_path_indirectly_struct_like { #[cfg(not(any(cfail1,cfail4)))] use super::Enum2 as TheEnum; - #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::Struct { @@ -170,9 +170,9 @@ pub mod change_constructor_variant_indirectly_struct_like { #[cfg(not(any(cfail1,cfail4)))] use super::Enum2::Struct2 as Variant; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn function() -> Enum2 { Variant { @@ -191,9 +191,9 @@ pub fn change_field_value_tuple_like() -> Enum { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_field_value_tuple_like() -> Enum { Enum::Tuple(0, 1, 3) @@ -210,12 +210,12 @@ pub fn change_constructor_path_tuple_like() { #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,typeck" + except="opt_hir_owner_nodes,typeck" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,typeck" + except="opt_hir_owner_nodes,typeck" )] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_tuple_like() { @@ -233,12 +233,12 @@ pub fn change_constructor_variant_tuple_like() { #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,typeck" + except="opt_hir_owner_nodes,typeck" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,typeck" + except="opt_hir_owner_nodes,typeck" )] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_variant_tuple_like() { @@ -253,9 +253,9 @@ pub mod change_constructor_path_indirectly_tuple_like { #[cfg(not(any(cfail1,cfail4)))] use super::Enum2 as TheEnum; - #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::Tuple(0, 1, 2) @@ -272,9 +272,9 @@ pub mod change_constructor_variant_indirectly_tuple_like { #[cfg(not(any(cfail1,cfail4)))] use super::Enum2::Tuple2 as Variant; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> Enum2 { Variant(0, 1, 2) @@ -301,9 +301,9 @@ pub fn change_constructor_path_c_like() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_c_like() { let _x = Clike2::B; @@ -318,9 +318,9 @@ pub fn change_constructor_variant_c_like() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_variant_c_like() { let _x = Clike::C; @@ -334,9 +334,9 @@ pub mod change_constructor_path_indirectly_c_like { #[cfg(not(any(cfail1,cfail4)))] use super::Clike2 as TheEnum; - #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::B @@ -353,9 +353,9 @@ pub mod change_constructor_variant_indirectly_c_like { #[cfg(not(any(cfail1,cfail4)))] use super::Clike::B as Variant; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn function() -> Clike { Variant diff --git a/tests/incremental/hashes/enum_defs.rs b/tests/incremental/hashes/enum_defs.rs index cb7a4e61e4f57..2293d15b97f27 100644 --- a/tests/incremental/hashes/enum_defs.rs +++ b/tests/incremental/hashes/enum_defs.rs @@ -31,7 +31,7 @@ enum EnumVisibility { A } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub enum EnumVisibility { A } @@ -45,9 +45,9 @@ enum EnumChangeNameCStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameCStyleVariant { Variant1, @@ -64,9 +64,9 @@ enum EnumChangeNameTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameTupleStyleVariant { Variant1, @@ -83,9 +83,9 @@ enum EnumChangeNameStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameStructStyleVariant { Variant1, @@ -102,9 +102,9 @@ enum EnumChangeValueCStyleVariant0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeValueCStyleVariant0 { Variant1, @@ -118,9 +118,9 @@ enum EnumChangeValueCStyleVariant1 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeValueCStyleVariant1 { Variant1, @@ -136,9 +136,9 @@ enum EnumAddCStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddCStyleVariant { Variant1, @@ -155,9 +155,9 @@ enum EnumRemoveCStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumRemoveCStyleVariant { Variant1, @@ -172,9 +172,9 @@ enum EnumAddTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTupleStyleVariant { Variant1, @@ -191,9 +191,9 @@ enum EnumRemoveTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumRemoveTupleStyleVariant { Variant1, @@ -208,9 +208,9 @@ enum EnumAddStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddStructStyleVariant { Variant1, @@ -227,9 +227,9 @@ enum EnumRemoveStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumRemoveStructStyleVariant { Variant1, @@ -244,9 +244,9 @@ enum EnumChangeFieldTypeTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldTypeTupleStyleVariant { Variant1(u32, @@ -263,9 +263,9 @@ enum EnumChangeFieldTypeStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, @@ -284,9 +284,9 @@ enum EnumChangeFieldNameStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldNameStructStyleVariant { Variant1 { a: u32, c: u32 }, @@ -301,9 +301,9 @@ enum EnumChangeOrderTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeOrderTupleStyleVariant { Variant1( @@ -320,9 +320,9 @@ enum EnumChangeFieldOrderStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldOrderStructStyleVariant { Variant1 { b: f32, a: u32 }, @@ -337,9 +337,9 @@ enum EnumAddFieldTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddFieldTupleStyleVariant { Variant1(u32, u32, u32), @@ -354,9 +354,9 @@ enum EnumAddFieldStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddFieldStructStyleVariant { Variant1 { a: u32, b: u32, c: u32 }, @@ -411,9 +411,9 @@ enum EnumChangeNameOfTypeParameter { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameOfTypeParameter { Variant1(T), @@ -429,9 +429,9 @@ enum EnumAddTypeParameter { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTypeParameter { Variant1(S), @@ -447,9 +447,9 @@ enum EnumChangeNameOfLifetimeParameter<'a> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameOfLifetimeParameter<'b> { Variant1(&'b u32), @@ -465,9 +465,9 @@ enum EnumAddLifetimeParameter<'a> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameter<'a, 'b> { Variant1(&'a u32), @@ -484,9 +484,9 @@ enum EnumAddLifetimeParameterBound<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameterBound<'a, 'b: 'a> { Variant1(&'a u32), @@ -501,9 +501,9 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), @@ -519,9 +519,9 @@ enum EnumAddTraitBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTraitBound { Variant1(T), @@ -537,9 +537,9 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a { Variant1(&'a u32), @@ -556,9 +556,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), @@ -574,9 +574,9 @@ enum EnumAddTraitBoundWhere { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTraitBoundWhere where T: Sync { Variant1(T), @@ -592,9 +592,9 @@ enum EnumSwapUsageTypeParameters { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumSwapUsageTypeParameters { Variant1 { @@ -615,9 +615,9 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { Variant1 { @@ -642,9 +642,9 @@ mod change_field_type_indirectly_tuple_style { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum TupleStyle { Variant1( @@ -662,9 +662,9 @@ mod change_field_type_indirectly_struct_style { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum StructStyle { Variant1 { @@ -687,9 +687,9 @@ mod change_trait_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum Enum { Variant1(T) @@ -705,9 +705,9 @@ mod change_trait_bound_indirectly_where { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum Enum where T: Trait { Variant1(T) diff --git a/tests/incremental/hashes/exported_vs_not.rs b/tests/incremental/hashes/exported_vs_not.rs index 9ac9ae24f81bc..358ba1d93d1a7 100644 --- a/tests/incremental/hashes/exported_vs_not.rs +++ b/tests/incremental/hashes/exported_vs_not.rs @@ -10,7 +10,7 @@ #![crate_type="rlib"] // Case 1: The function body is not exported to metadata. If the body changes, -// the hash of the hir_owner_nodes node should change, but not the hash of +// the hash of the opt_hir_owner_nodes node should change, but not the hash of // either the hir_owner or the Metadata node. #[cfg(any(cfail1,cfail4))] @@ -19,9 +19,9 @@ pub fn body_not_exported_to_metadata() -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn body_not_exported_to_metadata() -> u32 { 2 @@ -40,9 +40,9 @@ pub fn body_exported_to_metadata_because_of_inline() -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] #[inline] pub fn body_exported_to_metadata_because_of_inline() -> u32 { @@ -62,9 +62,9 @@ pub fn body_exported_to_metadata_because_of_generic() -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] #[inline] pub fn body_exported_to_metadata_because_of_generic() -> u32 { diff --git a/tests/incremental/hashes/extern_mods.rs b/tests/incremental/hashes/extern_mods.rs index 93a8fcfea3214..efac5c91658c6 100644 --- a/tests/incremental/hashes/extern_mods.rs +++ b/tests/incremental/hashes/extern_mods.rs @@ -24,9 +24,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn change_function_name2(c: i64) -> i32; @@ -129,9 +129,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "rust-call" { pub fn change_calling_convention(c: (i32,)); @@ -159,9 +159,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn add_function1(c: i32); diff --git a/tests/incremental/hashes/for_loops.rs b/tests/incremental/hashes/for_loops.rs index 84a04ff913b84..e297fcdd329db 100644 --- a/tests/incremental/hashes/for_loops.rs +++ b/tests/incremental/hashes/for_loops.rs @@ -28,9 +28,9 @@ pub fn change_loop_body() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; @@ -53,9 +53,9 @@ pub fn change_iteration_variable_name() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_iteration_variable_name() { let mut _x = 0; @@ -78,9 +78,9 @@ pub fn change_iteration_variable_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_iteration_variable_pattern() { let mut _x = 0; @@ -103,9 +103,9 @@ pub fn change_iterable() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, promoted_mir, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, promoted_mir, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_iterable() { let mut _x = 0; @@ -128,9 +128,9 @@ pub fn add_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; @@ -153,9 +153,9 @@ pub fn add_loop_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; @@ -178,9 +178,9 @@ pub fn add_loop_label_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -205,9 +205,9 @@ pub fn change_break_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; @@ -232,9 +232,9 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -259,9 +259,9 @@ pub fn change_continue_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; @@ -286,9 +286,9 @@ pub fn change_continue_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index 2aaaf94492c2f..5ba4781c5f1ca 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -25,12 +25,12 @@ pub fn add_parameter() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn add_parameter(p: i32) {} @@ -41,9 +41,9 @@ pub fn add_parameter(p: i32) {} pub fn add_return_type() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg = "cfail6")] pub fn add_return_type() -> () {} @@ -55,12 +55,12 @@ pub fn type_of_parameter(p: i32) {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn type_of_parameter(p: i64) {} @@ -73,12 +73,12 @@ pub fn type_of_parameter_ref(p: &i32) {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn type_of_parameter_ref(p: &mut i32) {} @@ -91,12 +91,12 @@ pub fn order_of_parameters(p1: i32, p2: i64) {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn order_of_parameters(p2: i64, p1: i32) {} @@ -109,12 +109,12 @@ pub fn make_unsafe() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub unsafe fn make_unsafe() {} @@ -125,9 +125,9 @@ pub unsafe fn make_unsafe() {} pub fn make_extern() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail6")] pub extern "C" fn make_extern() {} @@ -139,12 +139,12 @@ pub fn type_parameter () {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, generics_of, type_of, predicates_of" + except = "opt_hir_owner_nodes, generics_of, type_of, predicates_of" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, generics_of, type_of, predicates_of" + except = "opt_hir_owner_nodes, generics_of, type_of, predicates_of" )] #[rustc_clean(cfg = "cfail6")] pub fn type_parameter() {} @@ -155,9 +155,9 @@ pub fn type_parameter() {} pub fn lifetime_parameter () {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, generics_of,fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, generics_of,fn_sig")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, generics_of,fn_sig")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, generics_of,fn_sig")] #[rustc_clean(cfg = "cfail6")] pub fn lifetime_parameter<'a>() {} @@ -167,7 +167,7 @@ pub fn lifetime_parameter<'a>() {} pub fn trait_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn trait_bound() {} @@ -177,9 +177,9 @@ pub fn trait_bound() {} pub fn builtin_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn builtin_bound() {} @@ -191,12 +191,12 @@ pub fn lifetime_bound<'a, T>() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" + except = "opt_hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig,optimized_mir" + except = "opt_hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig,optimized_mir" )] #[rustc_clean(cfg = "cfail6")] pub fn lifetime_bound<'a, T: 'a>() {} @@ -207,7 +207,7 @@ pub fn lifetime_bound<'a, T: 'a>() {} pub fn second_trait_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn second_trait_bound() {} @@ -217,9 +217,9 @@ pub fn second_trait_bound() {} pub fn second_builtin_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn second_builtin_bound() {} @@ -231,12 +231,12 @@ pub fn second_lifetime_bound<'a, 'b, T: 'a >() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" + except = "opt_hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" + except = "opt_hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {} @@ -302,9 +302,9 @@ pub fn return_impl_trait() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, typeck, fn_sig, optimized_mir")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, typeck, fn_sig, optimized_mir")] #[rustc_clean(cfg = "cfail6")] pub fn return_impl_trait() -> impl Clone { 0 @@ -339,12 +339,12 @@ pub mod change_return_type_indirectly { #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn indirect_return_type() -> ReturnType { @@ -362,12 +362,12 @@ pub mod change_parameter_type_indirectly { #[rustc_clean( cfg = "cfail2", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn indirect_parameter_type(p: ParameterType) {} @@ -384,9 +384,9 @@ pub mod change_trait_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] - #[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn indirect_trait_bound(p: T) {} } @@ -399,9 +399,9 @@ pub mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] - #[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn indirect_trait_bound_where(p: T) where diff --git a/tests/incremental/hashes/if_expressions.rs b/tests/incremental/hashes/if_expressions.rs index cd80f8aa00a59..430a6015bd5a9 100644 --- a/tests/incremental/hashes/if_expressions.rs +++ b/tests/incremental/hashes/if_expressions.rs @@ -27,9 +27,9 @@ pub fn change_condition(x: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_condition(x: bool) -> u32 { if !x { @@ -50,9 +50,9 @@ pub fn change_then_branch(x: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_then_branch(x: bool) -> u32 { if x { @@ -75,9 +75,9 @@ pub fn change_else_branch(x: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_else_branch(x: bool) -> u32 { if x { @@ -103,9 +103,9 @@ pub fn add_else_branch(x: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -131,9 +131,9 @@ pub fn change_condition_if_let(x: Option) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_condition_if_let(x: Option) -> u32 { if let Some(_ ) = x { @@ -156,9 +156,9 @@ pub fn change_then_branch_if_let(x: Option) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_then_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -181,9 +181,9 @@ pub fn change_else_branch_if_let(x: Option) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_else_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -209,9 +209,9 @@ pub fn add_else_branch_if_let(x: Option) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; diff --git a/tests/incremental/hashes/indexing_expressions.rs b/tests/incremental/hashes/indexing_expressions.rs index 4bccec61a7ce3..f07550305f12c 100644 --- a/tests/incremental/hashes/indexing_expressions.rs +++ b/tests/incremental/hashes/indexing_expressions.rs @@ -23,9 +23,9 @@ fn change_simple_index(slice: &[u32]) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn change_simple_index(slice: &[u32]) -> u32 { slice[4] @@ -40,9 +40,9 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn change_lower_bound(slice: &[u32]) -> &[u32] { &slice[2..5] @@ -57,9 +57,9 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn change_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] @@ -74,9 +74,9 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn add_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..4] @@ -91,9 +91,9 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn add_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] @@ -108,9 +108,9 @@ fn change_mutability(slice: &mut [u32]) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn change_mutability(slice: &mut [u32]) -> u32 { (& slice[3..5])[0] @@ -125,9 +125,9 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { &slice[3..=7] diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs index 853fbc79fc878..a2b3dcdc1587a 100644 --- a/tests/incremental/hashes/inherent_impls.rs +++ b/tests/incremental/hashes/inherent_impls.rs @@ -26,9 +26,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail3")] @@ -41,9 +41,9 @@ impl Foo { // This should affect the method itself, but not the impl. #[cfg(any(cfail1,cfail4))] impl Foo { - //-------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------------ //-------------------------- - //-------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------------ //-------------------------- pub fn method_body() { // ----------------------- @@ -56,9 +56,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,promoted_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,promoted_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn method_body() { println!("Hello, world!"); @@ -73,12 +73,12 @@ impl Foo { impl Foo { //------------ //--------------- - //------------------------------------------------------------ + //---------------------------------------------------------------- // //-------------------------- //------------ //--------------- - //------------------------------------------------------------ + //---------------------------------------------------------------- // //-------------------------- #[inline] @@ -95,12 +95,12 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" + except="opt_hir_owner_nodes,optimized_mir,promoted_mir,typeck" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" + except="opt_hir_owner_nodes,optimized_mir,promoted_mir,typeck" )] #[rustc_clean(cfg="cfail6")] #[inline] @@ -115,7 +115,7 @@ impl Foo { impl Foo { //-------------------------- //-------------------------- - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- pub fn method_privacy() { } } @@ -128,7 +128,7 @@ impl Foo { impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] fn method_privacy() { } } @@ -138,31 +138,31 @@ impl Foo { impl Foo { //------------ //--------------- - //----------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- // //-------------------------- //------------ //--------------- - //----------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- // //-------------------------- pub fn method_selfness() { } } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", + except="opt_hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", + except="opt_hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", )] #[rustc_clean(cfg="cfail6")] pub fn method_selfness(&self) { } @@ -171,9 +171,9 @@ impl Foo { // Change Method Selfmutness --------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- pub fn method_selfmutness(& self) { } } @@ -184,9 +184,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn method_selfmutness(&mut self) { } } @@ -200,9 +200,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -221,9 +221,9 @@ impl Foo { // Add Method Parameter -------------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- pub fn add_method_parameter(&self ) { } } @@ -234,9 +234,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_method_parameter(&self, _: i32) { } } @@ -246,9 +246,9 @@ impl Foo { // Change Method Parameter Name ------------------------------------------------ #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- pub fn change_method_parameter_name(&self, a: i64) { } } @@ -259,9 +259,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_method_parameter_name(&self, b: i64) { } } @@ -271,9 +271,9 @@ impl Foo { // Change Method Return Type --------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- pub fn change_method_return_type(&self) -> u16 { 0 } } @@ -284,9 +284,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_method_return_type(&self) -> u32 { 0 } } @@ -323,9 +323,9 @@ impl Foo { // Change order of parameters ------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- pub fn change_method_parameter_order(&self, a: i64, b: i64) { } } @@ -336,9 +336,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } } @@ -348,9 +348,9 @@ impl Foo { // Make method unsafe ---------------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- - //-------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------ //-------------------------- pub fn make_method_unsafe(&self) { } } @@ -361,9 +361,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub unsafe fn make_method_unsafe(&self) { } } @@ -373,9 +373,9 @@ impl Foo { // Make method extern ---------------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- pub fn make_method_extern(&self) { } } @@ -386,9 +386,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail6")] pub extern "C" fn make_method_extern(&self) { } } @@ -398,9 +398,9 @@ impl Foo { // Change method calling convention -------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- pub extern "C" fn change_method_calling_convention(&self) { } } @@ -411,9 +411,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail6")] pub extern "system" fn change_method_calling_convention(&self) { } } @@ -432,9 +432,9 @@ impl Foo { // ---------------------------------------------------------- // ----------------------------------------------------------- // ---------------------------------------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // ------------------------- pub fn add_lifetime_parameter_to_method (&self) { } } @@ -454,9 +454,9 @@ impl Foo { // if we lower generics before the body, then the `HirId` for // things in the body will be affected. So if you start to see // `typeck` appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,generics_of")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,generics_of")] #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -477,12 +477,12 @@ impl Foo { // ------------------------------------------------- // ----------- // -------------- - // ------------------------------------------------------------ + // ---------------------------------------------------------------- // // ------------------------- // ----------- // -------------- - // ------------------------------------------------------------ + // ---------------------------------------------------------------- // // ------------------------- pub fn add_type_parameter_to_method (&self) { } @@ -505,12 +505,12 @@ impl Foo { // appear dirty, that might be the cause. -nmatsakis #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,generics_of,predicates_of,type_of", + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,generics_of,predicates_of,type_of", + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of", )] #[rustc_clean(cfg="cfail6")] pub fn add_type_parameter_to_method(&self) { } @@ -523,12 +523,12 @@ impl Foo { impl Foo { //------------ //--------------- - //------------------------------------------------------------------- + //----------------------------------------------------------------------- // //-------------------------- //------------ //--------------- - //------------------------------------------------------------------- + //----------------------------------------------------------------------- // //-------------------------- pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b >(&self) { } @@ -542,12 +542,12 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } @@ -569,12 +569,12 @@ impl Foo { // ------------------------------------------------- // ----------- // -------------- - // ------------------------------------------------------------------ + // ---------------------------------------------------------------------- // // ------------------------- // ----------- // -------------- - // ------------------------------------------------------------------ + // ---------------------------------------------------------------------- // // ------------------------- pub fn add_lifetime_bound_to_type_param_of_method<'a, T >(&self) { } @@ -597,12 +597,12 @@ impl Foo { // appear dirty, that might be the cause. -nmatsakis #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="opt_hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { } @@ -622,9 +622,9 @@ impl Foo { // ------------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------- - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- pub fn add_trait_bound_to_type_param_of_method(&self) { } } @@ -644,9 +644,9 @@ impl Foo { // generics before the body, then the `HirId` for things in the // body will be affected. So if you start to see `typeck` // appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] pub fn add_trait_bound_to_type_param_of_method(&self) { } } @@ -689,9 +689,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,generics_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,generics_of")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean( @@ -716,9 +716,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")] @@ -737,9 +737,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2")] @@ -758,9 +758,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2")] diff --git a/tests/incremental/hashes/inline_asm.rs b/tests/incremental/hashes/inline_asm.rs index 3118aa1356452..1570030dbeae3 100644 --- a/tests/incremental/hashes/inline_asm.rs +++ b/tests/incremental/hashes/inline_asm.rs @@ -33,9 +33,9 @@ pub fn change_template(_a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_template(_a: i32) -> i32 { @@ -66,9 +66,9 @@ pub fn change_output(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_output(a: i32) -> i32 { @@ -100,9 +100,9 @@ pub fn change_input(_a: i32, _b: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input(_a: i32, _b: i32) -> i32 { @@ -133,9 +133,9 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { @@ -166,9 +166,9 @@ pub fn change_clobber(_a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_clobber(_a: i32) -> i32 { @@ -201,9 +201,9 @@ pub fn change_options(_a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_options(_a: i32) -> i32 { diff --git a/tests/incremental/hashes/let_expressions.rs b/tests/incremental/hashes/let_expressions.rs index a835b8eef8ce7..62a91bf75f8a3 100644 --- a/tests/incremental/hashes/let_expressions.rs +++ b/tests/incremental/hashes/let_expressions.rs @@ -23,9 +23,9 @@ pub fn change_name() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_name() { let _y = 2u64; @@ -40,9 +40,9 @@ pub fn add_type() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_type() { let _x: u32 = 2u32; @@ -57,9 +57,9 @@ pub fn change_type() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_type() { let _x: u8 = 2; @@ -74,9 +74,9 @@ pub fn change_mutability_of_reference_type() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_reference_type() { let _x: &mut u64; @@ -91,9 +91,9 @@ pub fn change_mutability_of_slot() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -108,9 +108,9 @@ pub fn change_simple_binding_to_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_simple_binding_to_pattern() { let (_a, _b) = (0u8, 'x'); @@ -125,9 +125,9 @@ pub fn change_name_in_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_name_in_pattern() { let (_a, _c) = (1u8, 'y'); @@ -142,9 +142,9 @@ pub fn add_ref_in_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_ref_in_pattern() { let (ref _a, _b) = (1u8, 'y'); @@ -159,9 +159,9 @@ pub fn add_amp_in_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_amp_in_pattern() { let (&_a, _b) = (&1u8, 'y'); @@ -176,9 +176,9 @@ pub fn change_mutability_of_binding_in_pattern() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); @@ -193,9 +193,9 @@ pub fn add_initializer() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_initializer() { let _x: i16 = 3i16; @@ -210,9 +210,9 @@ pub fn change_initializer() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_initializer() { let _x = 5u16; diff --git a/tests/incremental/hashes/loop_expressions.rs b/tests/incremental/hashes/loop_expressions.rs index 13e37bd59f8e8..810ba877061c6 100644 --- a/tests/incremental/hashes/loop_expressions.rs +++ b/tests/incremental/hashes/loop_expressions.rs @@ -28,9 +28,9 @@ pub fn change_loop_body() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; @@ -53,9 +53,9 @@ pub fn add_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; @@ -78,9 +78,9 @@ pub fn add_loop_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; @@ -103,9 +103,9 @@ pub fn add_loop_label_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -130,9 +130,9 @@ pub fn change_break_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; @@ -157,9 +157,9 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -184,9 +184,9 @@ pub fn change_continue_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; @@ -211,9 +211,9 @@ pub fn change_continue_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, typeck, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, typeck, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/tests/incremental/hashes/match_expressions.rs b/tests/incremental/hashes/match_expressions.rs index ebcf1708a7aaa..c77ac27d49623 100644 --- a/tests/incremental/hashes/match_expressions.rs +++ b/tests/incremental/hashes/match_expressions.rs @@ -28,9 +28,9 @@ pub fn add_arm(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_arm(x: u32) -> u32 { match x { @@ -54,9 +54,9 @@ pub fn change_order_of_arms(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_order_of_arms(x: u32) -> u32 { match x { @@ -79,9 +79,9 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -104,9 +104,9 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -129,9 +129,9 @@ pub fn add_at_binding(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_at_binding(x: u32) -> u32 { match x { @@ -154,9 +154,9 @@ pub fn change_name_of_at_binding(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_name_of_at_binding(x: u32) -> u32 { match x { @@ -178,9 +178,9 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_simple_name_to_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -202,9 +202,9 @@ pub fn change_name_in_pattern(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_name_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -227,9 +227,9 @@ pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { // Ignore optimized_mir in cfail2, the only change to optimized MIR is a span. #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -250,9 +250,9 @@ pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -273,9 +273,9 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { match (&x, x & 1) { @@ -297,9 +297,9 @@ pub fn change_rhs_of_arm(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_rhs_of_arm(x: u32) -> u32 { match x { @@ -322,9 +322,9 @@ pub fn add_alternative_to_arm(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_alternative_to_arm(x: u32) -> u32 { match x { diff --git a/tests/incremental/hashes/panic_exprs.rs b/tests/incremental/hashes/panic_exprs.rs index 37d10d922c177..440a7b6fbf41f 100644 --- a/tests/incremental/hashes/panic_exprs.rs +++ b/tests/incremental/hashes/panic_exprs.rs @@ -18,7 +18,7 @@ // Indexing expression -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn indexing(slice: &[u8]) -> u8 { #[cfg(cfail1)] @@ -33,7 +33,7 @@ pub fn indexing(slice: &[u8]) -> u8 { // Arithmetic overflow plus -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_plus(val: i32) -> i32 { #[cfg(cfail1)] @@ -48,7 +48,7 @@ pub fn arithmetic_overflow_plus(val: i32) -> i32 { // Arithmetic overflow minus -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_minus(val: i32) -> i32 { #[cfg(cfail1)] @@ -63,7 +63,7 @@ pub fn arithmetic_overflow_minus(val: i32) -> i32 { // Arithmetic overflow mult -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_mult(val: i32) -> i32 { #[cfg(cfail1)] @@ -78,7 +78,7 @@ pub fn arithmetic_overflow_mult(val: i32) -> i32 { // Arithmetic overflow negation -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_negation(val: i32) -> i32 { #[cfg(cfail1)] @@ -93,7 +93,7 @@ pub fn arithmetic_overflow_negation(val: i32) -> i32 { // Division by zero -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn division_by_zero(val: i32) -> i32 { #[cfg(cfail1)] @@ -107,7 +107,7 @@ pub fn division_by_zero(val: i32) -> i32 { } // Division by zero -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn mod_by_zero(val: i32) -> i32 { #[cfg(cfail1)] @@ -122,7 +122,7 @@ pub fn mod_by_zero(val: i32) -> i32 { // shift left -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn shift_left(val: i32, shift: usize) -> i32 { #[cfg(cfail1)] @@ -137,7 +137,7 @@ pub fn shift_left(val: i32, shift: usize) -> i32 { // shift right -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn shift_right(val: i32, shift: usize) -> i32 { #[cfg(cfail1)] diff --git a/tests/incremental/hashes/statics.rs b/tests/incremental/hashes/statics.rs index 2adf05390bc4e..7e2ccc4ce6f20 100644 --- a/tests/incremental/hashes/statics.rs +++ b/tests/incremental/hashes/statics.rs @@ -26,7 +26,7 @@ static STATIC_VISIBILITY: u8 = 0; #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub static STATIC_VISIBILITY: u8 = 0; @@ -36,9 +36,9 @@ pub static STATIC_VISIBILITY: u8 = 0; static STATIC_MUTABILITY: u8 = 0; #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] static mut STATIC_MUTABILITY: u8 = 0; @@ -87,9 +87,9 @@ static STATIC_THREAD_LOCAL: u8 = 0; static STATIC_CHANGE_TYPE_1: i16 = 0; #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_1: u64 = 0; @@ -99,17 +99,17 @@ static STATIC_CHANGE_TYPE_1: u64 = 0; static STATIC_CHANGE_TYPE_2: Option = None; #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_2: Option = None; // Change value between simple literals -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_1: i16 = { #[cfg(any(cfail1,cfail4))] @@ -121,9 +121,9 @@ static STATIC_CHANGE_VALUE_1: i16 = { // Change value between expressions -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_2: i16 = { #[cfg(any(cfail1,cfail4))] @@ -133,9 +133,9 @@ static STATIC_CHANGE_VALUE_2: i16 = { { 1 + 2 } }; -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_3: i16 = { #[cfg(any(cfail1,cfail4))] @@ -145,9 +145,9 @@ static STATIC_CHANGE_VALUE_3: i16 = { { 2 * 3 } }; -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_4: i16 = { #[cfg(any(cfail1,cfail4))] @@ -169,15 +169,15 @@ mod static_change_type_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as Type; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff --git a/tests/incremental/hashes/struct_constructors.rs b/tests/incremental/hashes/struct_constructors.rs index eabb8683e0296..458f4d1a6d7de 100644 --- a/tests/incremental/hashes/struct_constructors.rs +++ b/tests/incremental/hashes/struct_constructors.rs @@ -34,9 +34,9 @@ pub fn change_field_value_regular_struct() -> RegularStruct { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { @@ -59,9 +59,9 @@ pub fn change_field_order_regular_struct() -> RegularStruct { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { @@ -90,9 +90,9 @@ pub fn add_field_regular_struct() -> RegularStruct { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -127,9 +127,9 @@ pub fn change_field_label_regular_struct() -> RegularStruct { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -164,9 +164,9 @@ pub fn change_constructor_path_regular_struct() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_regular_struct() { let _ = RegularStruct2 { @@ -185,9 +185,9 @@ pub mod change_constructor_path_indirectly_regular_struct { #[cfg(not(any(cfail1,cfail4)))] use super::RegularStruct2 as Struct; - #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> Struct { Struct { @@ -209,9 +209,9 @@ pub fn change_field_value_tuple_struct() -> TupleStruct { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 3) @@ -228,9 +228,9 @@ pub fn change_constructor_path_tuple_struct() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct2(0, 1, 2); @@ -245,9 +245,9 @@ pub mod change_constructor_path_indirectly_tuple_struct { #[cfg(not(any(cfail1,cfail4)))] use super::TupleStruct2 as Struct; - #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] - #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="fn_sig,opt_hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] pub fn function() -> Struct { Struct(0, 1, 2) diff --git a/tests/incremental/hashes/struct_defs.rs b/tests/incremental/hashes/struct_defs.rs index 6ea4d890e4d54..113ada2855d1e 100644 --- a/tests/incremental/hashes/struct_defs.rs +++ b/tests/incremental/hashes/struct_defs.rs @@ -51,9 +51,9 @@ struct LayoutC; struct TupleStructFieldType(i32); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. @@ -68,9 +68,9 @@ struct TupleStructFieldType( struct TupleStructAddField(i32); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct TupleStructAddField( i32, @@ -86,7 +86,7 @@ struct TupleStructFieldVisibility( char); #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] struct TupleStructFieldVisibility(pub char); @@ -97,9 +97,9 @@ struct TupleStructFieldVisibility(pub char); struct RecordStructFieldType { x: f32 } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. @@ -114,9 +114,9 @@ struct RecordStructFieldType { struct RecordStructFieldName { x: f32 } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct RecordStructFieldName { y: f32 } @@ -127,9 +127,9 @@ struct RecordStructFieldName { y: f32 } struct RecordStructAddField { x: f32 } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct RecordStructAddField { x: f32, @@ -144,7 +144,7 @@ struct RecordStructFieldVisibility { x: f32 } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] struct RecordStructFieldVisibility { pub x: f32 } @@ -155,9 +155,9 @@ struct RecordStructFieldVisibility { pub x: f32 } struct AddLifetimeParameter<'a>(&'a f32, &'a f64); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,type_of,generics_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,type_of,generics_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); @@ -168,9 +168,9 @@ struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddLifetimeParameterBound<'a, 'b: 'a>( &'a f32, @@ -181,9 +181,9 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>( struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddLifetimeParameterBoundWhereClause<'a, 'b>( &'a f32, @@ -197,9 +197,9 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>( struct AddTypeParameter(T1, T1); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddTypeParameter( // The field contains the parent's Generics, so it's dirty even though its @@ -215,9 +215,9 @@ struct AddTypeParameter( struct AddTypeParameterBound(T); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddTypeParameterBound( T @@ -228,9 +228,9 @@ struct AddTypeParameterBound( struct AddTypeParameterBoundWhereClause(T); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddTypeParameterBoundWhereClause( T @@ -257,7 +257,7 @@ struct Visibility; #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub struct Visibility; @@ -271,9 +271,9 @@ mod tuple_struct_change_field_type_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct TupleStruct( FieldType @@ -288,9 +288,9 @@ mod record_struct_change_field_type_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct RecordStruct { _x: FieldType @@ -310,9 +310,9 @@ mod change_trait_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct Struct(T); } @@ -324,9 +324,9 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct Struct(T) where T : Trait; } diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs index 0a5eba7397722..60faf3c47d69d 100644 --- a/tests/incremental/hashes/trait_defs.rs +++ b/tests/incremental/hashes/trait_defs.rs @@ -30,7 +30,7 @@ trait TraitVisibility { } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub trait TraitVisibility { } @@ -41,9 +41,9 @@ pub trait TraitVisibility { } trait TraitUnsafety { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] unsafe trait TraitUnsafety { } @@ -55,9 +55,9 @@ trait TraitAddMethod { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait TraitAddMethod { fn method(); @@ -72,9 +72,9 @@ trait TraitChangeMethodName { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodName { fn methodChanged(); @@ -85,9 +85,9 @@ trait TraitChangeMethodName { // Add return type to method #[cfg(any(cfail1,cfail4))] trait TraitAddReturnType { - //----------------------------------------------------------- + //--------------------------------------------------------------- //-------------------------- - //----------------------------------------------------------- + //--------------------------------------------------------------- //-------------------------- fn method() ; } @@ -98,9 +98,9 @@ trait TraitAddReturnType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddReturnType { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> u32; } @@ -110,9 +110,9 @@ trait TraitAddReturnType { // Change return type of method #[cfg(any(cfail1,cfail4))] trait TraitChangeReturnType { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method() -> u32; } @@ -123,9 +123,9 @@ trait TraitChangeReturnType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeReturnType { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> u64; } @@ -135,9 +135,9 @@ trait TraitChangeReturnType { // Add parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddParameterToMethod { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method( ); } @@ -148,9 +148,9 @@ trait TraitAddParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddParameterToMethod { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: u32); } @@ -161,15 +161,15 @@ trait TraitAddParameterToMethod { #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterName { //------------------------------------------------------ - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- fn method(a: u32); - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------ + //---------------------------------------------------------------------- //-------------------------- fn with_default(x: i32) {} } @@ -181,15 +181,15 @@ trait TraitChangeMethodParameterName { #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(b: u32); - #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn with_default(y: i32) {} } @@ -199,9 +199,9 @@ trait TraitChangeMethodParameterName { // Change type of method parameter (i32 => i64) #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterType { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method(a: i32); } @@ -212,9 +212,9 @@ trait TraitChangeMethodParameterType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterType { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: i64); } @@ -224,9 +224,9 @@ trait TraitChangeMethodParameterType { // Change type of method parameter (&i32 => &mut i32) #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterTypeRef { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method(a: & i32); } @@ -237,9 +237,9 @@ trait TraitChangeMethodParameterTypeRef { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterTypeRef { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: &mut i32); } @@ -249,9 +249,9 @@ trait TraitChangeMethodParameterTypeRef { // Change order of method parameters #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParametersOrder { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method(a: i32, b: i64); } @@ -262,9 +262,9 @@ trait TraitChangeMethodParametersOrder { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParametersOrder { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(b: i64, a: i32); } @@ -274,9 +274,9 @@ trait TraitChangeMethodParametersOrder { // Add default implementation to method #[cfg(any(cfail1,cfail4))] trait TraitAddMethodAutoImplementation { - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- fn method() ; } @@ -287,9 +287,9 @@ trait TraitAddMethodAutoImplementation { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddMethodAutoImplementation { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() {} } @@ -304,9 +304,9 @@ trait TraitChangeOrderOfMethods { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeOrderOfMethods { fn method1(); @@ -318,9 +318,9 @@ trait TraitChangeOrderOfMethods { // Change mode of self parameter #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfRefToMut { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method(& self); } @@ -331,9 +331,9 @@ trait TraitChangeModeSelfRefToMut { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfRefToMut { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(&mut self); } @@ -342,9 +342,9 @@ trait TraitChangeModeSelfRefToMut { #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToMut: Sized { - // ------------------------------------------------------------------------ + // ---------------------------------------------------------------------------- // ------------------------- - // ------------------------------------------------------------------------ + // ---------------------------------------------------------------------------- // ------------------------- fn method( self) {} } @@ -355,9 +355,9 @@ trait TraitChangeModeSelfOwnToMut: Sized { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToMut: Sized { - #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(mut self) {} } @@ -366,9 +366,9 @@ trait TraitChangeModeSelfOwnToMut: Sized { #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToRef { - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // ------------------------- fn method( self); } @@ -379,9 +379,9 @@ trait TraitChangeModeSelfOwnToRef { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToRef { - #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(&self); } @@ -391,9 +391,9 @@ trait TraitChangeModeSelfOwnToRef { // Add unsafe modifier to method #[cfg(any(cfail1,cfail4))] trait TraitAddUnsafeModifier { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method(); } @@ -404,9 +404,9 @@ trait TraitAddUnsafeModifier { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddUnsafeModifier { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] unsafe fn method(); } @@ -416,9 +416,9 @@ trait TraitAddUnsafeModifier { // Add extern modifier to method #[cfg(any(cfail1,cfail4))] trait TraitAddExternModifier { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method(); } @@ -429,9 +429,9 @@ trait TraitAddExternModifier { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddExternModifier { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] extern "C" fn method(); } @@ -441,9 +441,9 @@ trait TraitAddExternModifier { // Change extern "C" to extern "stdcall" #[cfg(any(cfail1,cfail4))] trait TraitChangeExternCToRustIntrinsic { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- extern "C" fn method(); } @@ -454,9 +454,9 @@ trait TraitChangeExternCToRustIntrinsic { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeExternCToRustIntrinsic { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] extern "stdcall" fn method(); } @@ -466,10 +466,10 @@ trait TraitChangeExternCToRustIntrinsic { // Add type parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddTypeParameterToMethod { - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // --------------- // ------------------------- - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // --------------- // ------------------------- fn method (); @@ -481,10 +481,10 @@ trait TraitAddTypeParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToMethod { - #[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of,type_of", + #[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of,type_of", + #[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); @@ -495,9 +495,9 @@ trait TraitAddTypeParameterToMethod { // Add lifetime parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeParameterToMethod { - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------------------- + // -------------------------------------------------------------------------- // ------------------------- fn method (); } @@ -508,9 +508,9 @@ trait TraitAddLifetimeParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToMethod { - #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method<'a>(); } @@ -524,9 +524,9 @@ trait ReferencedTrait1 { } // Add trait bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToMethodTypeParameter { - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- fn method(); } @@ -537,9 +537,9 @@ trait TraitAddTraitBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -549,9 +549,9 @@ trait TraitAddTraitBoundToMethodTypeParameter { // Add builtin bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundToMethodTypeParameter { - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- fn method(); } @@ -559,12 +559,12 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -575,12 +575,12 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToMethodLifetimeParameter { // ----------- - // ------------------------------------------------------------------- + // ----------------------------------------------------------------------- // -------------- // // ------------------------- // ----------- - // ------------------------------------------------------------------- + // ----------------------------------------------------------------------- // -------------- // // ------------------------- @@ -594,12 +594,12 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_clean( - except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="opt_hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="opt_hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -611,9 +611,9 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { // Add second trait bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddSecondTraitBoundToMethodTypeParameter { - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- fn method(); } @@ -624,9 +624,9 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -636,9 +636,9 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { // Add second builtin bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- fn method(); } @@ -649,9 +649,9 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -662,12 +662,12 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { // ----------- - // ------------------------------------------------------------------- + // ----------------------------------------------------------------------- // -------------- // // ------------------------- // ----------- - // ------------------------------------------------------------------- + // ----------------------------------------------------------------------- // -------------- // // ------------------------- @@ -681,12 +681,12 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_clean( - except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="opt_hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="opt_hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -710,9 +710,9 @@ trait TraitAddAssociatedType { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedType { #[rustc_clean(cfg="cfail3")] @@ -731,9 +731,9 @@ trait TraitAddAssociatedType { // Add trait bound to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToAssociatedType { - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- type Associated ; @@ -749,9 +749,9 @@ trait TraitAddTraitBoundToAssociatedType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToAssociatedType { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated: ReferencedTrait0; @@ -763,9 +763,9 @@ trait TraitAddTraitBoundToAssociatedType { // Add lifetime bound to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToAssociatedType<'a> { - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- type Associated ; @@ -778,9 +778,9 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToAssociatedType<'a> { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated: 'a; @@ -792,9 +792,9 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { // Add default to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddDefaultToAssociatedType { - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- type Associated ; @@ -807,9 +807,9 @@ trait TraitAddDefaultToAssociatedType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddDefaultToAssociatedType { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated = ReferenceType0; @@ -825,9 +825,9 @@ trait TraitAddAssociatedConstant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedConstant { const Value: u32; @@ -840,9 +840,9 @@ trait TraitAddAssociatedConstant { // Add initializer to associated constant #[cfg(any(cfail1,cfail4))] trait TraitAddInitializerToAssociatedConstant { - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- const Value: u32 ; @@ -859,9 +859,9 @@ trait TraitAddInitializerToAssociatedConstant { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddInitializerToAssociatedConstant { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] const Value: u32 = 1; @@ -877,9 +877,9 @@ trait TraitAddInitializerToAssociatedConstant { // Change type of associated constant #[cfg(any(cfail1,cfail4))] trait TraitChangeTypeOfAssociatedConstant { - // ----------------------------------------------------------- + // --------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------- + // --------------------------------------------------------------- // ------------------------- const Value: u32; @@ -896,9 +896,9 @@ trait TraitChangeTypeOfAssociatedConstant { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTypeOfAssociatedConstant { - #[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] const Value: f64; @@ -916,9 +916,9 @@ trait TraitChangeTypeOfAssociatedConstant { trait TraitAddSuperTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSuperTrait : ReferencedTrait0 { } @@ -929,9 +929,9 @@ trait TraitAddSuperTrait : ReferencedTrait0 { } trait TraitAddBuiltiBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltiBound : Send { } @@ -942,9 +942,9 @@ trait TraitAddBuiltiBound : Send { } trait TraitAddStaticLifetimeBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticLifetimeBound : 'static { } @@ -955,9 +955,9 @@ trait TraitAddStaticLifetimeBound : 'static { } trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } @@ -965,9 +965,9 @@ trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } @@ -978,9 +978,9 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } @@ -988,9 +988,9 @@ trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } @@ -1001,9 +1001,9 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } @@ -1011,9 +1011,9 @@ trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } @@ -1024,9 +1024,9 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } trait TraitAddTypeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToTrait { } @@ -1037,9 +1037,9 @@ trait TraitAddTypeParameterToTrait { } trait TraitAddLifetimeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToTrait<'a> { } @@ -1050,9 +1050,9 @@ trait TraitAddLifetimeParameterToTrait<'a> { } trait TraitAddTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToTypeParameterOfTrait { } @@ -1063,9 +1063,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait { } trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } @@ -1076,9 +1076,9 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } @@ -1089,9 +1089,9 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } trait TraitAddBuiltinBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToTypeParameterOfTrait { } @@ -1102,9 +1102,9 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait { } trait TraitAddSecondTypeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTypeParameterToTrait { } @@ -1115,9 +1115,9 @@ trait TraitAddSecondTypeParameterToTrait { } trait TraitAddSecondLifetimeParameterToTrait<'a> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } @@ -1128,9 +1128,9 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } @@ -1141,9 +1141,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } @@ -1154,9 +1154,9 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { } @@ -1167,9 +1167,9 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } @@ -1185,9 +1185,9 @@ struct ReferenceType1 {} trait TraitAddTraitBoundToTypeParameterOfTraitWhere { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } @@ -1198,9 +1198,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } @@ -1211,9 +1211,9 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { } @@ -1224,9 +1224,9 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } @@ -1237,9 +1237,9 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 + ReferencedTrait1 { } @@ -1251,9 +1251,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } @@ -1264,9 +1264,9 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { } @@ -1277,9 +1277,9 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } @@ -1296,9 +1296,9 @@ mod change_return_type_of_method_indirectly_use { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeReturnType { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> ReturnType; } @@ -1318,9 +1318,9 @@ mod change_method_parameter_type_indirectly_by_use { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeArgType { - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: ArgType); } @@ -1340,9 +1340,9 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeBoundOfMethodTypeParameter { - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: T); } @@ -1363,9 +1363,9 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeBoundOfMethodTypeParameterWhere { - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: T) where T: Bound; } @@ -1380,9 +1380,9 @@ mod change_method_type_parameter_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTraitBound { fn method(a: T); @@ -1399,9 +1399,9 @@ mod change_method_type_parameter_bound_indirectly_where { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTraitBoundWhere where T: Bound { fn method(a: T); diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 028598244de73..2e97a35d36bb7 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -32,9 +32,9 @@ impl ChangeMethodNameTrait for Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait ChangeMethodNameTrait { #[rustc_clean(cfg="cfail3")] @@ -43,9 +43,9 @@ pub trait ChangeMethodNameTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodNameTrait for Foo { #[rustc_clean(cfg="cfail3")] @@ -63,9 +63,9 @@ pub trait ChangeMethodBodyTrait { #[cfg(any(cfail1,cfail4))] impl ChangeMethodBodyTrait for Foo { - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------- + // -------------------------------------------------------------- // ------------------------- fn method_name() { // @@ -78,9 +78,9 @@ impl ChangeMethodBodyTrait for Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodBodyTrait for Foo { - #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name() { () @@ -97,9 +97,9 @@ pub trait ChangeMethodBodyTraitInlined { #[cfg(any(cfail1,cfail4))] impl ChangeMethodBodyTraitInlined for Foo { - // ------------------------------------------------------------------------ + // ---------------------------------------------------------------------------- // ------------------------- - // ------------------------------------------------------------------------ + // ---------------------------------------------------------------------------- // ------------------------- #[inline] fn method_name() { @@ -113,9 +113,9 @@ impl ChangeMethodBodyTraitInlined for Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodBodyTraitInlined for Foo { - #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] #[inline] fn method_name() { @@ -141,18 +141,18 @@ pub trait ChangeMethodSelfnessTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_clean( - except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="opt_hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="opt_hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -179,18 +179,18 @@ pub trait RemoveMethodSelfnessTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_clean( - except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="opt_hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="opt_hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -206,9 +206,9 @@ pub trait ChangeMethodSelfmutnessTrait { #[cfg(any(cfail1,cfail4))] impl ChangeMethodSelfmutnessTrait for Foo { - // ------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------- // ------------------------- - // ------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------- // ------------------------- fn method_name(& self) {} } @@ -224,9 +224,9 @@ pub trait ChangeMethodSelfmutnessTrait { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfmutnessTrait for Foo { - #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name(&mut self) {} } @@ -249,9 +249,9 @@ pub trait ChangeItemKindTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeItemKindTrait for Foo { type name = (); @@ -277,9 +277,9 @@ pub trait RemoveItemTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl RemoveItemTrait for Foo { type TypeName = (); @@ -304,9 +304,9 @@ pub trait AddItemTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddItemTrait for Foo { type TypeName = (); @@ -317,9 +317,9 @@ impl AddItemTrait for Foo { #[cfg(any(cfail1,cfail4))] pub trait ChangeHasValueTrait { - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- - //---------------------------------------------------- + //-------------------------------------------------------- //-------------------------- fn method_name() ; } @@ -335,9 +335,9 @@ impl ChangeHasValueTrait for Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait ChangeHasValueTrait { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name() { } } @@ -359,9 +359,9 @@ pub trait AddDefaultTrait { #[cfg(any(cfail1,cfail4))] impl AddDefaultTrait for Foo { - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- - // --------------------------------------------------- + // ------------------------------------------------------- // ------------------------- fn method_name() { } } @@ -372,9 +372,9 @@ impl AddDefaultTrait for Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddDefaultTrait for Foo { - #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] default fn method_name() { } } @@ -388,9 +388,9 @@ pub trait AddArgumentTrait { #[cfg(any(cfail1,cfail4))] impl AddArgumentTrait for Foo { - // ------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------- // ------------------------- - // ------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------- // ------------------------- fn method_name(&self ) { } } @@ -406,9 +406,9 @@ pub trait AddArgumentTrait { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddArgumentTrait for Foo { - #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name(&self, _x: u32) { } } @@ -422,9 +422,9 @@ pub trait ChangeArgumentTypeTrait { #[cfg(any(cfail1,cfail4))] impl ChangeArgumentTypeTrait for Foo { - // ------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------- // ------------------------- - // ------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------- // ------------------------- fn method_name(&self, _x: u32 ) { } } @@ -440,9 +440,9 @@ pub trait ChangeArgumentTypeTrait { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeArgumentTypeTrait for Foo { - #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name(&self, _x: char) { } } @@ -462,18 +462,18 @@ impl AddTypeParameterToImpl for Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddTypeParameterToImpl for Bar { #[rustc_clean( - except="hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", + except="opt_hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", + except="opt_hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -493,9 +493,9 @@ impl ChangeSelfTypeOfImpl for u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,impl_trait_ref", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeSelfTypeOfImpl for u64 { #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")] @@ -518,9 +518,9 @@ impl AddLifetimeBoundToImplParameter for T { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddLifetimeBoundToImplParameter for T { #[rustc_clean(cfg="cfail2")] @@ -543,9 +543,9 @@ impl AddTraitBoundToImplParameter for T { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddTraitBoundToImplParameter for T { #[rustc_clean(cfg="cfail2")] diff --git a/tests/incremental/hashes/type_defs.rs b/tests/incremental/hashes/type_defs.rs index 206c0595d5464..6b0dac1fe69b5 100644 --- a/tests/incremental/hashes/type_defs.rs +++ b/tests/incremental/hashes/type_defs.rs @@ -24,7 +24,7 @@ type ChangePrimitiveType = i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangePrimitiveType = i64; @@ -35,7 +35,7 @@ type ChangePrimitiveType = i64; type ChangeMutability = &'static i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeMutability = &'static mut i32; @@ -46,7 +46,7 @@ type ChangeMutability = &'static mut i32; type ChangeLifetime<'a> = (&'static i32, &'a i32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeLifetime<'a> = (&'a i32, &'a i32); @@ -60,7 +60,7 @@ struct Struct2; type ChangeTypeStruct = Struct1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeStruct = Struct2; @@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2; type ChangeTypeTuple = (u32, u64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeTuple = (u32, i64); @@ -91,7 +91,7 @@ enum Enum2 { type ChangeTypeEnum = Enum1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeEnum = Enum2; @@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2; type AddTupleField = (i32, i64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTupleField = (i32, i64, i16); @@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16); type ChangeNestedTupleField = (i32, (i64, i16)); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeNestedTupleField = (i32, (i64, i8)); @@ -124,7 +124,7 @@ type ChangeNestedTupleField = (i32, (i64, i8)); type AddTypeParam = (T1, T1); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTypeParam = (T1, T2); @@ -135,7 +135,7 @@ type AddTypeParam = (T1, T2); type AddTypeParamBound = (T1, u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTypeParamBound = (T1, u32); @@ -146,7 +146,7 @@ type AddTypeParamBound = (T1, u32); type AddTypeParamBoundWhereClause where T1: Clone = (T1, u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); @@ -157,7 +157,7 @@ type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); type AddLifetimeParam<'a> = (&'a u32, &'a u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); @@ -168,7 +168,7 @@ type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32); @@ -181,7 +181,7 @@ where 'b: 'a = (&'a u32, &'b u32, &'c u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> where 'b: 'a, @@ -200,7 +200,7 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly = (T, u32); } @@ -214,7 +214,7 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly where T : Trait = (T, u32); } diff --git a/tests/incremental/hashes/unary_and_binary_exprs.rs b/tests/incremental/hashes/unary_and_binary_exprs.rs index 58af51eef077f..3d48f2d28a37b 100644 --- a/tests/incremental/hashes/unary_and_binary_exprs.rs +++ b/tests/incremental/hashes/unary_and_binary_exprs.rs @@ -24,9 +24,9 @@ pub fn const_negation() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn const_negation() -> i32 { -1 @@ -41,9 +41,9 @@ pub fn const_bitwise_not() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn const_bitwise_not() -> i32 { !99 @@ -58,9 +58,9 @@ pub fn var_negation(x: i32, y: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn var_negation(x: i32, y: i32) -> i32 { -y @@ -75,9 +75,9 @@ pub fn var_bitwise_not(x: i32, y: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn var_bitwise_not(x: i32, y: i32) -> i32 { !y @@ -92,9 +92,9 @@ pub fn var_deref(x: &i32, y: &i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn var_deref(x: &i32, y: &i32) -> i32 { *y @@ -109,9 +109,9 @@ pub fn first_const_add() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn first_const_add() -> i32 { 2 + 3 @@ -126,9 +126,9 @@ pub fn second_const_add() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn second_const_add() -> i32 { 1 + 3 @@ -143,9 +143,9 @@ pub fn first_var_add(a: i32, b: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn first_var_add(a: i32, b: i32) -> i32 { b + 2 @@ -160,9 +160,9 @@ pub fn second_var_add(a: i32, b: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn second_var_add(a: i32, b: i32) -> i32 { 1 + b @@ -177,9 +177,9 @@ pub fn plus_to_minus(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn plus_to_minus(a: i32) -> i32 { 1 - a @@ -194,9 +194,9 @@ pub fn plus_to_mult(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn plus_to_mult(a: i32) -> i32 { 1 * a @@ -211,9 +211,9 @@ pub fn plus_to_div(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn plus_to_div(a: i32) -> i32 { 1 / a @@ -228,9 +228,9 @@ pub fn plus_to_mod(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn plus_to_mod(a: i32) -> i32 { 1 % a @@ -245,9 +245,9 @@ pub fn and_to_or(a: bool, b: bool) -> bool { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn and_to_or(a: bool, b: bool) -> bool { a || b @@ -262,9 +262,9 @@ pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { 1 | a @@ -279,9 +279,9 @@ pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { 1 ^ a @@ -296,9 +296,9 @@ pub fn bitwise_and_to_lshift(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_lshift(a: i32) -> i32 { a << 1 @@ -313,9 +313,9 @@ pub fn bitwise_and_to_rshift(a: i32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_rshift(a: i32) -> i32 { a >> 1 @@ -330,9 +330,9 @@ pub fn eq_to_uneq(a: i32) -> bool { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn eq_to_uneq(a: i32) -> bool { a != 1 @@ -347,9 +347,9 @@ pub fn eq_to_lt(a: i32) -> bool { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn eq_to_lt(a: i32) -> bool { a < 1 @@ -364,9 +364,9 @@ pub fn eq_to_gt(a: i32) -> bool { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn eq_to_gt(a: i32) -> bool { a > 1 @@ -381,9 +381,9 @@ pub fn eq_to_le(a: i32) -> bool { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn eq_to_le(a: i32) -> bool { a <= 1 @@ -398,9 +398,9 @@ pub fn eq_to_ge(a: i32) -> bool { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn eq_to_ge(a: i32) -> bool { a >= 1 @@ -417,9 +417,9 @@ pub fn type_cast(a: u8) -> u64 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir,typeck", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir,typeck", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn type_cast(a: u8) -> u64 { let b = a as u32; @@ -436,9 +436,9 @@ pub fn value_cast(a: u32) -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn value_cast(a: u32) -> i32 { 2 as i32 @@ -456,9 +456,9 @@ pub fn place() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn place() -> i32 { let mut x = 10; @@ -478,9 +478,9 @@ pub fn rvalue() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn rvalue() -> i32 { let mut x = 10; @@ -497,9 +497,9 @@ pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { s[j] diff --git a/tests/incremental/hashes/while_let_loops.rs b/tests/incremental/hashes/while_let_loops.rs index c81b0d0afb811..64ba3f6e7ef83 100644 --- a/tests/incremental/hashes/while_let_loops.rs +++ b/tests/incremental/hashes/while_let_loops.rs @@ -28,9 +28,9 @@ pub fn change_loop_body() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; @@ -53,9 +53,9 @@ pub fn change_loop_condition() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_loop_condition() { let mut _x = 0; @@ -78,9 +78,9 @@ pub fn add_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; @@ -103,9 +103,9 @@ pub fn add_loop_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; @@ -128,9 +128,9 @@ pub fn add_loop_label_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -155,9 +155,9 @@ pub fn change_break_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; @@ -180,9 +180,9 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -207,9 +207,9 @@ pub fn change_continue_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; @@ -234,9 +234,9 @@ pub fn change_continue_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/tests/incremental/hashes/while_loops.rs b/tests/incremental/hashes/while_loops.rs index 077d76fdd43a1..534f61b84bdee 100644 --- a/tests/incremental/hashes/while_loops.rs +++ b/tests/incremental/hashes/while_loops.rs @@ -28,9 +28,9 @@ pub fn change_loop_body() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; @@ -53,9 +53,9 @@ pub fn change_loop_condition() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_loop_condition() { let mut _x = 0; @@ -78,9 +78,9 @@ pub fn add_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; @@ -103,9 +103,9 @@ pub fn add_loop_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; @@ -128,9 +128,9 @@ pub fn add_loop_label_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -155,9 +155,9 @@ pub fn change_break_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; @@ -182,9 +182,9 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -209,9 +209,9 @@ pub fn change_continue_label() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; @@ -236,9 +236,9 @@ pub fn change_continue_to_break() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/tests/incremental/hygiene/auxiliary/cached_hygiene.rs b/tests/incremental/hygiene/auxiliary/cached_hygiene.rs index b31f60e972bf0..c1fd47cb2bb46 100644 --- a/tests/incremental/hygiene/auxiliary/cached_hygiene.rs +++ b/tests/incremental/hygiene/auxiliary/cached_hygiene.rs @@ -13,7 +13,7 @@ macro_rules! first_macro { } } -#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")] +#[rustc_clean(except="opt_hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")] #[inline(always)] pub fn changed_fn() { // This will cause additional hygiene to be generate, diff --git a/tests/incremental/ich_nested_items.rs b/tests/incremental/ich_nested_items.rs index 379c09575edfb..f0310e94015c0 100644 --- a/tests/incremental/ich_nested_items.rs +++ b/tests/incremental/ich_nested_items.rs @@ -8,7 +8,7 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#[rustc_clean(except = "hir_owner_nodes", cfg = "cfail2")] +#[rustc_clean(except = "opt_hir_owner_nodes", cfg = "cfail2")] pub fn foo() { #[cfg(cfail1)] pub fn baz() {} // order is different... diff --git a/tests/incremental/ich_resolve_results.rs b/tests/incremental/ich_resolve_results.rs index e6ab6bcebae09..9b5afcd801216 100644 --- a/tests/incremental/ich_resolve_results.rs +++ b/tests/incremental/ich_resolve_results.rs @@ -30,13 +30,13 @@ mod mod3 { use mod2::Foo; #[rustc_clean(cfg="rpass2")] - #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="rpass3")] fn in_expr() { Foo(0); } #[rustc_clean(cfg="rpass2")] - #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")] + #[rustc_clean(except="opt_hir_owner_nodes,typeck", cfg="rpass3")] fn in_type() { test::(); } diff --git a/tests/incremental/source_loc_macros.rs b/tests/incremental/source_loc_macros.rs index e5f04e5dc5818..16ad4d1899e94 100644 --- a/tests/incremental/source_loc_macros.rs +++ b/tests/incremental/source_loc_macros.rs @@ -22,7 +22,7 @@ fn file_same() { let _ = file!(); } -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="rpass2")] fn line_different() { #[cfg(rpass1)] { @@ -34,7 +34,7 @@ fn line_different() { } } -#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")] +#[rustc_clean(except="opt_hir_owner_nodes,optimized_mir", cfg="rpass2")] fn col_different() { #[cfg(rpass1)] { diff --git a/tests/incremental/string_constant.rs b/tests/incremental/string_constant.rs index 47cd100b13691..325b200e69b49 100644 --- a/tests/incremental/string_constant.rs +++ b/tests/incremental/string_constant.rs @@ -17,7 +17,7 @@ pub mod x { } #[cfg(cfail2)] - #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail2")] + #[rustc_clean(except = "opt_hir_owner_nodes,promoted_mir", cfg = "cfail2")] pub fn x() { println!("{}", "2"); } diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir new file mode 100644 index 0000000000000..1fae40c5f4004 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (_1.1: i32); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(_1.1: i32); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir new file mode 100644 index 0000000000000..1fae40c5f4004 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (_1.1: i32); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(_1.1: i32); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir new file mode 100644 index 0000000000000..9886d6f68a41c --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (*(_1.1: &i32)); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(*(_1.1: &i32)); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir new file mode 100644 index 0000000000000..9886d6f68a41c --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (*(_1.1: &i32)); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(*(_1.1: &i32)); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir new file mode 100644 index 0000000000000..7df4eb492605b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir @@ -0,0 +1,10 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move + +fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + + bb0: { + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir new file mode 100644 index 0000000000000..7df4eb492605b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir @@ -0,0 +1,10 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move + +fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + + bb0: { + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir new file mode 100644 index 0000000000000..517b8d0dd883b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir @@ -0,0 +1,16 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut + +fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + debug a => _2; + debug b => ((*_1).0: i32); + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + let mut _3: &i32; + + bb0: { + StorageLive(_3); + _3 = &((*_1).0: i32); + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 }; + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir new file mode 100644 index 0000000000000..517b8d0dd883b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir @@ -0,0 +1,16 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut + +fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + debug a => _2; + debug b => ((*_1).0: i32); + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + let mut _3: &i32; + + bb0: { + StorageLive(_3); + _3 = &((*_1).0: i32); + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 }; + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs new file mode 100644 index 0000000000000..ef3bdaaa145a3 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.rs @@ -0,0 +1,46 @@ +// edition:2021 +// skip-filecheck +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(async_closure, noop_waker, async_fn_traits)] + +use std::future::Future; +use std::ops::{AsyncFnMut, AsyncFnOnce}; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +async fn call_mut(f: &mut impl AsyncFnMut(i32)) { + f(0).await; +} + +async fn call_once(f: impl AsyncFnOnce(i32)) { + f(1).await; +} + +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir +fn main() { + block_on(async { + let b = 2i32; + let mut async_closure = async move |a: i32| { + let a = &a; + let b = &b; + }; + call_mut(&mut async_closure).await; + call_once(async_closure).await; + }); +} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 3c0d4008c9018..9c8cf8763fdf1 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -5,6 +5,7 @@ ty: Coroutine( DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), [ + (), std::future::ResumeTy, (), (), @@ -22,6 +23,7 @@ ty: Coroutine( DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), [ + (), std::future::ResumeTy, (), (), diff --git a/tests/mir-opt/building/custom/assume.assume_constant.built.after.mir b/tests/mir-opt/building/custom/assume.assume_constant.built.after.mir new file mode 100644 index 0000000000000..8e70d0a1e9b11 --- /dev/null +++ b/tests/mir-opt/building/custom/assume.assume_constant.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `assume_constant` after built + +fn assume_constant() -> () { + let mut _0: (); + + bb0: { + assume(const true); + return; + } +} diff --git a/tests/mir-opt/building/custom/assume.assume_local.built.after.mir b/tests/mir-opt/building/custom/assume.assume_local.built.after.mir new file mode 100644 index 0000000000000..7ea1fcd30c2ec --- /dev/null +++ b/tests/mir-opt/building/custom/assume.assume_local.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `assume_local` after built + +fn assume_local(_1: bool) -> () { + let mut _0: (); + + bb0: { + assume(_1); + return; + } +} diff --git a/tests/mir-opt/building/custom/assume.assume_place.built.after.mir b/tests/mir-opt/building/custom/assume.assume_place.built.after.mir new file mode 100644 index 0000000000000..ce914618d3dce --- /dev/null +++ b/tests/mir-opt/building/custom/assume.assume_place.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `assume_place` after built + +fn assume_place(_1: (bool, u8)) -> () { + let mut _0: (); + + bb0: { + assume((_1.0: bool)); + return; + } +} diff --git a/tests/mir-opt/building/custom/assume.rs b/tests/mir-opt/building/custom/assume.rs new file mode 100644 index 0000000000000..a477e12f0e03d --- /dev/null +++ b/tests/mir-opt/building/custom/assume.rs @@ -0,0 +1,44 @@ +// skip-filecheck +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR assume.assume_local.built.after.mir +#[custom_mir(dialect = "built")] +fn assume_local(x: bool) { + mir!( + { + Assume(x); + Return() + } + ) +} + +// EMIT_MIR assume.assume_place.built.after.mir +#[custom_mir(dialect = "built")] +fn assume_place(p: (bool, u8)) { + mir!( + { + Assume(p.0); + Return() + } + ) +} + +// EMIT_MIR assume.assume_constant.built.after.mir +#[custom_mir(dialect = "built")] +fn assume_constant() { + mir!( + { + Assume(true); + Return() + } + ) +} + +fn main() { + assume_local(true); + assume_place((true, 50)); + assume_constant(); +} diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs index 43ecbbed186f6..f15d15bfcb268 100644 --- a/tests/mir-opt/const_prop/offset_of.rs +++ b/tests/mir-opt/const_prop/offset_of.rs @@ -2,7 +2,7 @@ // unit-test: GVN // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] use std::marker::PhantomData; use std::mem::offset_of; diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir index 25bffbe248820..7214b01c60164 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir @@ -1,25 +1,4 @@ // MIR for `main::{closure#0}` 0 coroutine_drop -/* coroutine_layout = CoroutineLayout { - field_tys: { - _0: CoroutineSavedTy { - ty: std::string::String, - source_info: SourceInfo { - span: $DIR/coroutine_drop_cleanup.rs:12:13: 12:15 (#0), - scope: scope[0], - }, - ignore_for_traits: false, - }, - }, - variant_fields: { - Unresumed(0): [], - Returned (1): [], - Panicked (2): [], - Suspend0 (3): [_0], - }, - storage_conflicts: BitMatrix(1x1) { - (_0, _0), - }, -} */ fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { let mut _0: (); diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir index 2eac754b15ccd..00769a493b5a1 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir @@ -1,25 +1,4 @@ // MIR for `main::{closure#0}` 0 coroutine_drop -/* coroutine_layout = CoroutineLayout { - field_tys: { - _0: CoroutineSavedTy { - ty: std::string::String, - source_info: SourceInfo { - span: $DIR/coroutine_drop_cleanup.rs:12:13: 12:15 (#0), - scope: scope[0], - }, - ignore_for_traits: false, - }, - }, - variant_fields: { - Unresumed(0): [], - Returned (1): [], - Panicked (2): [], - Suspend0 (3): [_0], - }, - storage_conflicts: BitMatrix(1x1) { - (_0, _0), - }, -} */ fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { let mut _0: (); diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs index 3d420f930076d..8f0cc489a5bb7 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/array_index.rs @@ -1,9 +1,21 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR array_index.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main() -> () { fn main() { + // CHECK: let mut [[array_lit:_.*]]: [u32; 4]; + // CHECK: debug x => [[x:_.*]]; + + // CHECK: [[array_lit]] = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ + // CHECK: {{_.*}} = const 4_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true + // CHECK: [[x]] = [[array_lit]][2 of 3]; let x: u32 = [0, 1, 2, 3][2]; } diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs index 2605c7019e6f4..c9be1d65b0302 100644 --- a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs @@ -1,11 +1,18 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR boolean_identities.test.DataflowConstProp.diff + +// CHECK-LABEL: fn test( pub fn test(x: bool, y: bool) -> bool { + // CHECK-NOT: BitAnd( + // CHECK-NOT: BitOr( (y | true) & (x & false) + // CHECK: _0 = const false; + // CHECK-NOT: BitAnd( + // CHECK-NOT: BitOr( } +// CHECK-LABEL: fn main( fn main() { test(true, false); } diff --git a/tests/mir-opt/dataflow-const-prop/cast.rs b/tests/mir-opt/dataflow-const-prop/cast.rs index c87872609dcf7..298ff49803936 100644 --- a/tests/mir-opt/dataflow-const-prop/cast.rs +++ b/tests/mir-opt/dataflow-const-prop/cast.rs @@ -1,8 +1,14 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR cast.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + + // CHECK: [[a]] = const 257_i32; let a = 257; + // CHECK: [[b]] = const 2_u8; let b = a as u8 + 1; } diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs index f7fac8890a057..30b0afa8334dd 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.rs +++ b/tests/mir-opt/dataflow-const-prop/checked.rs @@ -1,15 +1,32 @@ -// skip-filecheck // unit-test: DataflowConstProp // compile-flags: -Coverflow-checks=on // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR checked.main.DataflowConstProp.diff #[allow(arithmetic_overflow)] + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + // CHECK: debug d => [[d:_.*]]; + // CHECK: debug e => [[e:_.*]]; + + // CHECK: [[a]] = const 1_i32; let a = 1; + + // CHECK: [[b]] = const 2_i32; let b = 2; + + // CHECK: assert(!const false, + // CHECK: [[c]] = const 3_i32; let c = a + b; + // CHECK: [[d]] = const _; let d = i32::MAX; + + // CHECK: assert(!const true, + // CHECK: [[e]] = const i32::MIN; let e = d + 1; } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs index 8006bd510e150..fb708e5084bb9 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs @@ -1,18 +1,29 @@ -// skip-filecheck // unit-test: DataflowConstProp // compile-flags: -Zmir-enable-passes=+GVN,+Inline // ignore-debug assertions change the output MIR // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// This test is to check ICE in issue [#115789](https://github.com/rust-lang/rust/issues/115789). + struct A { foo: Box<[bool]>, } // EMIT_MIR default_boxed_slice.main.GVN.diff // EMIT_MIR default_boxed_slice.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { // ConstProp will create a constant of type `Box<[bool]>`. + // FIXME: it is not yet a constant. + // Verify that `DataflowConstProp` does not ICE trying to dereference it directly. + + // CHECK: debug a => [[a:_.*]]; + // We may check other inlined functions as well... + + // CHECK: {{_.*}} = Box::<[bool]>( + // FIXME: should be `{{_.*}} = const Box::<[bool]>` let a: A = A { foo: Box::default() }; } diff --git a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff index 07ac5b72e244c..f50a763ef9a05 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff index 07ac5b72e244c..f50a763ef9a05 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff index 775325c4d0626..6bf702b856815 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff @@ -14,7 +14,7 @@ let _6: u8; let _8: u8; scope 2 { - debug x => _6; + debug x2 => _6; let _9: u8; scope 4 { debug y => _9; diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff index 775325c4d0626..6bf702b856815 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff @@ -14,7 +14,7 @@ let _6: u8; let _8: u8; scope 2 { - debug x => _6; + debug x2 => _6; let _9: u8; scope 4 { debug y => _9; diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs index e35c0e6e85bed..7ad64d05be434 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.rs +++ b/tests/mir-opt/dataflow-const-prop/enum.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH @@ -13,27 +12,67 @@ enum E { } // EMIT_MIR enum.simple.DataflowConstProp.diff + +// CHECK-LABEL: fn simple( fn simple() { + // CHECK: debug e => [[e:_.*]]; + // CHECK: debug x => [[x:_.*]]; + // CHECK: [[e]] = const E::V1(0_i32); let e = E::V1(0); - let x = match e { E::V1(x) => x, E::V2(x) => x }; + + // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb1, otherwise: bb2]; + // CHECK: [[target_bb]]: { + // CHECK: [[x]] = const 0_i32; + let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; } // EMIT_MIR enum.constant.DataflowConstProp.diff + +// CHECK-LABEL: fn constant( fn constant() { + // CHECK: debug e => [[e:_.*]]; + // CHECK: debug x => [[x:_.*]]; const C: E = E::V1(0); + + // CHECK: [[e]] = const _; let e = C; - let x = match e { E::V1(x) => x, E::V2(x) => x }; + // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb1, otherwise: bb2]; + // CHECK: [[target_bb]]: { + // CHECK: [[x]] = const 0_i32; + let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; } // EMIT_MIR enum.statics.DataflowConstProp.diff + +// CHECK-LABEL: fn statics( fn statics() { + // CHECK: debug e1 => [[e1:_.*]]; + // CHECK: debug x1 => [[x1:_.*]]; + // CHECK: debug e2 => [[e2:_.*]]; + // CHECK: debug x2 => [[x2:_.*]]; + static C: E = E::V1(0); - let e = C; - let x = match e { E::V1(x) => x, E::V2(x) => x }; + + // CHECK: [[e1]] = const E::V1(0_i32); + let e1 = C; + // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb1, otherwise: bb2]; + // CHECK: [[target_bb]]: { + // CHECK: [[x1]] = const 0_i32; + let x1 = match e1 { E::V1(x11) => x11, E::V2(x12) => x12 }; static RC: &E = &E::V2(4); - let e = RC; - let x = match e { E::V1(x) => x, E::V2(x) => x }; + + // CHECK: [[t:_.*]] = const {alloc2: &&E}; + // CHECK: [[e2]] = (*[[t]]); + let e2 = RC; + + // CHECK: switchInt({{move _.*}}) -> {{.*}} + // FIXME: add checks for x2. Currently, their MIRs are not symmetric in the two + // switch branches. + // One is `_9 = &(*_12) and another is `_9 = _11`. It is different from what we can + // get by printing MIR directly. It is better to check if there are any bugs in the + // MIR passes around this stage. + let x2 = match e2 { E::V1(x21) => x21, E::V2(x22) => x22 }; } #[rustc_layout_scalar_valid_range_start(1)] @@ -41,6 +80,8 @@ fn statics() { struct NonZeroUsize(usize); // EMIT_MIR enum.mutate_discriminant.DataflowConstProp.diff + +// CHECK-LABEL: fn mutate_discriminant( #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn mutate_discriminant() -> u8 { mir!( @@ -50,7 +91,11 @@ fn mutate_discriminant() -> u8 { // This assignment overwrites the niche in which the discriminant is stored. place!(Field(Field(Variant(x, 1), 0), 0)) = 0_usize; // So we cannot know the value of this discriminant. + + // CHECK: [[a:_.*]] = discriminant({{_.*}}); let a = Discriminant(x); + + // CHECK: switchInt([[a]]) -> [0: {{bb.*}}, otherwise: {{bb.*}}]; match a { 0 => bb1, _ => bad, @@ -68,18 +113,33 @@ fn mutate_discriminant() -> u8 { } // EMIT_MIR enum.multiple.DataflowConstProp.diff +// CHECK-LABEL: fn multiple( fn multiple(x: bool, i: u8) { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug e => [[e:_.*]]; + // CHECK: debug x2 => [[x2:_.*]]; + // CHECK: debug y => [[y:_.*]]; let e = if x { + // CHECK: [[e]] = Option::::Some(move {{_.*}}); Some(i) } else { + // CHECK: [[e]] = Option::::None; None }; // The dataflow state must have: // discriminant(e) => Top // (e as Some).0 => Top - let x = match e { Some(i) => i, None => 0 }; - // Therefore, `x` should be `Top` here, and no replacement shall happen. - let y = x; + // CHECK: [[x2]] = const 0_u8; + // CHECK: [[some:_.*]] = (({{_.*}} as Some).0: u8) + // CHECK: [[x2]] = [[some]]; + let x2 = match e { Some(i) => i, None => 0 }; + + // Therefore, `x2` should be `Top` here, and no replacement shall happen. + + // CHECK-NOT: [[y]] = const + // CHECK: [[y]] = [[x2]]; + // CHECK-NOT: [[y]] = const + let y = x2; } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff index 798b0c041b4ec..b31f98460e45b 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff index 798b0c041b4ec..b31f98460e45b 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index 053981abea3ec..44e8d39cca333 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -9,34 +9,34 @@ let mut _8: &&E; let mut _10: isize; scope 1 { - debug e => _1; + debug e1 => _1; let _3: i32; let _5: i32; let _6: i32; scope 2 { - debug x => _3; + debug x1 => _3; let _7: &E; scope 5 { - debug e => _7; + debug e2 => _7; let _9: &i32; let _11: &i32; let _12: &i32; scope 6 { - debug x => _9; + debug x2 => _9; } scope 7 { - debug x => _11; + debug x21 => _11; } scope 8 { - debug x => _12; + debug x22 => _12; } } } scope 3 { - debug x => _5; + debug x11 => _5; } scope 4 { - debug x => _6; + debug x12 => _6; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index d862bd93ff577..ac4ca086d0fed 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -9,34 +9,34 @@ let mut _8: &&E; let mut _10: isize; scope 1 { - debug e => _1; + debug e1 => _1; let _3: i32; let _5: i32; let _6: i32; scope 2 { - debug x => _3; + debug x1 => _3; let _7: &E; scope 5 { - debug e => _7; + debug e2 => _7; let _9: &i32; let _11: &i32; let _12: &i32; scope 6 { - debug x => _9; + debug x2 => _9; } scope 7 { - debug x => _11; + debug x21 => _11; } scope 8 { - debug x => _12; + debug x22 => _12; } } } scope 3 { - debug x => _5; + debug x11 => _5; } scope 4 { - debug x => _6; + debug x12 => _6; } } diff --git a/tests/mir-opt/dataflow-const-prop/if.rs b/tests/mir-opt/dataflow-const-prop/if.rs index 72aabbccf56c8..3400068baba2a 100644 --- a/tests/mir-opt/dataflow-const-prop/if.rs +++ b/tests/mir-opt/dataflow-const-prop/if.rs @@ -1,12 +1,26 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR if.main.DataflowConstProp.diff +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + // CHECK: debug d => [[d:_.*]]; + // CHECK: debug e => [[e:_.*]]; + let a = 1; + + // CHECK: switchInt(const true) -> [0: {{bb.*}}, otherwise: {{bb.*}}]; + // CHECK: [[b]] = const 2_i32; let b = if a == 1 { 2 } else { 3 }; + + // CHECK: [[c]] = const 3_i32; let c = b + 1; + // CHECK: switchInt(const true) -> [0: {{bb.*}}, otherwise: {{bb.*}}]; + // CHECK: [[d]] = const 1_i32; let d = if a == 1 { a } else { a + 1 }; + + // CHECK: [[e]] = const 2_i32; let e = d + 1; } diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs b/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs index 664cbcb2c259f..b0acc31e0dbcc 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs @@ -1,11 +1,14 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // compile-flags: -Zmir-enable-passes=+Inline // EMIT_MIR inherit_overflow.main.DataflowConstProp.diff +// CHECK-LABEL: fn main( fn main() { // After inlining, this will contain a `CheckedBinaryOp`. // Propagating the overflow is ok as codegen will just skip emitting the panic. + + // CHECK: {{_.*}} = const (0_u8, true); + // CHECK: assert(!const true, let _ = ::add(255, 1); } diff --git a/tests/mir-opt/dataflow-const-prop/issue_81605.rs b/tests/mir-opt/dataflow-const-prop/issue_81605.rs index 7c5eceb8a2b68..f13c364279d41 100644 --- a/tests/mir-opt/dataflow-const-prop/issue_81605.rs +++ b/tests/mir-opt/dataflow-const-prop/issue_81605.rs @@ -1,9 +1,18 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR issue_81605.f.DataflowConstProp.diff + +// Plese find the original issue [here](https://github.com/rust-lang/rust/issues/81605). +// This test program comes directly from the issue. Prior to this issue, +// the compiler cannot simplify the return value of `f` into 2. This was +// solved by adding a new MIR constant propagation based on dataflow +// analysis in [#101168](https://github.com/rust-lang/rust/pull/101168). + +// CHECK-LABEL: fn f( fn f() -> usize { + // CHECK: switchInt(const true) -> [0: {{bb.*}}, otherwise: {{bb.*}}]; 1 + if true { 1 } else { 2 } + // CHECK: _0 = const 2_usize; } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs index d611a54ba71a2..62be2c3824fa5 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs @@ -1,10 +1,18 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR large_array_index.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { // check that we don't propagate this, because it's too large + + // CHECK: debug x => [[x:_.*]]; + // CHECK: [[array_lit:_.*]] = [const 0_u8; 5000]; + // CHECK: {{_.*}} = const 5000_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true + // CHECK: [[x]] = [[array_lit]][2 of 3]; let x: u8 = [0_u8; 5000][2]; } diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs index 16a45c8e9fb59..be8ce7310564c 100644 --- a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs @@ -1,9 +1,10 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR mult_by_zero.test.DataflowConstProp.diff +// CHECK-LABEL: fn test( fn test(x : i32) -> i32 { x * 0 + // CHECK: _0 = const 0_i32; } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs index e71b3f59ecab3..ed8e8fcec16e6 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.rs +++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs @@ -1,8 +1,7 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::marker::PhantomData; use std::mem::offset_of; @@ -29,18 +28,46 @@ struct Delta { } // EMIT_MIR offset_of.concrete.DataflowConstProp.diff + +// CHECK-LABEL: fn concrete( fn concrete() { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + // CHECK: debug z0 => [[z0:_.*]]; + // CHECK: debug z1 => [[z1:_.*]]; + + // CHECK: [[x]] = must_use::(const 4_usize) -> {{.*}} let x = offset_of!(Alpha, x); + + // CHECK: [[y]] = must_use::(const 0_usize) -> {{.*}} let y = offset_of!(Alpha, y); + + // CHECK: [[z0]] = must_use::(const 2_usize) -> {{.*}} let z0 = offset_of!(Alpha, z.0); + + // CHECK: [[z1]] = must_use::(const 3_usize) -> {{.*}} let z1 = offset_of!(Alpha, z.1); } // EMIT_MIR offset_of.generic.DataflowConstProp.diff + +// CHECK-LABEL: fn generic( fn generic() { + // CHECK: debug gx => [[gx:_.*]]; + // CHECK: debug gy => [[gy:_.*]]; + // CHECK: debug dx => [[dx:_.*]]; + // CHECK: debug dy => [[dy:_.*]]; + + // CHECK: [[gx]] = must_use::(move {{_.*}}) -> {{.*}} let gx = offset_of!(Gamma, x); + + // CHECK: [[gy]] = must_use::(move {{_.*}}) -> {{.*}} let gy = offset_of!(Gamma, y); + + // CHECK: [[dx]] = must_use::(const 0_usize) -> {{.*}} let dx = offset_of!(Delta, x); + + // CHECK: [[dy]] = must_use::(const 2_usize) -> {{.*}} let dy = offset_of!(Delta, y); } diff --git a/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs b/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs index 2851c0590ad5f..7bf2b18407854 100644 --- a/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs +++ b/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp @@ -9,11 +8,23 @@ fn escape(x: &T) {} fn some_function() {} // EMIT_MIR ref_without_sb.main.DataflowConstProp.diff +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + let mut a = 0; + + // CHECK: {{_.*}} = escape::(move {{_.*}}) -> {{.*}} escape(&a); a = 1; + + // CHECK: {{_.*}} = some_function() -> {{.*}} some_function(); // This should currently not be propagated. + + // CHECK-NOT: [[b]] = const + // CHECK: [[b]] = [[a]]; + // CHECK-NOT: [[b]] = const let b = a; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs index b824481948116..daa8dbaf07655 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.rs +++ b/tests/mir-opt/dataflow-const-prop/repeat.rs @@ -1,9 +1,21 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR repeat.main.DataflowConstProp.diff +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug x => [[x:_.*]]; + + // CHECK: [[array_lit:_.*]] = [const 42_u32; 8]; + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK: {{_.*}} = const 8_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true + + // CHECK-NOT: [[t:_.*]] = [[array_lit]][_ + // CHECK: [[t:_.*]] = [[array_lit]][2 of 3]; + // CHECK: [[x]] = Add(move [[t]], const 0_u32); let x: u32 = [42; 8][2] + 0; } diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs index 8cbed6fbb624d..39a2b357193ad 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // The struct has scalar ABI, but is not a scalar type. @@ -7,7 +6,15 @@ struct I32(i32); // EMIT_MIR repr_transparent.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + + // CHECK: [[x]] = const I32(0_i32); let x = I32(0); + + // CHECK: [[y]] = const I32(0_i32); let y = I32(x.0 + x.0); } diff --git a/tests/mir-opt/dataflow-const-prop/self_assign.rs b/tests/mir-opt/dataflow-const-prop/self_assign.rs index c5866c4a9fd98..a5b232131286f 100644 --- a/tests/mir-opt/dataflow-const-prop/self_assign.rs +++ b/tests/mir-opt/dataflow-const-prop/self_assign.rs @@ -1,13 +1,26 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR self_assign.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + let mut a = 0; + + // CHECK: [[a]] = Add(move {{_.*}}, const 1_i32); a = a + 1; + + // CHECK: [[a]] = move {{_.*}}; a = a; + // CHECK: [[b]] = &[[a]]; let mut b = &a; + + // CHECK: [[b]] = move {{_.*}}; b = b; + + // CHECK: [[a]] = move {{_.*}}; a = *b; } diff --git a/tests/mir-opt/dataflow-const-prop/self_assign_add.rs b/tests/mir-opt/dataflow-const-prop/self_assign_add.rs index cfe1458e44be7..7bfbda7a96c61 100644 --- a/tests/mir-opt/dataflow-const-prop/self_assign_add.rs +++ b/tests/mir-opt/dataflow-const-prop/self_assign_add.rs @@ -1,9 +1,15 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR self_assign_add.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; let mut a = 0; + + // CHECK: [[a]] = const 1_i32; a += 1; + + // CHECK: [[a]] = const 2_i32; a += 1; } diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs index 68aff528695d5..9c610aabe821a 100644 --- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs +++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // This attempts to modify `x.1` via a pointer derived from `addr_of_mut!(x.0)`. // According to Miri, that is UB. However, T-opsem has not finalized that @@ -10,11 +9,17 @@ // unit-test: DataflowConstProp // EMIT_MIR sibling_ptr.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug x1 => [[x1:_.*]]; + let mut x: (u8, u8) = (0, 0); unsafe { let p = std::ptr::addr_of_mut!(x.0); *p.add(1) = 1; } + + // CHECK: [[x1]] = ({{_.*}}.1: u8); let x1 = x.1; // should not be propagated } diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs index 86266ef5d4e60..65c87580330fc 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.rs +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -1,13 +1,34 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // compile-flags: -Zmir-enable-passes=+InstSimplify // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR slice_len.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug local => [[local:_.*]]; + // CHECK: debug constant => [[constant:_.*]]; + + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ + // CHECK: {{_.*}} = const 3_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true, + + // CHECK: [[local]] = (*{{_.*}})[1 of 2]; let local = (&[1u32, 2, 3] as &[u32])[1]; + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ const SLICE: &[u32] = &[1, 2, 3]; + // CHECK: {{_.*}} = const 3_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true, + + // CHECK-NOT: [[constant]] = (*{{_.*}})[_ + // CHECK: [[constant]] = (*{{_.*}})[1 of 2]; let constant = SLICE[1]; } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index 0f461f515fdd0..c486281d6f8d7 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -37,16 +37,16 @@ let _8: std::option::Option; let _9: &[f32]; scope 4 { - debug a => _7; - debug b => _8; - debug c => _9; + debug a1 => _7; + debug b1 => _8; + debug c1 => _9; let _11: f32; let _12: std::option::Option; let _13: &[f32]; scope 5 { - debug a => _11; - debug b => _12; - debug c => _13; + debug a2 => _11; + debug b2 => _12; + debug c2 => _13; let _15: SmallStruct; scope 6 { debug ss => _15; @@ -54,16 +54,16 @@ let _20: std::option::Option; let _21: &[f32]; scope 7 { - debug a => _19; - debug b => _20; - debug c => _21; + debug a3 => _19; + debug b3 => _20; + debug c3 => _21; let _23: f32; let _24: std::option::Option; let _25: &[f32]; scope 8 { - debug a => _23; - debug b => _24; - debug c => _25; + debug a4 => _23; + debug b4 => _24; + debug c4 => _25; let _27: BigStruct; scope 9 { debug bs => _27; diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index 3c40ec8bfb450..7ea53d157334d 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -37,16 +37,16 @@ let _8: std::option::Option; let _9: &[f32]; scope 4 { - debug a => _7; - debug b => _8; - debug c => _9; + debug a1 => _7; + debug b1 => _8; + debug c1 => _9; let _11: f32; let _12: std::option::Option; let _13: &[f32]; scope 5 { - debug a => _11; - debug b => _12; - debug c => _13; + debug a2 => _11; + debug b2 => _12; + debug c2 => _13; let _15: SmallStruct; scope 6 { debug ss => _15; @@ -54,16 +54,16 @@ let _20: std::option::Option; let _21: &[f32]; scope 7 { - debug a => _19; - debug b => _20; - debug c => _21; + debug a3 => _19; + debug b3 => _20; + debug c3 => _21; let _23: f32; let _24: std::option::Option; let _25: &[f32]; scope 8 { - debug a => _23; - debug b => _24; - debug c => _25; + debug a4 => _23; + debug b4 => _24; + debug c4 => _25; let _27: BigStruct; scope 9 { debug bs => _27; diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs index 043981a295484..a7e0f6a987d5a 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.rs +++ b/tests/mir-opt/dataflow-const-prop/struct.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH @@ -12,27 +11,69 @@ struct SmallStruct(f32, Option, &'static [f32]); struct BigStruct(f32, Option, &'static [f32]); // EMIT_MIR struct.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug s => [[s:_.*]]; + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug a1 => [[a1:_.*]]; + // CHECK: debug b1 => [[b1:_.*]]; + // CHECK: debug c1 => [[c1:_.*]]; + // CHECK: debug a2 => [[a2:_.*]]; + // CHECK: debug b2 => [[b2:_.*]]; + // CHECK: debug c2 => [[c2:_.*]]; + // CHECK: debug ss => [[ss:_.*]]; + // CHECK: debug a3 => [[a3:_.*]]; + // CHECK: debug b3 => [[b3:_.*]]; + // CHECK: debug c3 => [[c3:_.*]]; + // CHECK: debug a4 => [[a4:_.*]]; + // CHECK: debug b4 => [[b4:_.*]]; + // CHECK: debug c4 => [[c4:_.*]]; + // CHECK: debug bs => [[bs:_.*]]; + + // CHECK: [[s]] = const S(1_i32); let mut s = S(1); + + // CHECK: [[a]] = const 3_i32; let a = s.0 + 2; s.0 = 3; + + // CHECK: [[b]] = const 6_i32; let b = a + s.0; const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); - let SmallStruct(a, b, c) = SMALL_VAL; + + // CHECK: [[a1]] = const 4f32; + // CHECK: [[b1]] = const Option::::Some(S(1_i32)); + // CHECK: [[c1]] = ({{_.*}}.2: &[f32]); + let SmallStruct(a1, b1, c1) = SMALL_VAL; static SMALL_STAT: &SmallStruct = &SmallStruct(9., None, &[13.]); - let SmallStruct(a, b, c) = *SMALL_STAT; - let ss = SmallStruct(a, b, c); + // CHECK: [[a2]] = const 9f32; + // CHECK: [[b2]] = ((*{{_.*}}).1: std::option::Option); + // CHECK: [[c2]] = ((*{{_.*}}).2: &[f32]); + let SmallStruct(a2, b2, c2) = *SMALL_STAT; + + // CHECK: [[ss]] = SmallStruct(const 9f32, move {{_.*}}, move {{_.*}}); + let ss = SmallStruct(a2, b2, c2); const BIG_VAL: BigStruct = BigStruct(25., None, &[]); - let BigStruct(a, b, c) = BIG_VAL; + + // CHECK: [[a3]] = const 25f32; + // CHECK: [[b3]] = ({{_.*}}.1: std::option::Option); + // CHECK: [[c3]] = ({{_.*}}.2: &[f32]); + let BigStruct(a3, b3, c3) = BIG_VAL; static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]); - let BigStruct(a, b, c) = *BIG_STAT; + // CHECK: [[a4]] = const 82f32; + // CHECK: [[b4]] = const Option::::Some(S(35_i32)); + // CHECK: [[c4]] = ((*{{_.*}}).2: &[f32]); + let BigStruct(a4, b4, c4) = *BIG_STAT; // We arbitrarily limit the size of synthetized values to 4 pointers. // `BigStruct` can be read, but we will keep a MIR aggregate for this. - let bs = BigStruct(a, b, c); + // CHECK: [[bs]] = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move {{_.*}}); + let bs = BigStruct(a4, b4, c4); } diff --git a/tests/mir-opt/dataflow-const-prop/terminator.rs b/tests/mir-opt/dataflow-const-prop/terminator.rs index 92a42f22c218f..4472861f132db 100644 --- a/tests/mir-opt/dataflow-const-prop/terminator.rs +++ b/tests/mir-opt/dataflow-const-prop/terminator.rs @@ -1,12 +1,14 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp fn foo(n: i32) {} // EMIT_MIR terminator.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { let a = 1; // Checks that we propagate into terminators. + // CHECK: {{_.*}} = foo(const 2_i32) -> [return: {{bb.*}}, unwind foo(a + 1); } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index bb706eafe8885..563558da04a5d 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -1,13 +1,27 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR tuple.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + // CHECK: debug d => [[d:_.*]]; + + // CHECK: [[a]] = const (1_i32, 2_i32); let mut a = (1, 2); + + // CHECK: [[b]] = const 6_i32; let b = a.0 + a.1 + 3; + + // CHECK: [[a]] = const (2_i32, 3_i32); a = (2, 3); + + // CHECK: [[c]] = const 11_i32; let c = a.0 + a.1 + b; + // CHECK: [[d]] = (const 6_i32, const (2_i32, 3_i32), const 11_i32); let d = (b, a, c); } diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff new file mode 100644 index 0000000000000..0b6819ad48336 --- /dev/null +++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff @@ -0,0 +1,34 @@ +- // MIR for `f` before GVN ++ // MIR for `f` after GVN + + fn f() -> u32 { + let mut _0: u32; + let _1: u32; + let mut _2: E; + let mut _3: &U; + let _4: U; + scope 1 { + debug i => _1; + } + scope 2 { + let mut _5: &U; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _5 = const _; + _3 = &(*_5); + _2 = ((*_3).1: E); + StorageLive(_1); +- _1 = ((_2 as A).1: u32); ++ _1 = const 0_u32; + StorageDead(_3); + StorageDead(_2); +- _0 = _1; ++ _0 = const 0_u32; + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..0b6819ad48336 --- /dev/null +++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff @@ -0,0 +1,34 @@ +- // MIR for `f` before GVN ++ // MIR for `f` after GVN + + fn f() -> u32 { + let mut _0: u32; + let _1: u32; + let mut _2: E; + let mut _3: &U; + let _4: U; + scope 1 { + debug i => _1; + } + scope 2 { + let mut _5: &U; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _5 = const _; + _3 = &(*_5); + _2 = ((*_3).1: E); + StorageLive(_1); +- _1 = ((_2 as A).1: u32); ++ _1 = const 0_u32; + StorageDead(_3); + StorageDead(_2); +- _0 = _1; ++ _0 = const 0_u32; + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/gvn_uninhabited.rs b/tests/mir-opt/gvn_uninhabited.rs new file mode 100644 index 0000000000000..a55b2dd763ac5 --- /dev/null +++ b/tests/mir-opt/gvn_uninhabited.rs @@ -0,0 +1,24 @@ +// unit-test: GVN +// compile-flags: -O +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// skip-filecheck + +#![feature(never_type)] + +#[derive(Copy, Clone)] +pub enum E { + A(!, u32), +} + +pub union U { + i: u32, + e: E, +} + +// EMIT_MIR gvn_uninhabited.f.GVN.diff +pub const fn f() -> u32 { + let E::A(_, i) = unsafe { (&U { i: 0 }).e }; + i +} + +fn main() {} diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 8e53427e7e060..a38b8246bdef2 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind unreachable]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index b06db41af9d40..dc6628ab44c5f 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind continue]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff b/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff index cb623e83f5298..be7f9cd441210 100644 --- a/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff +++ b/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff @@ -4,7 +4,7 @@ fn adt_transmutes() -> () { let mut _0: (); let _1: u8; - let mut _2: std::option::Option; + let mut _2: std::option::Option>; let mut _4: std::num::Wrapping; let mut _6: std::num::Wrapping; let mut _8: Union32; @@ -37,7 +37,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = Option::::Some(const _); + _2 = Option::>::Some(const _); _1 = move _2 as u8 (Transmute); StorageDead(_2); StorageLive(_3); diff --git a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff new file mode 100644 index 0000000000000..66aa892c6f331 --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff @@ -0,0 +1,52 @@ +- // MIR for `aggregate` before JumpThreading ++ // MIR for `aggregate` after JumpThreading + + fn aggregate(_1: u8) -> u8 { + debug x => _1; + let mut _0: u8; + let _2: u8; + let _3: u8; + let mut _4: (u8, u8); + let mut _5: bool; + let mut _6: u8; + scope 1 { + debug a => _2; + debug b => _3; + } + + bb0: { + StorageLive(_4); + _4 = const _; + StorageLive(_2); + _2 = (_4.0: u8); + StorageLive(_3); + _3 = (_4.1: u8); + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = _2; + _5 = Eq(move _6, const 7_u8); +- switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; + } + + bb1: { + StorageDead(_6); + _0 = _3; + goto -> bb3; + } + + bb2: { + StorageDead(_6); + _0 = _2; + goto -> bb3; + } + + bb3: { + StorageDead(_5); + StorageDead(_3); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff new file mode 100644 index 0000000000000..66aa892c6f331 --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff @@ -0,0 +1,52 @@ +- // MIR for `aggregate` before JumpThreading ++ // MIR for `aggregate` after JumpThreading + + fn aggregate(_1: u8) -> u8 { + debug x => _1; + let mut _0: u8; + let _2: u8; + let _3: u8; + let mut _4: (u8, u8); + let mut _5: bool; + let mut _6: u8; + scope 1 { + debug a => _2; + debug b => _3; + } + + bb0: { + StorageLive(_4); + _4 = const _; + StorageLive(_2); + _2 = (_4.0: u8); + StorageLive(_3); + _3 = (_4.1: u8); + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = _2; + _5 = Eq(move _6, const 7_u8); +- switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; + } + + bb1: { + StorageDead(_6); + _0 = _3; + goto -> bb3; + } + + bb2: { + StorageDead(_6); + _0 = _2; + goto -> bb3; + } + + bb3: { + StorageDead(_5); + StorageDead(_3); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.assume.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.assume.JumpThreading.panic-abort.diff new file mode 100644 index 0000000000000..f1f0106fdbce9 --- /dev/null +++ b/tests/mir-opt/jump_threading.assume.JumpThreading.panic-abort.diff @@ -0,0 +1,39 @@ +- // MIR for `assume` before JumpThreading ++ // MIR for `assume` after JumpThreading + + fn assume(_1: u8, _2: bool) -> u8 { + let mut _0: u8; + + bb0: { + switchInt(_1) -> [7: bb1, otherwise: bb2]; + } + + bb1: { + assume(_2); +- goto -> bb3; ++ goto -> bb6; + } + + bb2: { + goto -> bb3; + } + + bb3: { + switchInt(_2) -> [0: bb4, otherwise: bb5]; + } + + bb4: { + _0 = const 4_u8; + return; + } + + bb5: { + _0 = const 5_u8; + return; ++ } ++ ++ bb6: { ++ goto -> bb5; + } + } + diff --git a/tests/mir-opt/jump_threading.assume.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.assume.JumpThreading.panic-unwind.diff new file mode 100644 index 0000000000000..f1f0106fdbce9 --- /dev/null +++ b/tests/mir-opt/jump_threading.assume.JumpThreading.panic-unwind.diff @@ -0,0 +1,39 @@ +- // MIR for `assume` before JumpThreading ++ // MIR for `assume` after JumpThreading + + fn assume(_1: u8, _2: bool) -> u8 { + let mut _0: u8; + + bb0: { + switchInt(_1) -> [7: bb1, otherwise: bb2]; + } + + bb1: { + assume(_2); +- goto -> bb3; ++ goto -> bb6; + } + + bb2: { + goto -> bb3; + } + + bb3: { + switchInt(_2) -> [0: bb4, otherwise: bb5]; + } + + bb4: { + _0 = const 4_u8; + return; + } + + bb5: { + _0 = const 5_u8; + return; ++ } ++ ++ bb6: { ++ goto -> bb5; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 0cbdaa085bc97..a66fe8b57e718 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -453,7 +453,69 @@ fn disappearing_bb(x: u8) -> u8 { ) } +/// Verify that we can thread jumps when we assign from an aggregate constant. +fn aggregate(x: u8) -> u8 { + // CHECK-LABEL: fn aggregate( + // CHECK-NOT: switchInt( + + const FOO: (u8, u8) = (5, 13); + + let (a, b) = FOO; + if a == 7 { + b + } else { + a + } +} + +/// Verify that we can leverage the existence of an `Assume` terminator. +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +fn assume(a: u8, b: bool) -> u8 { + // CHECK-LABEL: fn assume( + mir!( + { + // CHECK: bb0: { + // CHECK-NEXT: switchInt(_1) -> [7: bb1, otherwise: bb2] + match a { 7 => bb1, _ => bb2 } + } + bb1 = { + // CHECK: bb1: { + // CHECK-NEXT: assume(_2); + // CHECK-NEXT: goto -> bb6; + Assume(b); + Goto(bb3) + } + bb2 = { + // CHECK: bb2: { + // CHECK-NEXT: goto -> bb3; + Goto(bb3) + } + bb3 = { + // CHECK: bb3: { + // CHECK-NEXT: switchInt(_2) -> [0: bb4, otherwise: bb5]; + match b { false => bb4, _ => bb5 } + } + bb4 = { + // CHECK: bb4: { + // CHECK-NEXT: _0 = const 4_u8; + // CHECK-NEXT: return; + RET = 4; + Return() + } + bb5 = { + // CHECK: bb5: { + // CHECK-NEXT: _0 = const 5_u8; + // CHECK-NEXT: return; + RET = 5; + Return() + } + // CHECK: bb6: { + // CHECK-NEXT: goto -> bb5; + ) +} + fn main() { + // CHECK-LABEL: fn main( too_complex(Ok(0)); identity(Ok(0)); custom_discr(false); @@ -464,6 +526,8 @@ fn main() { mutable_ref(); renumbered_bb(true); disappearing_bb(7); + aggregate(7); + assume(7, false); } // EMIT_MIR jump_threading.too_complex.JumpThreading.diff @@ -476,3 +540,5 @@ fn main() { // EMIT_MIR jump_threading.mutable_ref.JumpThreading.diff // EMIT_MIR jump_threading.renumbered_bb.JumpThreading.diff // EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff +// EMIT_MIR jump_threading.aggregate.JumpThreading.diff +// EMIT_MIR jump_threading.assume.JumpThreading.diff diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 36329f8fc6845..dc37c1b4cbf9f 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -42,7 +42,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug self => _8; } scope 15 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { - debug data_address => _9; + debug data_pointer => _9; debug metadata => _6; let mut _10: *const (); let mut _11: std::ptr::metadata::PtrComponents<[u32]>; @@ -90,7 +90,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_11); StorageLive(_10); _10 = _9 as *const () (PointerCoercion(MutToConstPointer)); - _11 = std::ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; + _11 = std::ptr::metadata::PtrComponents::<[u32]> { data_pointer: move _10, metadata: _6 }; StorageDead(_10); _12 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; StorageDead(_11); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 36329f8fc6845..dc37c1b4cbf9f 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -42,7 +42,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug self => _8; } scope 15 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { - debug data_address => _9; + debug data_pointer => _9; debug metadata => _6; let mut _10: *const (); let mut _11: std::ptr::metadata::PtrComponents<[u32]>; @@ -90,7 +90,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_11); StorageLive(_10); _10 = _9 as *const () (PointerCoercion(MutToConstPointer)); - _11 = std::ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; + _11 = std::ptr::metadata::PtrComponents::<[u32]> { data_pointer: move _10, metadata: _6 }; StorageDead(_10); _12 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; StorageDead(_11); diff --git a/tests/pretty/delimited-token-groups.rs b/tests/pretty/delimited-token-groups.rs index c7c9277faf69e..b24c35bf0813f 100644 --- a/tests/pretty/delimited-token-groups.rs +++ b/tests/pretty/delimited-token-groups.rs @@ -9,7 +9,7 @@ mac! { { fn clone() -> S { - panic! () ; + panic! (); } } diff --git a/tests/pretty/macro_rules.rs b/tests/pretty/macro_rules.rs index 01adb14133b35..a5265446ee796 100644 --- a/tests/pretty/macro_rules.rs +++ b/tests/pretty/macro_rules.rs @@ -1,19 +1,19 @@ // pp-exact -macro_rules! brace { () => {} ; } +macro_rules! brace { () => {}; } -macro_rules! bracket[() => {} ;]; +macro_rules! bracket[() => {};]; -macro_rules! paren(() => {} ;); +macro_rules! paren(() => {};); macro_rules! matcher_brackets { - (paren) => {} ; (bracket) => {} ; (brace) => {} ; + (paren) => {}; (bracket) => {}; (brace) => {}; } macro_rules! all_fragments { ($b : block, $e : expr, $i : ident, $it : item, $l : lifetime, $lit : literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty, - $vis : vis) => {} ; + $vis : vis) => {}; } fn main() {} diff --git a/tests/pretty/offset_of.rs b/tests/pretty/offset_of.rs index e1783432857e2..1307c335ad322 100644 --- a/tests/pretty/offset_of.rs +++ b/tests/pretty/offset_of.rs @@ -1,4 +1,3 @@ // pp-exact -#![feature(offset_of)] fn main() { std::mem::offset_of!(std :: ops :: Range < usize >, end); } diff --git a/tests/pretty/stmt_expr_attributes.rs b/tests/pretty/stmt_expr_attributes.rs index 052c45f2cb8b6..69b153175615b 100644 --- a/tests/pretty/stmt_expr_attributes.rs +++ b/tests/pretty/stmt_expr_attributes.rs @@ -113,7 +113,7 @@ fn _8() { } fn _9() { - macro_rules! stmt_mac { () => { let _ = () ; } } + macro_rules! stmt_mac { () => { let _ = (); } } #[rustc_dummy] stmt_mac!(); diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index fd9386be8f3c3..fbdad0c323f34 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -28,7 +28,8 @@ should_panic: test::ShouldPanic::No, test_type: test::TestType::Unknown, }, - testfn: test::StaticTestFn(|| test::assert_test_result(m_test())), + testfn: test::StaticTestFn(#[coverage(off)] || + test::assert_test_result(m_test())), }; fn m_test() {} @@ -51,7 +52,8 @@ should_panic: test::ShouldPanic::No, test_type: test::TestType::Unknown, }, - testfn: test::StaticTestFn(|| test::assert_test_result(z_test())), + testfn: test::StaticTestFn(#[coverage(off)] || + test::assert_test_result(z_test())), }; #[ignore = "not yet implemented"] fn z_test() {} @@ -75,7 +77,8 @@ should_panic: test::ShouldPanic::No, test_type: test::TestType::Unknown, }, - testfn: test::StaticTestFn(|| test::assert_test_result(a_test())), + testfn: test::StaticTestFn(#[coverage(off)] || + test::assert_test_result(a_test())), }; fn a_test() {} #[rustc_main] diff --git a/tests/run-make/rust-lld-custom-target/custom-target.json b/tests/run-make/rust-lld-custom-target/custom-target.json index 7828a99f235c1..e2c64cbdb43c2 100644 --- a/tests/run-make/rust-lld-custom-target/custom-target.json +++ b/tests/run-make/rust-lld-custom-target/custom-target.json @@ -2,7 +2,7 @@ "arch": "x86_64", "cpu": "x86-64", "crt-static-respected": true, - "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "dynamic-linking": true, "env": "gnu", "has-rpath": true, diff --git a/tests/run-make/rustdoc-target-spec-json-path/target.json b/tests/run-make/rustdoc-target-spec-json-path/target.json index 34357182c205e..c478f1196fae0 100644 --- a/tests/run-make/rustdoc-target-spec-json-path/target.json +++ b/tests/run-make/rustdoc-target-spec-json-path/target.json @@ -2,7 +2,7 @@ "arch": "x86_64", "cpu": "x86-64", "crt-static-respected": true, - "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "dynamic-linking": true, "env": "gnu", "executables": true, diff --git a/tests/run-make/symbol-mangling-hashed/Makefile b/tests/run-make/symbol-mangling-hashed/Makefile new file mode 100644 index 0000000000000..68894b2192aba --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/Makefile @@ -0,0 +1,48 @@ +include ../tools.mk + +# ignore-cross-compile +# only-linux +# only-x86_64 + +NM=nm -D +RLIB_NAME=liba_rlib.rlib +DYLIB_NAME=liba_dylib.so +SO_NAME=libb_dylib.so +BIN_NAME=b_bin + +ifeq ($(UNAME),Darwin) +NM=nm -gU +RLIB_NAME=liba_rlib.rlib +DYLIB_NAME=liba_dylib.dylib +SO_NAME=libb_dylib.dylib +BIN_NAME=b_bin +endif + +ifdef IS_WINDOWS +NM=nm -g +RLIB_NAME=liba_rlib.dll.a +DYLIB_NAME=liba_dylib.dll +SO_NAME=libb_dylib.dll +BIN_NAME=b_bin.exe +endif + +all: + $(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=foo a_dylib.rs + $(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=bar a_rlib.rs + $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_dylib.rs + $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_bin.rs + + # Check hashed symbol name + + [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep -c hello)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep _RNxC7a_dylib | grep -c ' T ')" -eq "1" ] + + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep b_dylib | grep -c hello)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC6a_rlib | grep -c ' T ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ] + + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC6a_rlib | grep -c ' U ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep b_dylib | grep hello | grep -c ' U ')" -eq "1" ] + + $(call RUN,$(BIN_NAME)) diff --git a/tests/run-make/symbol-mangling-hashed/a_dylib.rs b/tests/run-make/symbol-mangling-hashed/a_dylib.rs new file mode 100644 index 0000000000000..8aec8fd82a53f --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/a_dylib.rs @@ -0,0 +1,4 @@ +#![crate_type="dylib"] +pub fn hello() { + println!("hello dylib"); +} diff --git a/tests/run-make/symbol-mangling-hashed/a_rlib.rs b/tests/run-make/symbol-mangling-hashed/a_rlib.rs new file mode 100644 index 0000000000000..873c86c5d0b4c --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/a_rlib.rs @@ -0,0 +1,5 @@ +#![crate_type="rlib"] + +pub fn hello() { + println!("hello rlib"); +} diff --git a/tests/run-make/symbol-mangling-hashed/b_bin.rs b/tests/run-make/symbol-mangling-hashed/b_bin.rs new file mode 100644 index 0000000000000..bcc53c37e122a --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/b_bin.rs @@ -0,0 +1,9 @@ +extern crate a_rlib; +extern crate a_dylib; +extern crate b_dylib; + +fn main() { + a_rlib::hello(); + a_dylib::hello(); + b_dylib::hello(); +} diff --git a/tests/run-make/symbol-mangling-hashed/b_dylib.rs b/tests/run-make/symbol-mangling-hashed/b_dylib.rs new file mode 100644 index 0000000000000..c26a04b39ec32 --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/b_dylib.rs @@ -0,0 +1,9 @@ +#![crate_type="dylib"] + +extern crate a_rlib; +extern crate a_dylib; + +pub fn hello() { + a_rlib::hello(); + a_dylib::hello(); +} diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile index 62d5365a73d03..161b66021857b 100644 --- a/tests/run-make/target-specs/Makefile +++ b/tests/run-make/target-specs/Makefile @@ -9,4 +9,4 @@ all: $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' $(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian' - $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib + $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib 2>&1 | $(CGREP) 'data-layout for target' diff --git a/tests/run-make/target-specs/my-awesome-platform.json b/tests/run-make/target-specs/my-awesome-platform.json index 00de3de05f07a..1673ef7bd54d1 100644 --- a/tests/run-make/target-specs/my-awesome-platform.json +++ b/tests/run-make/target-specs/my-awesome-platform.json @@ -1,5 +1,5 @@ { - "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", "linker-flavor": "gcc", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", diff --git a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json index 6d5e964ed4fee..0cafce15a9fef 100644 --- a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json +++ b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json @@ -1,6 +1,6 @@ { "pre-link-args": {"gcc": ["-m64"]}, - "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "linker-flavor": "gcc", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", diff --git a/tests/rustdoc-gui/docblock-details.goml b/tests/rustdoc-gui/docblock-details.goml index 8e6d2ba824f73..4b8f5b54fac5d 100644 --- a/tests/rustdoc-gui/docblock-details.goml +++ b/tests/rustdoc-gui/docblock-details.goml @@ -6,7 +6,7 @@ reload: // We first check that the headers in the `.top-doc` doc block still have their // bottom border. -assert-text: (".top-doc .docblock > h3", "Hello") +assert-text: (".top-doc .docblock > h3", "§Hello") assert-css: ( ".top-doc .docblock > h3", {"border-bottom": "1px solid #d2d2d2"}, diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml index 19185818f407e..80d11c9c849cf 100644 --- a/tests/rustdoc-gui/headers-color.goml +++ b/tests/rustdoc-gui/headers-color.goml @@ -1,4 +1,4 @@ -// This test check for headers text and background colors for the different themes. +// This test check for headings text and background colors for the different themes. define-function: ( "check-colors", @@ -45,7 +45,7 @@ call-function: ( "color": "#c5c5c5", "code_header_color": "#e6e1cf", "focus_background_color": "rgba(255, 236, 164, 0.06)", - "headings_color": "#39afd7", + "headings_color": "#c5c5c5", }, ) call-function: ( @@ -55,7 +55,7 @@ call-function: ( "color": "#ddd", "code_header_color": "#ddd", "focus_background_color": "#494a3d", - "headings_color": "#d2991d", + "headings_color": "#ddd", }, ) call-function: ( @@ -65,6 +65,6 @@ call-function: ( "color": "black", "code_header_color": "black", "focus_background_color": "#fdffd3", - "headings_color": "#3873ad", + "headings_color": "black", }, ) diff --git a/tests/rustdoc-gui/headings-anchor.goml b/tests/rustdoc-gui/headings-anchor.goml new file mode 100644 index 0000000000000..f568caa3b07fe --- /dev/null +++ b/tests/rustdoc-gui/headings-anchor.goml @@ -0,0 +1,32 @@ +// Test to ensure that the headings anchor behave as expected. +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" +show-text: true + +define-function: ( + "check-heading-anchor", + (heading_id), + block { + // The anchor should not be displayed by default. + assert-css: ("#" + |heading_id| + " .doc-anchor", { "display": "none" }) + // We ensure that hovering the heading makes the anchor visible. + move-cursor-to: "#" + |heading_id| + assert-css: ("#" + |heading_id| + ":hover .doc-anchor", { "display": "block" }) + // We then ensure that moving from the heading to the anchor doesn't make the anchor + // disappear. + move-cursor-to: "#" + |heading_id| + " .doc-anchor" + assert-css: ("#" + |heading_id| + " .doc-anchor:hover", { + "display": "block", + // We also ensure that there is no underline decoration. + "text-decoration-line": "none", + }) + } +) + +move-cursor-to: "#top-doc-prose-title" +// If the top documentation block first element is a heading, we should never display its anchor +// to prevent it from overlapping with the `[-]` element. +assert-css: ("#top-doc-prose-title:hover .doc-anchor", { "display": "none" }) + +call-function: ("check-heading-anchor", ("top-doc-prose-sub-heading")) +call-function: ("check-heading-anchor", ("top-doc-prose-sub-sub-heading")) +call-function: ("check-heading-anchor", ("you-know-the-drill")) diff --git a/tests/rustdoc-gui/sidebar-resize-close-popover.goml b/tests/rustdoc-gui/sidebar-resize-close-popover.goml new file mode 100644 index 0000000000000..2a8fbac855e97 --- /dev/null +++ b/tests/rustdoc-gui/sidebar-resize-close-popover.goml @@ -0,0 +1,20 @@ +// Checks sidebar resizing close the Settings popover +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-property: (".sidebar", {"clientWidth": "200"}) +show-text: true +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings", {"display": "block"}) +// normal resizing +drag-and-drop: ((205, 100), (185, 100)) +assert-property: (".sidebar", {"clientWidth": "182"}) +assert-css: ("#settings", {"display": "none"}) + +// Now same thing, but for source code +go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings", {"display": "block"}) +assert-property: (".sidebar", {"clientWidth": "49"}) +drag-and-drop: ((52, 100), (185, 100)) +assert-css: ("#settings", {"display": "none"}) diff --git a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs index 0901ac3640fdd..ffd694e987908 100644 --- a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs +++ b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs @@ -24,10 +24,9 @@ mod rustc_ok { pub fn rustc_lints() { let x = 42.0; - #[expect(illegal_floating_point_literal_pattern)] + #[expect(invalid_nan_comparisons)] match x { - 5.0 => {} - 6.0 => {} + f32::NAN => {} _ => {} } } @@ -40,7 +39,7 @@ mod rustc_warn { pub fn rustc_lints() { let x = 42; - #[expect(illegal_floating_point_literal_pattern)] + #[expect(invalid_nan_comparisons)] match x { 5 => {} 6 => {} diff --git a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr index efc5f349f4f44..5ae3c039d275a 100644 --- a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr +++ b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr @@ -7,19 +7,19 @@ LL | #![expect(rustdoc::missing_crate_level_docs)] = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:71:14 + --> $DIR/expect-tool-lint-rfc-2383.rs:70:14 | LL | #[expect(rustdoc::broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:76:14 + --> $DIR/expect-tool-lint-rfc-2383.rs:75:14 | LL | #[expect(rustdoc::invalid_html_tags)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: this lint expectation is unfulfilled - --> $DIR/expect-tool-lint-rfc-2383.rs:81:14 + --> $DIR/expect-tool-lint-rfc-2383.rs:80:14 | LL | #[expect(rustdoc::bare_urls)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr index bd21dcb6e1af9..000a5b597d299 100644 --- a/tests/rustdoc-ui/unescaped_backticks.stderr +++ b/tests/rustdoc-ui/unescaped_backticks.stderr @@ -302,7 +302,6 @@ LL | | /// level changes. = help: if you meant to use a literal backtick, escape it change: or `None` if it isn't. to this: or `None\` if it isn't. - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unescaped backtick --> $DIR/unescaped_backticks.rs:323:5 @@ -322,7 +321,6 @@ LL | | /// level changes. = help: if you meant to use a literal backtick, escape it change: `on_event` should be called. to this: `on_event\` should be called. - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unescaped backtick --> $DIR/unescaped_backticks.rs:323:5 @@ -342,7 +340,6 @@ LL | | /// level changes. = help: if you meant to use a literal backtick, escape it change: [`rebuild_interest_cache`][rebuild] is called after the value of the max to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unescaped backtick --> $DIR/unescaped_backticks.rs:349:56 diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async-fn.rs index 70bcbcb6ff44a..b3c35c8c3f309 100644 --- a/tests/rustdoc/async-fn.rs +++ b/tests/rustdoc/async-fn.rs @@ -48,6 +48,8 @@ impl Foo { pub trait Pattern<'a> {} +impl Pattern<'_> for () {} + pub trait Trait {} // @has async_fn/fn.const_generics.html // @has - '//pre[@class="rust item-decl"]' 'pub async fn const_generics(_: impl Trait)' @@ -57,18 +59,18 @@ pub async fn const_generics(_: impl Trait) {} // regression test for #63037 // @has async_fn/fn.elided.html // @has - '//pre[@class="rust item-decl"]' 'pub async fn elided(foo: &str) -> &str' -pub async fn elided(foo: &str) -> &str {} +pub async fn elided(foo: &str) -> &str { "" } // This should really be shown as written, but for implementation reasons it's difficult. // See `impl Clean for TyKind::Ref`. // @has async_fn/fn.user_elided.html // @has - '//pre[@class="rust item-decl"]' 'pub async fn user_elided(foo: &str) -> &str' -pub async fn user_elided(foo: &'_ str) -> &str {} +pub async fn user_elided(foo: &'_ str) -> &str { "" } // @has async_fn/fn.static_trait.html // @has - '//pre[@class="rust item-decl"]' 'pub async fn static_trait(foo: &str) -> Box' -pub async fn static_trait(foo: &str) -> Box {} +pub async fn static_trait(foo: &str) -> Box { Box::new(()) } // @has async_fn/fn.lifetime_for_trait.html // @has - '//pre[@class="rust item-decl"]' "pub async fn lifetime_for_trait(foo: &str) -> Box" -pub async fn lifetime_for_trait(foo: &str) -> Box {} +pub async fn lifetime_for_trait(foo: &str) -> Box { Box::new(()) } // @has async_fn/fn.elided_in_input_trait.html // @has - '//pre[@class="rust item-decl"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)" pub async fn elided_in_input_trait(t: impl Pattern<'_>) {} @@ -78,10 +80,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } impl Foo { // @has async_fn/struct.Foo.html // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar ) -> impl Iterator' - pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator {} + pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator { + [0].iter() + } // taken from `tokio` as an example of a method that was particularly bad before // @has - '//*[@class="method"]' "pub async fn readable(&self) -> Result, ()>" - pub async fn readable(&self) -> Result, ()> {} + pub async fn readable(&self) -> Result, ()> { Err(()) } // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)" pub async fn mut_self(&mut self) {} } @@ -89,7 +93,7 @@ impl Foo { // test named lifetimes, just in case // @has async_fn/fn.named.html // @has - '//pre[@class="rust item-decl"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str" -pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {} +pub async fn named<'a, 'b>(foo: &'a str) -> &'b str { "" } // @has async_fn/fn.named_trait.html // @has - '//pre[@class="rust item-decl"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>" pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {} diff --git a/tests/rustdoc/disambiguate-anchors-header-29449.rs b/tests/rustdoc/disambiguate-anchors-header-29449.rs index 38a4954fc1395..1388af7df4b2e 100644 --- a/tests/rustdoc/disambiguate-anchors-header-29449.rs +++ b/tests/rustdoc/disambiguate-anchors-header-29449.rs @@ -5,18 +5,23 @@ pub struct Foo; impl Foo { - // @has - '//*[@id="examples"]//a' 'Examples' - // @has - '//*[@id="panics"]//a' 'Panics' + // @has - '//*[@id="examples"]' 'Examples' + // @has - '//*[@id="examples"]/a[@href="#examples"]' '§' + // @has - '//*[@id="panics"]' 'Panics' + // @has - '//*[@id="panics"]/a[@href="#panics"]' '§' /// # Examples /// # Panics pub fn bar() {} - // @has - '//*[@id="examples-1"]//a' 'Examples' + // @has - '//*[@id="examples-1"]' 'Examples' + // @has - '//*[@id="examples-1"]/a[@href="#examples-1"]' '§' /// # Examples pub fn bar_1() {} - // @has - '//*[@id="examples-2"]//a' 'Examples' - // @has - '//*[@id="panics-1"]//a' 'Panics' + // @has - '//*[@id="examples-2"]' 'Examples' + // @has - '//*[@id="examples-2"]/a[@href="#examples-2"]' '§' + // @has - '//*[@id="panics-1"]' 'Panics' + // @has - '//*[@id="panics-1"]/a[@href="#panics-1"]' '§' /// # Examples /// # Panics pub fn bar_2() {} diff --git a/tests/rustdoc/doc-cfg-target-feature.rs b/tests/rustdoc/doc-cfg-target-feature.rs index f1b000dc82362..98d230c978b7e 100644 --- a/tests/rustdoc/doc-cfg-target-feature.rs +++ b/tests/rustdoc/doc-cfg-target-feature.rs @@ -1,7 +1,6 @@ // only-x86_64 // compile-flags:--test // should-fail -// no-system-llvm // #49723: rustdoc didn't add target features when extracting or running doctests diff --git a/tests/rustdoc/footnote-definition-without-blank-line-100638.rs b/tests/rustdoc/footnote-definition-without-blank-line-100638.rs new file mode 100644 index 0000000000000..b6f62c3bcba57 --- /dev/null +++ b/tests/rustdoc/footnote-definition-without-blank-line-100638.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +//! Reference to footnotes A[^1], B[^2] and C[^3]. +//! +//! [^1]: Footnote A. +//! [^2]: Footnote B. +//! [^3]: Footnote C. + +// @has 'foo/index.html' +// @has - '//*[@class="docblock"]/*[@class="footnotes"]/ol/li[@id="fn1"]/p' 'Footnote A' +// @has - '//li[@id="fn1"]/p/a/@href' '#fnref1' +// @has - '//*[@class="docblock"]/*[@class="footnotes"]/ol/li[@id="fn2"]/p' 'Footnote B' +// @has - '//li[@id="fn2"]/p/a/@href' '#fnref2' +// @has - '//*[@class="docblock"]/*[@class="footnotes"]/ol/li[@id="fn3"]/p' 'Footnote C' +// @has - '//li[@id="fn3"]/p/a/@href' '#fnref3' diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs new file mode 100644 index 0000000000000..98cdec107ae08 --- /dev/null +++ b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs @@ -0,0 +1,32 @@ +// This test ensures that non-glob reexports don't get their attributes merge with +// the reexported item whereas glob reexports do. +// Regression test for . + +#![crate_name = "foo"] +#![feature(doc_cfg)] + +// @has 'foo/index.html' +// There are two items. +// @count - '//*[@class="item-table"]//div[@class="item-name"]' 2 +// Only one of them should have an attribute. +// @count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1 + +mod a { + #[doc(cfg(not(feature = "a")))] + #[cfg(not(feature = "a"))] + pub struct Test1; +} + +mod b { + #[doc(cfg(not(feature = "a")))] + #[cfg(not(feature = "a"))] + pub struct Test2; +} + +// @has 'foo/struct.Test1.html' +// @count - '//*[@id="main-content"]/*[@class="item-info"]' 1 +// @has - '//*[@id="main-content"]/*[@class="item-info"]' 'Available on non-crate feature a only.' +pub use a::*; +// @has 'foo/struct.Test2.html' +// @count - '//*[@id="main-content"]/*[@class="item-info"]' 0 +pub use b::Test2; diff --git a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs new file mode 100644 index 0000000000000..68996deae6fda --- /dev/null +++ b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs @@ -0,0 +1,27 @@ +#![crate_name = "foo"] + +// @has 'foo/index.html' +// There should be only `type A`. +// @count - '//*[@class="item-table"]//*[@class="item-name"]' 1 +// @has - '//*[@class="item-name"]/a[@href="type.A.html"]' 'A' + +mod foo { + pub struct S; +} + +use foo::S; + +pub type A = S; + +// @has 'foo/type.A.html' +// @has - '//*[@id="method.default"]/h4' 'fn default() -> Self' +impl Default for A { + fn default() -> Self { + S + } +} + +// @has - '//*[@id="method.a"]/h4' 'pub fn a(&self)' +impl A { + pub fn a(&self) {} +} diff --git a/tests/rustdoc/links-in-headings.rs b/tests/rustdoc/links-in-headings.rs new file mode 100644 index 0000000000000..c5bee1a79750c --- /dev/null +++ b/tests/rustdoc/links-in-headings.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +//! # Heading with [a link](https://a.com) inside +//! +//! And even with +//! +//! ## [multiple](https://b.com) [links](https://c.com) +//! +//! ! + +// @has 'foo/index.html' +// @has - '//h2/a[@href="https://a.com"]' 'a link' +// @has - '//h3/a[@href="https://b.com"]' 'multiple' +// @has - '//h3/a[@href="https://c.com"]' 'links' diff --git a/tests/rustdoc/remove-url-from-headings.rs b/tests/rustdoc/remove-url-from-headings.rs index 599c429a6e1de..8f4770286192e 100644 --- a/tests/rustdoc/remove-url-from-headings.rs +++ b/tests/rustdoc/remove-url-from-headings.rs @@ -1,9 +1,12 @@ +// It actually checks that the link is kept in the headings as expected now. + #![crate_name = "foo"] // @has foo/fn.foo.html -// @!has - '//a[@href="http://a.a"]' '' -// @has - '//a[@href="#implementing-stuff-somewhere"]' 'Implementing stuff somewhere' -// @has - '//a[@href="#another-one-urg"]' 'Another one urg' +// @has - '//a[@href="http://a.a"]' 'stuff' +// @has - '//*[@id="implementing-stuff-somewhere"]' 'Implementing stuff somewhere' +// @has - '//a[@href="http://b.b"]' 'one' +// @has - '//*[@id="another-one-urg"]' 'Another one urg' /// fooo /// @@ -13,5 +16,5 @@ /// /// # Another [one][two] urg /// -/// [two]: http://a.a +/// [two]: http://b.b pub fn foo() {} diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc/short-docblock.rs index 791d3547c9fec..151a42a9c9ee5 100644 --- a/tests/rustdoc/short-docblock.rs +++ b/tests/rustdoc/short-docblock.rs @@ -2,8 +2,9 @@ // @has foo/index.html '//*[@class="desc docblock-short"]' 'fooo' // @!has foo/index.html '//*[@class="desc docblock-short"]/h1' 'fooo' -// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' '§' /// # fooo /// /// foo @@ -11,8 +12,9 @@ pub fn foo() {} // @has foo/index.html '//*[@class="desc docblock-short"]' 'mooood' // @!has foo/index.html '//*[@class="desc docblock-short"]/h2' 'mooood' -// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' '§' /// ## mooood /// /// foo mod diff --git a/tests/ui-fulldeps/internal-lints/query_stability.rs b/tests/ui-fulldeps/internal-lints/query_stability.rs index 560675b448608..627ffa5cbd0f3 100644 --- a/tests/ui-fulldeps/internal-lints/query_stability.rs +++ b/tests/ui-fulldeps/internal-lints/query_stability.rs @@ -21,4 +21,17 @@ fn main() { for _ in x {} //~^ ERROR using `into_iter` + + let x = FxHashMap::::default(); + let _ = x.keys(); + //~^ ERROR using `keys` can result in unstable query results + + let _ = x.values(); + //~^ ERROR using `values` can result in unstable query results + + let mut x = FxHashMap::::default(); + for val in x.values_mut() { + //~^ ERROR using `values_mut` can result in unstable query results + *val = *val + 10; + } } diff --git a/tests/ui-fulldeps/internal-lints/query_stability.stderr b/tests/ui-fulldeps/internal-lints/query_stability.stderr index ee4ef9982371e..43b156dc20a3c 100644 --- a/tests/ui-fulldeps/internal-lints/query_stability.stderr +++ b/tests/ui-fulldeps/internal-lints/query_stability.stderr @@ -35,5 +35,29 @@ LL | for _ in x {} | = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale -error: aborting due to 4 previous errors +error: using `keys` can result in unstable query results + --> $DIR/query_stability.rs:26:15 + | +LL | let _ = x.keys(); + | ^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +error: using `values` can result in unstable query results + --> $DIR/query_stability.rs:29:15 + | +LL | let _ = x.values(); + | ^^^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +error: using `values_mut` can result in unstable query results + --> $DIR/query_stability.rs:33:18 + | +LL | for val in x.values_mut() { + | ^^^^^^^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +error: aborting due to 7 previous errors diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs index ae7f341fe4e33..cce223c77bbab 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -29,6 +29,7 @@ fn main() { TyKind::FnPtr(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Dynamic(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::CoroutineClosure(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Coroutine(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::CoroutineWitness(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Never => (), //~ ERROR usage of `ty::TyKind::` diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 45b7c26faad07..2ff5aad95dd87 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -109,71 +109,77 @@ LL | TyKind::Closure(..) => (), error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:32:9 | -LL | TyKind::Coroutine(..) => (), +LL | TyKind::CoroutineClosure(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:33:9 | -LL | TyKind::CoroutineWitness(..) => (), +LL | TyKind::Coroutine(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:34:9 | -LL | TyKind::Never => (), +LL | TyKind::CoroutineWitness(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:35:9 | -LL | TyKind::Tuple(..) => (), +LL | TyKind::Never => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:36:9 | -LL | TyKind::Alias(..) => (), +LL | TyKind::Tuple(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:37:9 | -LL | TyKind::Param(..) => (), +LL | TyKind::Alias(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:38:9 | -LL | TyKind::Bound(..) => (), +LL | TyKind::Param(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:39:9 | -LL | TyKind::Placeholder(..) => (), +LL | TyKind::Bound(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:40:9 | -LL | TyKind::Infer(..) => (), +LL | TyKind::Placeholder(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:41:9 | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using `ty::` directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:42:9 + | LL | TyKind::Error(_) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` - --> $DIR/ty_tykind_usage.rs:46:12 + --> $DIR/ty_tykind_usage.rs:47:12 | LL | if let TyKind::Int(int_ty) = kind {} | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:48:24 + --> $DIR/ty_tykind_usage.rs:49:24 | LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} | ^^^^^^^^^^ @@ -181,7 +187,7 @@ LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:50:37 + --> $DIR/ty_tykind_usage.rs:51:37 | LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { | ^^^^^^^^^^^ @@ -189,7 +195,7 @@ LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:50:53 + --> $DIR/ty_tykind_usage.rs:51:53 | LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { | ^^^^^^^^^^^ @@ -197,12 +203,12 @@ LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { = help: try using `Ty` instead error: usage of `ty::TyKind::` - --> $DIR/ty_tykind_usage.rs:53:9 + --> $DIR/ty_tykind_usage.rs:54:9 | LL | IrTyKind::Bool | --------^^^^^^ | | | help: try using `ty::` directly: `ty` -error: aborting due to 32 previous errors +error: aborting due to 33 previous errors diff --git a/tests/ui-fulldeps/rustc_encodable_hygiene.rs b/tests/ui-fulldeps/rustc_encodable_hygiene.rs index bec7930d4622f..36c684a131e65 100644 --- a/tests/ui-fulldeps/rustc_encodable_hygiene.rs +++ b/tests/ui-fulldeps/rustc_encodable_hygiene.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(rustc_private)] diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index f553aa96505ec..d3cfd28082d61 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -25,22 +25,26 @@ extern crate rustc_middle; use rustc_middle::ty::Ty; extern crate rustc_errors; -use rustc_errors::{Applicability, DiagnosticMessage, MultiSpan, SubdiagnosticMessage}; +use rustc_errors::{Applicability, DiagnosticMessage, ErrCode, MultiSpan, SubdiagnosticMessage}; extern crate rustc_session; rustc_fluent_macro::fluent_messages! { "./example.ftl" } +// E0123 and E0456 are no longer used, so we define our own constants here just for this test. +const E0123: ErrCode = ErrCode::from_u32(0123); +const E0456: ErrCode = ErrCode::from_u32(0456); + #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct Hello {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct HelloWarn {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] //~^ ERROR unsupported type attribute for diagnostic derive enum enum DiagnosticOnEnum { Foo, @@ -50,53 +54,53 @@ enum DiagnosticOnEnum { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[diag = "E0123"] //~^ ERROR failed to resolve: maybe a missing crate `core` struct WrongStructAttrStyle {} #[derive(Diagnostic)] -#[nonsense(no_crate_example, code = "E0123")] +#[nonsense(no_crate_example, code = E0123)] //~^ ERROR `#[nonsense(...)]` is not a valid attribute //~^^ ERROR diagnostic slug not specified //~^^^ ERROR cannot find attribute `nonsense` in this scope struct InvalidStructAttr {} #[derive(Diagnostic)] -#[diag("E0123")] +#[diag(code = E0123)] //~^ ERROR diagnostic slug not specified struct InvalidLitNestedAttr {} #[derive(Diagnostic)] -#[diag(nonsense, code = "E0123")] +#[diag(nonsense, code = E0123)] //~^ ERROR cannot find value `nonsense` in module `crate::fluent_generated` struct InvalidNestedStructAttr {} #[derive(Diagnostic)] -#[diag(nonsense("foo"), code = "E0123", slug = "foo")] +#[diag(nonsense("foo"), code = E0123, slug = "foo")] //~^ ERROR diagnostic slug must be the first argument //~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr1 {} #[derive(Diagnostic)] -#[diag(nonsense = "...", code = "E0123", slug = "foo")] +#[diag(nonsense = "...", code = E0123, slug = "foo")] //~^ ERROR unknown argument //~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr2 {} #[derive(Diagnostic)] -#[diag(nonsense = 4, code = "E0123", slug = "foo")] +#[diag(nonsense = 4, code = E0123, slug = "foo")] //~^ ERROR unknown argument //~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr3 {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123", slug = "foo")] +#[diag(no_crate_example, code = E0123, slug = "foo")] //~^ ERROR unknown argument struct InvalidNestedStructAttr4 {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct WrongPlaceField { #[suggestion = "bar"] //~^ ERROR `#[suggestion = ...]` is not a valid attribute @@ -104,19 +108,19 @@ struct WrongPlaceField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] -#[diag(no_crate_example, code = "E0456")] +#[diag(no_crate_example, code = E0123)] +#[diag(no_crate_example, code = E0456)] //~^ ERROR specified multiple times //~^^ ERROR specified multiple times struct DiagSpecifiedTwice {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0456", code = "E0457")] +#[diag(no_crate_example, code = E0123, code = E0456)] //~^ ERROR specified multiple times struct CodeSpecifiedTwice {} #[derive(Diagnostic)] -#[diag(no_crate_example, no_crate::example, code = "E0456")] +#[diag(no_crate_example, no_crate::example, code = E0123)] //~^ ERROR diagnostic slug must be the first argument struct SlugSpecifiedTwice {} @@ -124,7 +128,7 @@ struct SlugSpecifiedTwice {} struct KindNotProvided {} //~ ERROR diagnostic slug not specified #[derive(Diagnostic)] -#[diag(code = "E0456")] +#[diag(code = E0123)] //~^ ERROR diagnostic slug not specified struct SlugNotProvided {} @@ -133,7 +137,7 @@ struct SlugNotProvided {} struct CodeNotProvided {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct MessageWrongType { #[primary_span] //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` @@ -141,7 +145,7 @@ struct MessageWrongType { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct InvalidPathFieldAttr { #[nonsense] //~^ ERROR `#[nonsense]` is not a valid attribute @@ -150,7 +154,7 @@ struct InvalidPathFieldAttr { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithField { name: String, #[label(no_crate_label)] @@ -158,7 +162,7 @@ struct ErrorWithField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithMessageAppliedToField { #[label(no_crate_label)] //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` @@ -166,7 +170,7 @@ struct ErrorWithMessageAppliedToField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithNonexistentField { #[suggestion(no_crate_suggestion, code = "{name}")] //~^ ERROR `name` doesn't refer to a field on this type @@ -175,7 +179,7 @@ struct ErrorWithNonexistentField { #[derive(Diagnostic)] //~^ ERROR invalid format string: expected `'}'` -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorMissingClosingBrace { #[suggestion(no_crate_suggestion, code = "{name")] suggestion: (Span, Applicability), @@ -185,7 +189,7 @@ struct ErrorMissingClosingBrace { #[derive(Diagnostic)] //~^ ERROR invalid format string: unmatched `}` -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorMissingOpeningBrace { #[suggestion(no_crate_suggestion, code = "name}")] suggestion: (Span, Applicability), @@ -194,14 +198,14 @@ struct ErrorMissingOpeningBrace { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelOnSpan { #[label(no_crate_label)] sp: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelOnNonSpan { #[label(no_crate_label)] //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` @@ -209,7 +213,7 @@ struct LabelOnNonSpan { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct Suggest { #[suggestion(no_crate_suggestion, code = "This is the suggested code")] #[suggestion(no_crate_suggestion, code = "This is the suggested code", style = "normal")] @@ -220,7 +224,7 @@ struct Suggest { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithoutCode { #[suggestion(no_crate_suggestion)] //~^ ERROR suggestion without `code = "..."` @@ -228,7 +232,7 @@ struct SuggestWithoutCode { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithBadKey { #[suggestion(nonsense = "bar")] //~^ ERROR invalid nested attribute @@ -237,7 +241,7 @@ struct SuggestWithBadKey { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithShorthandMsg { #[suggestion(msg = "bar")] //~^ ERROR invalid nested attribute @@ -246,21 +250,21 @@ struct SuggestWithShorthandMsg { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithoutMsg { #[suggestion(code = "bar")] suggestion: (Span, Applicability), } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithTypesSwapped { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: (Applicability, Span), } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithWrongTypeApplicabilityOnly { #[suggestion(no_crate_suggestion, code = "This is suggested code")] //~^ ERROR wrong field type for suggestion @@ -268,14 +272,14 @@ struct SuggestWithWrongTypeApplicabilityOnly { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithSpanOnly { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithDuplicateSpanAndApplicability { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: (Span, Span, Applicability), @@ -283,7 +287,7 @@ struct SuggestWithDuplicateSpanAndApplicability { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithDuplicateApplicabilityAndSpan { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: (Applicability, Applicability, Span), @@ -291,7 +295,7 @@ struct SuggestWithDuplicateApplicabilityAndSpan { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct WrongKindOfAnnotation { #[label = "bar"] //~^ ERROR `#[label = ...]` is not a valid attribute @@ -299,7 +303,7 @@ struct WrongKindOfAnnotation { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct OptionsInErrors { #[label(no_crate_label)] label: Option, @@ -308,7 +312,7 @@ struct OptionsInErrors { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0456")] +#[diag(no_crate_example, code = E0123)] struct MoveOutOfBorrowError<'tcx> { name: Ident, ty: Ty<'tcx>, @@ -322,7 +326,7 @@ struct MoveOutOfBorrowError<'tcx> { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithLifetime<'a> { #[label(no_crate_label)] span: Span, @@ -330,7 +334,7 @@ struct ErrorWithLifetime<'a> { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithDefaultLabelAttr<'a> { #[label] span: Span, @@ -338,7 +342,7 @@ struct ErrorWithDefaultLabelAttr<'a> { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ArgFieldWithoutSkip { #[primary_span] span: Span, @@ -347,7 +351,7 @@ struct ArgFieldWithoutSkip { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ArgFieldWithSkip { #[primary_span] span: Span, @@ -358,56 +362,56 @@ struct ArgFieldWithSkip { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedNote { #[note] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedNoteCustom { #[note(no_crate_note)] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[note] struct ErrorWithNote { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[note(no_crate_note)] struct ErrorWithNoteCustom { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedHelp { #[help] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedHelpCustom { #[help(no_crate_help)] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[help] struct ErrorWithHelp { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[help(no_crate_help)] struct ErrorWithHelpCustom { val: String, @@ -415,34 +419,34 @@ struct ErrorWithHelpCustom { #[derive(Diagnostic)] #[help] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithHelpWrongOrder { val: String, } #[derive(Diagnostic)] #[help(no_crate_help)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithHelpCustomWrongOrder { val: String, } #[derive(Diagnostic)] #[note] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithNoteWrongOrder { val: String, } #[derive(Diagnostic)] #[note(no_crate_note)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithNoteCustomWrongOrder { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ApplicabilityInBoth { #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] //~^ ERROR specified multiple times @@ -450,7 +454,7 @@ struct ApplicabilityInBoth { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct InvalidApplicability { #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] //~^ ERROR invalid applicability @@ -458,14 +462,14 @@ struct InvalidApplicability { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ValidApplicability { #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] suggestion: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct NoApplicability { #[suggestion(no_crate_suggestion, code = "...")] suggestion: Span, @@ -483,7 +487,7 @@ struct Subdiagnostic { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct VecField { #[primary_span] #[label] @@ -491,7 +495,7 @@ struct VecField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct UnitField { #[primary_span] spans: Span, @@ -502,7 +506,7 @@ struct UnitField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct OptUnitField { #[primary_span] spans: Span, @@ -526,7 +530,7 @@ struct BoolField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelWithTrailingPath { #[label(no_crate_label, foo)] //~^ ERROR a diagnostic slug must be the first argument to the attribute @@ -534,7 +538,7 @@ struct LabelWithTrailingPath { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelWithTrailingNameValue { #[label(no_crate_label, foo = "...")] //~^ ERROR only `no_span` is a valid nested attribute @@ -542,7 +546,7 @@ struct LabelWithTrailingNameValue { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelWithTrailingList { #[label(no_crate_label, foo("..."))] //~^ ERROR only `no_span` is a valid nested attribute @@ -562,42 +566,42 @@ struct PrimarySpanOnLint { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithMultiSpan { #[primary_span] span: MultiSpan, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[warning] struct ErrorWithWarn { val: String, } #[derive(Diagnostic)] -#[error(no_crate_example, code = "E0123")] +#[error(no_crate_example, code = E0123)] //~^ ERROR `#[error(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified //~| ERROR cannot find attribute `error` in this scope struct ErrorAttribute {} #[derive(Diagnostic)] -#[warn_(no_crate_example, code = "E0123")] +#[warn_(no_crate_example, code = E0123)] //~^ ERROR `#[warn_(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified //~| ERROR cannot find attribute `warn_` in this scope struct WarnAttribute {} #[derive(Diagnostic)] -#[lint(no_crate_example, code = "E0123")] +#[lint(no_crate_example, code = E0123)] //~^ ERROR `#[lint(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified //~| ERROR cannot find attribute `lint` in this scope struct LintAttributeOnSessionDiag {} #[derive(LintDiagnostic)] -#[lint(no_crate_example, code = "E0123")] +#[lint(no_crate_example, code = E0123)] //~^ ERROR `#[lint(...)]` is not a valid attribute //~| ERROR `#[lint(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified @@ -605,7 +609,7 @@ struct LintAttributeOnSessionDiag {} struct LintAttributeOnLintDiag {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct DuplicatedSuggestionCode { #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] //~^ ERROR specified multiple times @@ -613,7 +617,7 @@ struct DuplicatedSuggestionCode { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct InvalidTypeInSuggestionTuple { #[suggestion(no_crate_suggestion, code = "...")] suggestion: (Span, usize), @@ -621,7 +625,7 @@ struct InvalidTypeInSuggestionTuple { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct MissingApplicabilityInSuggestionTuple { #[suggestion(no_crate_suggestion, code = "...")] suggestion: (Span,), @@ -629,7 +633,7 @@ struct MissingApplicabilityInSuggestionTuple { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct MissingCodeInSuggestion { #[suggestion(no_crate_suggestion)] //~^ ERROR suggestion without `code = "..."` @@ -637,7 +641,7 @@ struct MissingCodeInSuggestion { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[multipart_suggestion(no_crate_suggestion)] //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute //~| ERROR cannot find attribute `multipart_suggestion` in this scope @@ -652,7 +656,7 @@ struct MultipartSuggestion { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[suggestion(no_crate_suggestion, code = "...")] //~^ ERROR `#[suggestion(...)]` is not a valid attribute struct SuggestionOnStruct { @@ -661,7 +665,7 @@ struct SuggestionOnStruct { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[label] //~^ ERROR `#[label]` is not a valid attribute struct LabelOnStruct { @@ -688,7 +692,7 @@ enum ExampleEnum { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct RawIdentDiagnosticArg { pub r#type: String, } @@ -762,7 +766,7 @@ struct SubdiagnosticEagerSuggestion { /// with a doc comment on the type.. #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct WithDocComment { /// ..and the field #[primary_span] diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f376c034587fa..67257c28b6eb0 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,11 +1,11 @@ error: unsupported type attribute for diagnostic derive enum - --> $DIR/diagnostic-derive.rs:43:1 + --> $DIR/diagnostic-derive.rs:47:1 | -LL | #[diag(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[diag(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:46:5 + --> $DIR/diagnostic-derive.rs:50:5 | LL | Foo, | ^^^ @@ -13,7 +13,7 @@ LL | Foo, = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:48:5 + --> $DIR/diagnostic-derive.rs:52:5 | LL | Bar, | ^^^ @@ -21,15 +21,15 @@ LL | Bar, = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[nonsense(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:59:1 + --> $DIR/diagnostic-derive.rs:63:1 | -LL | #[nonsense(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[nonsense(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:59:1 + --> $DIR/diagnostic-derive.rs:63:1 | -LL | / #[nonsense(no_crate_example, code = "E0123")] +LL | / #[nonsense(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -39,9 +39,9 @@ LL | | struct InvalidStructAttr {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:66:1 + --> $DIR/diagnostic-derive.rs:70:1 | -LL | / #[diag("E0123")] +LL | / #[diag(code = E0123)] LL | | LL | | struct InvalidLitNestedAttr {} | |______________________________^ @@ -49,15 +49,15 @@ LL | | struct InvalidLitNestedAttr {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug must be the first argument - --> $DIR/diagnostic-derive.rs:76:16 + --> $DIR/diagnostic-derive.rs:80:16 | -LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")] +LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] | ^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:76:1 + --> $DIR/diagnostic-derive.rs:80:1 | -LL | / #[diag(nonsense("foo"), code = "E0123", slug = "foo")] +LL | / #[diag(nonsense("foo"), code = E0123, slug = "foo")] LL | | LL | | LL | | struct InvalidNestedStructAttr1 {} @@ -66,17 +66,17 @@ LL | | struct InvalidNestedStructAttr1 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:82:8 + --> $DIR/diagnostic-derive.rs:86:8 | -LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")] +LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] | ^^^^^^^^ | = note: only the `code` parameter is valid after the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:82:1 + --> $DIR/diagnostic-derive.rs:86:1 | -LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")] +LL | / #[diag(nonsense = "...", code = E0123, slug = "foo")] LL | | LL | | LL | | struct InvalidNestedStructAttr2 {} @@ -85,17 +85,17 @@ LL | | struct InvalidNestedStructAttr2 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:88:8 + --> $DIR/diagnostic-derive.rs:92:8 | -LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")] +LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] | ^^^^^^^^ | = note: only the `code` parameter is valid after the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:88:1 + --> $DIR/diagnostic-derive.rs:92:1 | -LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")] +LL | / #[diag(nonsense = 4, code = E0123, slug = "foo")] LL | | LL | | LL | | struct InvalidNestedStructAttr3 {} @@ -104,63 +104,63 @@ LL | | struct InvalidNestedStructAttr3 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:94:42 + --> $DIR/diagnostic-derive.rs:98:40 | -LL | #[diag(no_crate_example, code = "E0123", slug = "foo")] - | ^^^^ +LL | #[diag(no_crate_example, code = E0123, slug = "foo")] + | ^^^^ | = note: only the `code` parameter is valid after the slug error: `#[suggestion = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:101:5 + --> $DIR/diagnostic-derive.rs:105:5 | LL | #[suggestion = "bar"] | ^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:108:8 + --> $DIR/diagnostic-derive.rs:112:8 | -LL | #[diag(no_crate_example, code = "E0456")] +LL | #[diag(no_crate_example, code = E0456)] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:107:8 + --> $DIR/diagnostic-derive.rs:111:8 | -LL | #[diag(no_crate_example, code = "E0123")] +LL | #[diag(no_crate_example, code = E0123)] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:108:26 + --> $DIR/diagnostic-derive.rs:112:26 | -LL | #[diag(no_crate_example, code = "E0456")] +LL | #[diag(no_crate_example, code = E0456)] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:107:26 + --> $DIR/diagnostic-derive.rs:111:26 | -LL | #[diag(no_crate_example, code = "E0123")] +LL | #[diag(no_crate_example, code = E0123)] | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:114:42 + --> $DIR/diagnostic-derive.rs:118:40 | -LL | #[diag(no_crate_example, code = "E0456", code = "E0457")] - | ^^^^ +LL | #[diag(no_crate_example, code = E0123, code = E0456)] + | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:114:26 + --> $DIR/diagnostic-derive.rs:118:26 | -LL | #[diag(no_crate_example, code = "E0456", code = "E0457")] +LL | #[diag(no_crate_example, code = E0123, code = E0456)] | ^^^^ error: diagnostic slug must be the first argument - --> $DIR/diagnostic-derive.rs:119:43 + --> $DIR/diagnostic-derive.rs:123:43 | -LL | #[diag(no_crate_example, no_crate::example, code = "E0456")] +LL | #[diag(no_crate_example, no_crate::example, code = E0123)] | ^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:124:1 + --> $DIR/diagnostic-derive.rs:128:1 | LL | struct KindNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,9 +168,9 @@ LL | struct KindNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:127:1 + --> $DIR/diagnostic-derive.rs:131:1 | -LL | / #[diag(code = "E0456")] +LL | / #[diag(code = E0123)] LL | | LL | | struct SlugNotProvided {} | |_________________________^ @@ -178,31 +178,31 @@ LL | | struct SlugNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:138:5 + --> $DIR/diagnostic-derive.rs:142:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: `#[nonsense]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:146:5 + --> $DIR/diagnostic-derive.rs:150:5 | LL | #[nonsense] | ^^^^^^^^^^^ error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:163:5 + --> $DIR/diagnostic-derive.rs:167:5 | LL | #[label(no_crate_label)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/diagnostic-derive.rs:171:46 + --> $DIR/diagnostic-derive.rs:175:46 | LL | #[suggestion(no_crate_suggestion, code = "{name}")] | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:176:10 + --> $DIR/diagnostic-derive.rs:180:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ expected `'}'` in format string @@ -211,7 +211,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:186:10 + --> $DIR/diagnostic-derive.rs:190:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ unmatched `}` in format string @@ -220,19 +220,19 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:206:5 + --> $DIR/diagnostic-derive.rs:210:5 | LL | #[label(no_crate_label)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:225:5 + --> $DIR/diagnostic-derive.rs:229:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid nested attribute - --> $DIR/diagnostic-derive.rs:233:18 + --> $DIR/diagnostic-derive.rs:237:18 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^ @@ -240,13 +240,13 @@ LL | #[suggestion(nonsense = "bar")] = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:233:5 + --> $DIR/diagnostic-derive.rs:237:5 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid nested attribute - --> $DIR/diagnostic-derive.rs:242:18 + --> $DIR/diagnostic-derive.rs:246:18 | LL | #[suggestion(msg = "bar")] | ^^^ @@ -254,13 +254,13 @@ LL | #[suggestion(msg = "bar")] = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:242:5 + --> $DIR/diagnostic-derive.rs:246:5 | LL | #[suggestion(msg = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wrong field type for suggestion - --> $DIR/diagnostic-derive.rs:265:5 + --> $DIR/diagnostic-derive.rs:269:5 | LL | / #[suggestion(no_crate_suggestion, code = "This is suggested code")] LL | | @@ -270,79 +270,79 @@ LL | | suggestion: Applicability, = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` error: specified multiple times - --> $DIR/diagnostic-derive.rs:281:24 + --> $DIR/diagnostic-derive.rs:285:24 | LL | suggestion: (Span, Span, Applicability), | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:281:18 + --> $DIR/diagnostic-derive.rs:285:18 | LL | suggestion: (Span, Span, Applicability), | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:289:33 + --> $DIR/diagnostic-derive.rs:293:33 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:289:18 + --> $DIR/diagnostic-derive.rs:293:18 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ error: `#[label = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:296:5 + --> $DIR/diagnostic-derive.rs:300:5 | LL | #[label = "bar"] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:447:5 + --> $DIR/diagnostic-derive.rs:451:5 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:449:24 + --> $DIR/diagnostic-derive.rs:453:24 | LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:455:69 + --> $DIR/diagnostic-derive.rs:459:69 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` - --> $DIR/diagnostic-derive.rs:522:5 + --> $DIR/diagnostic-derive.rs:526:5 | LL | #[help(no_crate_help)] | ^^^^^^^^^^^^^^^^^^^^^^ error: a diagnostic slug must be the first argument to the attribute - --> $DIR/diagnostic-derive.rs:531:32 + --> $DIR/diagnostic-derive.rs:535:32 | LL | #[label(no_crate_label, foo)] | ^ error: only `no_span` is a valid nested attribute - --> $DIR/diagnostic-derive.rs:539:29 + --> $DIR/diagnostic-derive.rs:543:29 | LL | #[label(no_crate_label, foo = "...")] | ^^^ error: only `no_span` is a valid nested attribute - --> $DIR/diagnostic-derive.rs:547:29 + --> $DIR/diagnostic-derive.rs:551:29 | LL | #[label(no_crate_label, foo("..."))] | ^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:559:5 + --> $DIR/diagnostic-derive.rs:563:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -350,15 +350,15 @@ LL | #[primary_span] = help: the `primary_span` field attribute is not valid for lint diagnostics error: `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:579:1 + --> $DIR/diagnostic-derive.rs:583:1 | -LL | #[error(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:579:1 + --> $DIR/diagnostic-derive.rs:583:1 | -LL | / #[error(no_crate_example, code = "E0123")] +LL | / #[error(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -368,15 +368,15 @@ LL | | struct ErrorAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:586:1 + --> $DIR/diagnostic-derive.rs:590:1 | -LL | #[warn_(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn_(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:586:1 + --> $DIR/diagnostic-derive.rs:590:1 | -LL | / #[warn_(no_crate_example, code = "E0123")] +LL | / #[warn_(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -386,15 +386,15 @@ LL | | struct WarnAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:593:1 + --> $DIR/diagnostic-derive.rs:597:1 | -LL | #[lint(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:593:1 + --> $DIR/diagnostic-derive.rs:597:1 | -LL | / #[lint(no_crate_example, code = "E0123")] +LL | / #[lint(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -404,23 +404,23 @@ LL | | struct LintAttributeOnSessionDiag {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:600:1 + --> $DIR/diagnostic-derive.rs:604:1 | -LL | #[lint(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:600:1 + --> $DIR/diagnostic-derive.rs:604:1 | -LL | #[lint(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:600:1 + --> $DIR/diagnostic-derive.rs:604:1 | -LL | / #[lint(no_crate_example, code = "E0123")] +LL | / #[lint(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -431,19 +431,19 @@ LL | | struct LintAttributeOnLintDiag {} = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` error: specified multiple times - --> $DIR/diagnostic-derive.rs:610:53 + --> $DIR/diagnostic-derive.rs:614:53 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:610:39 + --> $DIR/diagnostic-derive.rs:614:39 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:619:24 + --> $DIR/diagnostic-derive.rs:623:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -451,7 +451,7 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:627:17 + --> $DIR/diagnostic-derive.rs:631:17 | LL | suggestion: (Span,), | ^^^^^^^ @@ -459,13 +459,13 @@ LL | suggestion: (Span,), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:634:5 + --> $DIR/diagnostic-derive.rs:638:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:641:1 + --> $DIR/diagnostic-derive.rs:645:1 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -473,7 +473,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:644:1 + --> $DIR/diagnostic-derive.rs:648:1 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +481,7 @@ LL | #[multipart_suggestion()] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:648:5 + --> $DIR/diagnostic-derive.rs:652:5 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:656:1 + --> $DIR/diagnostic-derive.rs:660:1 | LL | #[suggestion(no_crate_suggestion, code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `#[label]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:665:1 + --> $DIR/diagnostic-derive.rs:669:1 | LL | #[label] | ^^^^^^^^ @@ -505,31 +505,31 @@ LL | #[label] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:699:7 + --> $DIR/diagnostic-derive.rs:703:7 | LL | #[subdiagnostic(bad)] | ^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:707:5 + --> $DIR/diagnostic-derive.rs:711:5 | LL | #[subdiagnostic = "bad"] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:715:7 + --> $DIR/diagnostic-derive.rs:719:7 | LL | #[subdiagnostic(bad, bad)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:723:7 + --> $DIR/diagnostic-derive.rs:727:7 | LL | #[subdiagnostic("bad")] | ^^^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:731:5 + --> $DIR/diagnostic-derive.rs:735:5 | LL | #[subdiagnostic(eager)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -537,19 +537,19 @@ LL | #[subdiagnostic(eager)] = help: eager subdiagnostics are not supported on lints error: expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive.rs:789:23 + --> $DIR/diagnostic-derive.rs:793:23 | LL | #[suggestion(code())] | ^ error: `code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:797:23 + --> $DIR/diagnostic-derive.rs:801:23 | LL | #[suggestion(code(foo))] | ^^^ error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:821:5 + --> $DIR/diagnostic-derive.rs:825:5 | LL | #[suggestion(no_crate_suggestion, code = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -559,85 +559,85 @@ LL | #[suggestion(no_crate_suggestion, code = "")] = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]` error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:54:8 + --> $DIR/diagnostic-derive.rs:58:8 | LL | #[diag = "E0123"] | ^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:797:23 + --> $DIR/diagnostic-derive.rs:801:23 | LL | #[suggestion(code(foo))] | ^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:806:25 + --> $DIR/diagnostic-derive.rs:810:25 | LL | #[suggestion(code = 3)] | ^ maybe a missing crate `core`? error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:59:3 + --> $DIR/diagnostic-derive.rs:63:3 | -LL | #[nonsense(no_crate_example, code = "E0123")] +LL | #[nonsense(no_crate_example, code = E0123)] | ^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:146:7 + --> $DIR/diagnostic-derive.rs:150:7 | LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive.rs:579:3 + --> $DIR/diagnostic-derive.rs:583:3 | -LL | #[error(no_crate_example, code = "E0123")] +LL | #[error(no_crate_example, code = E0123)] | ^^^^^ error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive.rs:586:3 + --> $DIR/diagnostic-derive.rs:590:3 | -LL | #[warn_(no_crate_example, code = "E0123")] +LL | #[warn_(no_crate_example, code = E0123)] | ^^^^^ help: a built-in attribute with a similar name exists: `warn` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:593:3 + --> $DIR/diagnostic-derive.rs:597:3 | -LL | #[lint(no_crate_example, code = "E0123")] +LL | #[lint(no_crate_example, code = E0123)] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:600:3 + --> $DIR/diagnostic-derive.rs:604:3 | -LL | #[lint(no_crate_example, code = "E0123")] +LL | #[lint(no_crate_example, code = E0123)] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:641:3 + --> $DIR/diagnostic-derive.rs:645:3 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:644:3 + --> $DIR/diagnostic-derive.rs:648:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:648:7 + --> $DIR/diagnostic-derive.rs:652:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated` - --> $DIR/diagnostic-derive.rs:71:8 + --> $DIR/diagnostic-derive.rs:75:8 | -LL | #[diag(nonsense, code = "E0123")] +LL | #[diag(nonsense, code = E0123)] | ^^^^^^^^ not found in `crate::fluent_generated` error[E0425]: cannot find value `__code_34` in this scope - --> $DIR/diagnostic-derive.rs:803:10 + --> $DIR/diagnostic-derive.rs:807:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ not found in this scope @@ -645,7 +645,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive.rs:345:12 + --> $DIR/diagnostic-derive.rs:349:12 | LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs index a0a8114e0c5c5..3056ebb7575fd 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs @@ -19,6 +19,6 @@ use rustc_errors::{Applicability, MultiSpan}; extern crate rustc_session; #[derive(Diagnostic)] -#[diag(compiletest_example, code = "E0123")] +#[diag(compiletest_example, code = E0123)] //~^ ERROR diagnostic slug and crate name do not match struct Hello {} diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr index 4cdc24e6a6bc9..df1bad3cad0cf 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr @@ -1,7 +1,7 @@ error: diagnostic slug and crate name do not match --> $DIR/enforce_slug_naming.rs:22:8 | -LL | #[diag(compiletest_example, code = "E0123")] +LL | #[diag(compiletest_example, code = E0123)] | ^^^^^^^^^^^^^^^^^^^ | = note: slug is `compiletest_example` but the crate name is `rustc_dummy` diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index b4faaeb4fc06d..e23b0f6820a7d 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -26,11 +26,11 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation(_tcx: TyCtxt) -> ControlFlow<()> { +fn test_translation(tcx: TyCtxt<'_>) -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; - let rustc_ty = rustc_internal::internal(&orig_ty); + let rustc_ty = rustc_internal::internal(tcx, &orig_ty); assert!(rustc_ty.is_unit()); ControlFlow::Continue(()) } diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index d7b4e6150ff31..72a9519e3e772 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,59 +1,53 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 - | -LL | extern "amdgpu-kernel" fn amdgpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:34:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:42:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:41:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:46:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:51:1 + --> $DIR/unsupported.rs:48:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:53:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:62:1 + --> $DIR/unsupported.rs:59:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,6 +56,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 9 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 3a3ed2dd9c569..473b59a334df3 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,53 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 - | -LL | extern "amdgpu-kernel" fn amdgpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:34:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:42:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:41:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:46:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:51:1 + --> $DIR/unsupported.rs:48:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:53:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:62:1 + --> $DIR/unsupported.rs:59:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 31b7d030bd3b4..f0af3d251e245 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,45 +1,39 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 - | -LL | extern "amdgpu-kernel" fn amdgpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:34:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:42:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:41:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:46:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 1966e18f0a06e..b466a2a6ff86b 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,53 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 - | -LL | extern "amdgpu-kernel" fn amdgpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:34:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:42:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:41:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:51:1 + --> $DIR/unsupported.rs:48:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:53:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:62:1 + --> $DIR/unsupported.rs:59:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 1966e18f0a06e..b466a2a6ff86b 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,53 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 - | -LL | extern "amdgpu-kernel" fn amdgpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:34:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:42:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:41:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:51:1 + --> $DIR/unsupported.rs:48:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:53:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:62:1 + --> $DIR/unsupported.rs:59:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 57278e664b51e..9b99e51905da2 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -19,7 +19,6 @@ abi_ptx, abi_msp430_interrupt, abi_avr_interrupt, - abi_amdgpu_kernel, wasm_abi, abi_x86_interrupt, abi_riscv_interrupt @@ -29,8 +28,6 @@ trait Sized {} extern "ptx-kernel" fn ptx() {} //~^ ERROR is not a supported ABI -extern "amdgpu-kernel" fn amdgpu() {} -//~^ ERROR is not a supported ABI extern "wasm" fn wasm() {} //~^ ERROR is not a supported ABI extern "aapcs" fn aapcs() {} diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index ea62cb1514807..4a2b7e7496920 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,53 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 - | -LL | extern "amdgpu-kernel" fn amdgpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:34:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:42:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:41:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:46:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:53:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:62:1 + --> $DIR/unsupported.rs:59:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/anon-params/anon-params-deprecated.fixed b/tests/ui/anon-params/anon-params-deprecated.fixed index c09e20770846e..8ec1d41a70985 100644 --- a/tests/ui/anon-params/anon-params-deprecated.fixed +++ b/tests/ui/anon-params/anon-params-deprecated.fixed @@ -5,6 +5,7 @@ // edition:2015 // run-rustfix +#[allow(dead_code)] trait T { fn foo(_: i32); //~ WARNING anonymous parameters are deprecated //~| WARNING this is accepted in the current edition diff --git a/tests/ui/anon-params/anon-params-deprecated.rs b/tests/ui/anon-params/anon-params-deprecated.rs index 6f7385da040c5..108ba60a02f58 100644 --- a/tests/ui/anon-params/anon-params-deprecated.rs +++ b/tests/ui/anon-params/anon-params-deprecated.rs @@ -5,6 +5,7 @@ // edition:2015 // run-rustfix +#[allow(dead_code)] trait T { fn foo(i32); //~ WARNING anonymous parameters are deprecated //~| WARNING this is accepted in the current edition diff --git a/tests/ui/anon-params/anon-params-deprecated.stderr b/tests/ui/anon-params/anon-params-deprecated.stderr index 691e2c7951249..541cb004b5b2c 100644 --- a/tests/ui/anon-params/anon-params-deprecated.stderr +++ b/tests/ui/anon-params/anon-params-deprecated.stderr @@ -1,5 +1,5 @@ warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/anon-params-deprecated.rs:9:12 + --> $DIR/anon-params-deprecated.rs:10:12 | LL | fn foo(i32); | ^^^ help: try naming the parameter or explicitly ignoring it: `_: i32` @@ -13,7 +13,7 @@ LL | #![warn(anonymous_parameters)] | ^^^^^^^^^^^^^^^^^^^^ warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/anon-params-deprecated.rs:12:30 + --> $DIR/anon-params-deprecated.rs:13:30 | LL | fn bar_with_default_impl(String, String) {} | ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String` @@ -22,7 +22,7 @@ LL | fn bar_with_default_impl(String, String) {} = note: for more information, see issue #41686 warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/anon-params-deprecated.rs:12:38 + --> $DIR/anon-params-deprecated.rs:13:38 | LL | fn bar_with_default_impl(String, String) {} | ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String` diff --git a/tests/ui/anonymous-higher-ranked-lifetime.stderr b/tests/ui/anonymous-higher-ranked-lifetime.stderr index e441cbdc866a1..cc27a0fcf95f5 100644 --- a/tests/ui/anonymous-higher-ranked-lifetime.stderr +++ b/tests/ui/anonymous-higher-ranked-lifetime.stderr @@ -2,8 +2,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 | LL | f1(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _` @@ -22,8 +23,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 | LL | f2(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _` @@ -42,8 +44,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 | LL | f3(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a> fn(&(), &'a ()) -> _` @@ -62,8 +65,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 | LL | f4(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'r, 'a> fn(&'a (), &'r ()) -> _` @@ -82,8 +86,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 | LL | f5(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'r> fn(&'r (), &'r ()) -> _` @@ -102,8 +107,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 | LL | g1(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` @@ -122,8 +128,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | LL | g2(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _` @@ -142,8 +149,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 | LL | g3(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` @@ -162,8 +170,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | LL | g4(|_: (), _: ()| {}); - | ^^ -------------- found signature defined here - | | + | ^^^--------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _` @@ -182,8 +191,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 | LL | h1(|_: (), _: (), _: (), _: ()| {}); - | ^^ ---------------------------- found signature defined here - | | + | ^^^----------------------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'a, 'b> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'b (), for<'a, 'b> fn(&'a (), &'b ())) -> _` @@ -202,8 +212,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 | LL | h2(|_: (), _: (), _: (), _: ()| {}); - | ^^ ---------------------------- found signature defined here - | | + | ^^^----------------------------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `for<'t0, 'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'t0 (), for<'a, 'b> fn(&'a (), &'b ())) -> _` diff --git a/tests/ui/array-slice-vec/repeat_empty_ok.stderr b/tests/ui/array-slice-vec/repeat_empty_ok.stderr index e8bac04ac4503..c272d47d9617f 100644 --- a/tests/ui/array-slice-vec/repeat_empty_ok.stderr +++ b/tests/ui/array-slice-vec/repeat_empty_ok.stderr @@ -5,6 +5,8 @@ LL | let headers = [Header{value: &[]}; 128]; | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` | = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Header<'_>` with `#[derive(Copy)]` | LL + #[derive(Copy)] @@ -18,6 +20,8 @@ LL | let headers = [Header{value: &[0]}; 128]; | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` | = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Header<'_>` with `#[derive(Copy)]` | LL + #[derive(Copy)] diff --git a/tests/ui/array-slice-vec/vec-matching-autoslice.rs b/tests/ui/array-slice-vec/vec-matching-autoslice.rs index 8179edf420cb0..f839cd62b1a5d 100644 --- a/tests/ui/array-slice-vec/vec-matching-autoslice.rs +++ b/tests/ui/array-slice-vec/vec-matching-autoslice.rs @@ -1,5 +1,4 @@ // run-pass -#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620 pub fn main() { let x = [1, 2, 3]; diff --git a/tests/ui/asm/aarch64/type-check-3.rs b/tests/ui/asm/aarch64/type-check-3.rs index 623f6593d79ba..77524ba7aa5e4 100644 --- a/tests/ui/asm/aarch64/type-check-3.rs +++ b/tests/ui/asm/aarch64/type-check-3.rs @@ -1,7 +1,7 @@ // only-aarch64 // compile-flags: -C target-feature=+neon -#![feature(repr_simd, stdsimd, asm_const)] +#![feature(repr_simd, asm_const)] use std::arch::aarch64::float64x2_t; use std::arch::{asm, global_asm}; diff --git a/tests/ui/asm/aarch64/type-check-4.rs b/tests/ui/asm/aarch64/type-check-4.rs index bd23755c02316..5dec60a2138d9 100644 --- a/tests/ui/asm/aarch64/type-check-4.rs +++ b/tests/ui/asm/aarch64/type-check-4.rs @@ -1,7 +1,7 @@ // only-aarch64 // compile-flags: -C target-feature=+neon -#![feature(repr_simd, stdsimd, asm_const)] +#![feature(repr_simd, asm_const)] use std::arch::aarch64::float64x2_t; use std::arch::{asm, global_asm}; diff --git a/tests/ui/associated-consts/associated-const-outer-ty-refs.rs b/tests/ui/associated-consts/associated-const-outer-ty-refs.rs index f32ca0cccfc91..d5e9a2bde0060 100644 --- a/tests/ui/associated-consts/associated-const-outer-ty-refs.rs +++ b/tests/ui/associated-consts/associated-const-outer-ty-refs.rs @@ -1,4 +1,5 @@ -// run-pass +// check-pass + trait Lattice { const BOTTOM: Self; } diff --git a/tests/ui/associated-consts/associated-const-type-parameters.rs b/tests/ui/associated-consts/associated-const-type-parameters.rs index b62d47458be5e..a233b09ff89c6 100644 --- a/tests/ui/associated-consts/associated-const-type-parameters.rs +++ b/tests/ui/associated-consts/associated-const-type-parameters.rs @@ -27,7 +27,7 @@ fn sub() -> i32 { A::X - B::X } -trait Bar: Foo { +trait Bar: Foo { //~ WARN trait `Bar` is never used const Y: i32 = Self::X; } diff --git a/tests/ui/associated-consts/associated-const-type-parameters.stderr b/tests/ui/associated-consts/associated-const-type-parameters.stderr new file mode 100644 index 0000000000000..6ee2a5de1b6ad --- /dev/null +++ b/tests/ui/associated-consts/associated-const-type-parameters.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/associated-const-type-parameters.rs:30:7 + | +LL | trait Bar: Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-consts/issue-105330.rs b/tests/ui/associated-consts/issue-105330.rs index 6c6dae864f340..285e89cce4985 100644 --- a/tests/ui/associated-consts/issue-105330.rs +++ b/tests/ui/associated-consts/issue-105330.rs @@ -14,6 +14,5 @@ fn foo>() { //~ ERROR E0658 fn main>() { //~^ ERROR E0658 - //~| ERROR E0131 foo::(); } diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index b4c021d0f4fdc..452367bed1201 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -43,13 +43,7 @@ LL | impl TraitWAssocConst for impl Demo { | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0131]: `main` function is not allowed to have generic parameters - --> $DIR/issue-105330.rs:15:8 - | -LL | fn main>() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0131, E0404, E0562, E0658. -For more information about an error, try `rustc --explain E0131`. +Some errors have detailed explanations: E0404, E0562, E0658. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 21062fdaf5859..88b17be601ceb 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -9,11 +9,6 @@ note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`. | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 - | -LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:27 | diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index e4abf6203e8f2..fd1b4f2f964b0 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -9,11 +9,6 @@ note: ...which requires simplifying constant for the type system `DEFAULT_REF_BA | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 - | -LL | const DEFAULT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:30 | diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 05ebd76f50012..303400f928e65 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -9,11 +9,6 @@ note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR` | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 - | -LL | const TRAIT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:28 | diff --git a/tests/ui/associated-consts/issue-58022.stderr b/tests/ui/associated-consts/issue-58022.stderr index 82cbc9ed3b094..6ce995eaab716 100644 --- a/tests/ui/associated-consts/issue-58022.stderr +++ b/tests/ui/associated-consts/issue-58022.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn new(slice: &[u8; Self::SIZE]) -> Self { | ^^^^ doesn't have a size known at compile-time | - = help: within `Bar<[u8]>`, the trait `Sized` is not implemented for `[u8]` + = help: within `Bar<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `Bar<[u8]>: Sized` note: required because it appears within the type `Bar<[u8]>` --> $DIR/issue-58022.rs:8:12 | diff --git a/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr b/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr index 650b5946064c2..1613af6b8b152 100644 --- a/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr +++ b/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr @@ -4,10 +4,7 @@ error: the associated type `X` exists for `S`, but its LL | struct S(A, B); | -------------- associated item `X` not found for this struct LL | struct Featureless; - | ------------------ - | | - | doesn't satisfy `Featureless: One` - | doesn't satisfy `Featureless: Two` + | ------------------ doesn't satisfy `Featureless: One` or `Featureless: Two` ... LL | let _: S::::X; | ^ associated type cannot be referenced on `S` due to unsatisfied trait bounds diff --git a/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs b/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs index a3f4717791abd..079c44b3a598d 100644 --- a/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs +++ b/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs @@ -5,7 +5,7 @@ use std::ops::Add; trait Tr1 { type As1; fn mk(&self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used fn assert_copy(x: T) { let _x = x; let _x = x; } fn assert_static(_: T) {} diff --git a/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr b/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr new file mode 100644 index 0000000000000..2e26a434f5d34 --- /dev/null +++ b/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr @@ -0,0 +1,12 @@ +warning: method `tr2` is never used + --> $DIR/dyn-impl-trait-type.rs:8:20 + | +LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs b/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs index 52199124ea3b5..49e5e72f225e2 100644 --- a/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs +++ b/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs @@ -7,7 +7,7 @@ use std::ops::Add; trait Tr1 { type As1; fn mk(&self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used fn assert_copy(x: T) { let _x = x; let _x = x; } fn assert_static(_: T) {} diff --git a/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr b/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr new file mode 100644 index 0000000000000..9eddbe462847d --- /dev/null +++ b/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr @@ -0,0 +1,12 @@ +warning: method `tr2` is never used + --> $DIR/dyn-rpit-and-let.rs:10:20 + | +LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index f576cc9c95f09..dde7036231e21 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -13,7 +13,7 @@ error: future cannot be sent between threads safely LL | is_send(foo::()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future> { ::method() }` + = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future> { ::method() }`, which is required by `impl Future>: Send` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/basic.rs:13:5 | diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs new file mode 100644 index 0000000000000..3b350e14fd937 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs @@ -0,0 +1,17 @@ +// edition: 2021 + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait HealthCheck { + async fn check() -> bool; +} + +async fn do_health_check_par(hc: HC) +where + HC: HealthCheck + Send + 'static, + //~^ ERROR return type notation is not allowed for functions that have const parameters +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr new file mode 100644 index 0000000000000..8a3f037d00321 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr @@ -0,0 +1,20 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-120208-higher-ranked-const.rs:3:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation is not allowed for functions that have const parameters + --> $DIR/issue-120208-higher-ranked-const.rs:12:21 + | +LL | async fn check() -> bool; + | -------------- const parameter declared here +... +LL | HC: HealthCheck + Send + 'static, + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/rpit.rs b/tests/ui/associated-type-bounds/rpit.rs index 59c7733fbe4ba..557e63b5f71fa 100644 --- a/tests/ui/associated-type-bounds/rpit.rs +++ b/tests/ui/associated-type-bounds/rpit.rs @@ -5,7 +5,7 @@ use std::ops::Add; trait Tr1 { type As1; fn mk(self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used fn assert_copy(x: T) { let _x = x; let _x = x; } fn assert_static(_: T) {} diff --git a/tests/ui/associated-type-bounds/rpit.stderr b/tests/ui/associated-type-bounds/rpit.stderr new file mode 100644 index 0000000000000..76bd75bd2cab3 --- /dev/null +++ b/tests/ui/associated-type-bounds/rpit.stderr @@ -0,0 +1,12 @@ +warning: method `tr2` is never used + --> $DIR/rpit.rs:8:20 + | +LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed index b9f26a40219b5..128c7dfdda2ed 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait O { type M; } diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs index abff6af73e24b..6b6478419b4c0 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait O { type M; } diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr index 7ca9aff432279..21bc37bb3ea2d 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21 + --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:13:21 | LL | const N: C::M = 4u8; | ^^^ expected associated type, found `u8` diff --git a/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs b/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs index 93a44c01ce053..60088e443f300 100644 --- a/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs +++ b/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(dead_code)] #![feature(associated_type_bounds)] #![feature(type_alias_impl_trait)] diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed index 80bbef17469db..adfba994f32dc 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #![allow(unused_variables)] trait Get { diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.rs b/tests/ui/associated-types/associated-types-for-unimpl-trait.rs index 0f6cea8e69fcf..50478171d869a 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.rs +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #![allow(unused_variables)] trait Get { diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr index 17941b6bf1eef..27014fa53d8a2 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:10:40 + --> $DIR/associated-types-for-unimpl-trait.rs:11:40 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` diff --git a/tests/ui/associated-types/associated-types-in-bound-type-arg.rs b/tests/ui/associated-types/associated-types-in-bound-type-arg.rs index 88bb5fe0afeab..05e66a168d9cf 100644 --- a/tests/ui/associated-types/associated-types-in-bound-type-arg.rs +++ b/tests/ui/associated-types/associated-types-in-bound-type-arg.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test the case where we resolve `C::Result` and the trait bound // itself includes a `Self::Item` shorthand. // diff --git a/tests/ui/associated-types/associated-types-issue-20220.rs b/tests/ui/associated-types/associated-types-issue-20220.rs index 19fa7a6085a56..89efce198340f 100644 --- a/tests/ui/associated-types/associated-types-issue-20220.rs +++ b/tests/ui/associated-types/associated-types-issue-20220.rs @@ -4,7 +4,7 @@ use std::vec; -trait IntoIteratorX { +trait IntoIteratorX { //~ WARN trait `IntoIteratorX` is never used type Item; type IntoIter: Iterator; diff --git a/tests/ui/associated-types/associated-types-issue-20220.stderr b/tests/ui/associated-types/associated-types-issue-20220.stderr new file mode 100644 index 0000000000000..c682f46e1409b --- /dev/null +++ b/tests/ui/associated-types/associated-types-issue-20220.stderr @@ -0,0 +1,10 @@ +warning: trait `IntoIteratorX` is never used + --> $DIR/associated-types-issue-20220.rs:7:7 + | +LL | trait IntoIteratorX { + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-types/associated-types-issue-20371.rs b/tests/ui/associated-types/associated-types-issue-20371.rs index ae8a8767d2746..cbec83d45b29d 100644 --- a/tests/ui/associated-types/associated-types-issue-20371.rs +++ b/tests/ui/associated-types/associated-types-issue-20371.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that we are able to have an impl that defines an associated type // before the actual trait. diff --git a/tests/ui/associated-types/associated-types-nested-projections.rs b/tests/ui/associated-types/associated-types-nested-projections.rs index 76ba7496250cc..440f35c8bdef4 100644 --- a/tests/ui/associated-types/associated-types-nested-projections.rs +++ b/tests/ui/associated-types/associated-types-nested-projections.rs @@ -13,7 +13,7 @@ impl<'a> Bound for &'a i32 {} trait IntoIterator { type Iter: Iterator; - fn into_iter(self) -> Self::Iter; + fn into_iter(self) -> Self::Iter; //~ WARN method `into_iter` is never used } impl<'a, T> IntoIterator for &'a [T; 3] { diff --git a/tests/ui/associated-types/associated-types-nested-projections.stderr b/tests/ui/associated-types/associated-types-nested-projections.stderr new file mode 100644 index 0000000000000..97d5a7585736c --- /dev/null +++ b/tests/ui/associated-types/associated-types-nested-projections.stderr @@ -0,0 +1,13 @@ +warning: method `into_iter` is never used + --> $DIR/associated-types-nested-projections.rs:16:8 + | +LL | trait IntoIterator { + | ------------ method in this trait +... +LL | fn into_iter(self) -> Self::Iter; + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs index e09aa3663c6e5..6612598b1b8b4 100644 --- a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs +++ b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Test that we normalize associated types that appear in bounds; if // we didn't, the call to `self.split2()` fails to type check. diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs index dcfae0f37e1da..df0a82ee7ceb0 100644 --- a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs +++ b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Test that we normalize associated types that appear in bounds; if // we didn't, the call to `self.split2()` fails to type check. diff --git a/tests/ui/associated-types/associated-types-path-2.rs b/tests/ui/associated-types/associated-types-path-2.rs index 00066efccb8dd..c993e1d27202d 100644 --- a/tests/ui/associated-types/associated-types-path-2.rs +++ b/tests/ui/associated-types/associated-types-path-2.rs @@ -29,14 +29,12 @@ pub fn f1_uint_uint() { f1(2u32, 4u32); //~^ ERROR `u32: Foo` is not satisfied //~| ERROR `u32: Foo` is not satisfied - //~| ERROR `u32: Foo` is not satisfied } pub fn f1_uint_int() { f1(2u32, 4i32); //~^ ERROR `u32: Foo` is not satisfied //~| ERROR `u32: Foo` is not satisfied - //~| ERROR `u32: Foo` is not satisfied } pub fn f2_int() { diff --git a/tests/ui/associated-types/associated-types-path-2.stderr b/tests/ui/associated-types/associated-types-path-2.stderr index 206f490241026..5edd5c864e135 100644 --- a/tests/ui/associated-types/associated-types-path-2.stderr +++ b/tests/ui/associated-types/associated-types-path-2.stderr @@ -31,14 +31,6 @@ note: required by a bound in `f1` LL | pub fn f1(a: T, x: T::A) {} | ^^^ required by this bound in `f1` -error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:29:5 - | -LL | f1(2u32, 4u32); - | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32` - | - = help: the trait `Foo` is implemented for `i32` - error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:29:14 | @@ -48,7 +40,7 @@ LL | f1(2u32, 4u32); = help: the trait `Foo` is implemented for `i32` error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:36:8 + --> $DIR/associated-types-path-2.rs:35:8 | LL | f1(2u32, 4i32); | -- ^^^^ the trait `Foo` is not implemented for `u32` @@ -63,15 +55,7 @@ LL | pub fn f1(a: T, x: T::A) {} | ^^^ required by this bound in `f1` error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:36:5 - | -LL | f1(2u32, 4i32); - | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32` - | - = help: the trait `Foo` is implemented for `i32` - -error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:36:14 + --> $DIR/associated-types-path-2.rs:35:14 | LL | f1(2u32, 4i32); | ^^^^ the trait `Foo` is not implemented for `u32` @@ -79,7 +63,7 @@ LL | f1(2u32, 4i32); = help: the trait `Foo` is implemented for `i32` error[E0308]: mismatched types - --> $DIR/associated-types-path-2.rs:43:18 + --> $DIR/associated-types-path-2.rs:41:18 | LL | let _: i32 = f2(2i32); | --- ^^^^^^^^ expected `i32`, found `u32` @@ -91,7 +75,7 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn LL | let _: i32 = f2(2i32).try_into().unwrap(); | ++++++++++++++++++++ -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs b/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs index 107e6b4ce0ca0..e99d0112ec4fd 100644 --- a/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs +++ b/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Test that we correctly handle projection bounds appearing in the // supertrait list (and in conjunction with overloaded operators). In diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs index a59c327be2101..e172c6e5611d3 100644 --- a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs +++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs @@ -6,7 +6,7 @@ trait Int { type T; - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } trait NonZero diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr new file mode 100644 index 0000000000000..c26ed79a026e4 --- /dev/null +++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr @@ -0,0 +1,13 @@ +warning: method `dummy` is never used + --> $DIR/associated-types-projection-from-known-type-in-impl.rs:9:8 + | +LL | trait Int + | --- method in this trait +... +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed index 9bc308465ebdd..01f49d52ee212 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed @@ -2,6 +2,7 @@ // Check that we get an error when you use `::Value` in // the trait definition even if there is no default method. +#![allow(dead_code)] trait Get { type Value; } diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs index 549fc8fc618e0..7068a754a12c1 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs @@ -2,6 +2,7 @@ // Check that we get an error when you use `::Value` in // the trait definition even if there is no default method. +#![allow(dead_code)] trait Get { type Value; } diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index 64a88525af8d4..79200dc3acc24 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40 + --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:11:40 | LL | fn okay(&self, foo: U, bar: ::Value); | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs index 3b8c8c019e50b..a2d6c9ff5a45b 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Check that we do not get an error when you use `::Value` in // the trait definition if there is no default method and for every impl, // `Self` does implement `Get`. diff --git a/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs b/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs index 3c830d37060ab..1768fd1687b4e 100644 --- a/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs +++ b/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/associated-types/associated-types-resolve-lifetime.rs b/tests/ui/associated-types/associated-types-resolve-lifetime.rs index 52f2324d72ab7..563d0c1182211 100644 --- a/tests/ui/associated-types/associated-types-resolve-lifetime.rs +++ b/tests/ui/associated-types/associated-types-resolve-lifetime.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Get { diff --git a/tests/ui/associated-types/associated-types-unconstrained.stderr b/tests/ui/associated-types/associated-types-unconstrained.stderr index 4221a064ff9ce..83b7f61fd6964 100644 --- a/tests/ui/associated-types/associated-types-unconstrained.stderr +++ b/tests/ui/associated-types/associated-types-unconstrained.stderr @@ -5,7 +5,7 @@ LL | fn bar() -> isize; | ------------------ `Foo::bar` defined here ... LL | let x: isize = Foo::bar(); - | ^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | diff --git a/tests/ui/associated-types/defaults-suitability.stderr b/tests/ui/associated-types/defaults-suitability.stderr index 0a8ad0f89e212..82b35a4863788 100644 --- a/tests/ui/associated-types/defaults-suitability.stderr +++ b/tests/ui/associated-types/defaults-suitability.stderr @@ -39,7 +39,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:28:23 | LL | type Bar: Clone = Vec; - | ^^^^^^ the trait `Clone` is not implemented for `T` + | ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `Vec: Clone` | = note: required for `Vec` to implement `Clone` note: required by a bound in `Foo::Bar` @@ -88,7 +88,7 @@ error[E0277]: the trait bound `>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:65:23 | LL | type Bar: Clone = Vec; - | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `>::Baz` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `>::Baz`, which is required by `Vec<>::Baz>: Clone` | = note: required for `Vec<>::Baz>` to implement `Clone` note: required by a bound in `Foo2::Bar` @@ -105,7 +105,7 @@ error[E0277]: the trait bound `>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:74:23 | LL | type Bar: Clone = Vec; - | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `>::Baz` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `>::Baz`, which is required by `Vec<>::Baz>: Clone` | = note: required for `Vec<>::Baz>` to implement `Clone` note: required by a bound in `Foo25::Bar` diff --git a/tests/ui/associated-types/defaults-wf.stderr b/tests/ui/associated-types/defaults-wf.stderr index aeb4e47abcbf7..f0b10189bd8d9 100644 --- a/tests/ui/associated-types/defaults-wf.stderr +++ b/tests/ui/associated-types/defaults-wf.stderr @@ -5,7 +5,7 @@ LL | type Ty = Vec<[u8]>; | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/hr-associated-type-bound-1.stderr b/tests/ui/associated-types/hr-associated-type-bound-1.stderr index ab5dc803cdf47..01005b6b22d1f 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-1.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-1.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-1.rs:12:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> >::U: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr index 9e03936422491..0031d205b8426 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-1.rs:14:14 | LL | type V = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> >::V: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `Y` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr index 1a749007ab674..bb484da6a77b1 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -18,7 +18,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:15:14 | LL | type W = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> >::W: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `Z` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr index f8be4ec241052..f4d2f43a9b4d9 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-3.rs:13:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <(T,) as X<'b, (T,)>>::U: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr index 22c4bd68690e3..7f03d1553912d 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-4.rs:13:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <(T,) as X<'b, T>>::U: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr index aae80a9b2e196..fbbc2f4577243 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> < as Cycle>::Next as X<'b, as Cycle>::Next>>::U: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` @@ -18,7 +18,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:31:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str` + | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> < as Cycle>::Next as X<'b, as Cycle>::Next>>::U: Clone` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/impl-wf-cycle-1.stderr b/tests/ui/associated-types/impl-wf-cycle-1.stderr index 5fa36733f6677..d642f9f0e36a7 100644 --- a/tests/ui/associated-types/impl-wf-cycle-1.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-1.stderr @@ -7,6 +7,9 @@ LL | | where LL | | Self::A: Baz, LL | | Self::B: Fiz, | |_________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` --> $DIR/impl-wf-cycle-1.rs:15:17 @@ -18,6 +21,10 @@ LL | Self::A: Baz, | --- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `(T,)` to implement `Grault` +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - Self::A: Baz, + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-2.stderr b/tests/ui/associated-types/impl-wf-cycle-2.stderr index 17a96bbd93430..9454d1d669792 100644 --- a/tests/ui/associated-types/impl-wf-cycle-2.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-2.stderr @@ -6,6 +6,9 @@ LL | | LL | | where LL | | Self::A: Copy, | |__________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` --> $DIR/impl-wf-cycle-2.rs:7:17 @@ -15,6 +18,11 @@ LL | impl Grault for (T,) ... LL | Self::A: Copy, | ---- unsatisfied trait bound introduced here +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - where +LL - Self::A: Copy, + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-3.rs b/tests/ui/associated-types/impl-wf-cycle-3.rs new file mode 100644 index 0000000000000..044033c5e8ab1 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-3.rs @@ -0,0 +1,13 @@ +trait A {} + +trait B { + type Type; +} + +impl B for T //~ ERROR overflow evaluating the requirement +where + T: A, +{ + type Type = bool; +} +fn main() {} diff --git a/tests/ui/associated-types/impl-wf-cycle-3.stderr b/tests/ui/associated-types/impl-wf-cycle-3.stderr new file mode 100644 index 0000000000000..d3ca06f890b34 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-3.stderr @@ -0,0 +1,27 @@ +error[E0275]: overflow evaluating the requirement `::Type == ::Type` + --> $DIR/impl-wf-cycle-3.rs:7:1 + | +LL | / impl B for T +LL | | where +LL | | T: A, + | |_____________________^ +LL | { +LL | type Type = bool; + | --------- associated type `::Type` is specified here + | +note: required for `T` to implement `B` + --> $DIR/impl-wf-cycle-3.rs:7:9 + | +LL | impl B for T + | ^ ^ +LL | where +LL | T: A, + | ------------- unsatisfied trait bound introduced here +help: replace the associated type with the type specified in this `impl` + | +LL | T: A, + | ~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/associated-types/impl-wf-cycle-4.rs b/tests/ui/associated-types/impl-wf-cycle-4.rs new file mode 100644 index 0000000000000..bfa8adc71a11d --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-4.rs @@ -0,0 +1,15 @@ +trait Filter { + type ToMatch; +} + +impl Filter for T //~ ERROR overflow evaluating the requirement +where + T: Fn(Self::ToMatch), +{ +} + +struct JustFilter { + filter: F, +} + +fn main() {} diff --git a/tests/ui/associated-types/impl-wf-cycle-4.stderr b/tests/ui/associated-types/impl-wf-cycle-4.stderr new file mode 100644 index 0000000000000..cdbac267d34dc --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-4.stderr @@ -0,0 +1,25 @@ +error[E0275]: overflow evaluating the requirement `::ToMatch == ::ToMatch` + --> $DIR/impl-wf-cycle-4.rs:5:1 + | +LL | / impl Filter for T +LL | | where +LL | | T: Fn(Self::ToMatch), + | |_________________________^ + | +note: required for `T` to implement `Filter` + --> $DIR/impl-wf-cycle-4.rs:5:9 + | +LL | impl Filter for T + | ^^^^^^ ^ +LL | where +LL | T: Fn(Self::ToMatch), + | ----------------- unsatisfied trait bound introduced here +note: associated types for the current `impl` cannot be restricted in `where` clauses + --> $DIR/impl-wf-cycle-4.rs:7:11 + | +LL | T: Fn(Self::ToMatch), + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/associated-types/impl-wf-cycle-5.fixed b/tests/ui/associated-types/impl-wf-cycle-5.fixed new file mode 100644 index 0000000000000..2b8f1e0d865ee --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-5.fixed @@ -0,0 +1,33 @@ +// run-rustfix + +#[allow(dead_code)] +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +#[allow(dead_code)] +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + T: Grault, +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-5.rs b/tests/ui/associated-types/impl-wf-cycle-5.rs new file mode 100644 index 0000000000000..e6de292ca5c91 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-5.rs @@ -0,0 +1,34 @@ +// run-rustfix + +#[allow(dead_code)] +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +#[allow(dead_code)] +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + T: Grault, + Self::A: Baz, +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-5.stderr b/tests/ui/associated-types/impl-wf-cycle-5.stderr new file mode 100644 index 0000000000000..61edf18b43d97 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-5.stderr @@ -0,0 +1,31 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-5.rs:22:1 + | +LL | / impl Grault for (T,) +LL | | +LL | | where +LL | | T: Grault, +LL | | Self::A: Baz, + | |_________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here + | +note: required for `(T,)` to implement `Grault` + --> $DIR/impl-wf-cycle-5.rs:22:9 + | +LL | impl Grault for (T,) + | ^^^^^^ ^^^^ +... +LL | Self::A: Baz, + | --- unsatisfied trait bound introduced here +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - T: Grault, +LL - Self::A: Baz, +LL + T: Grault, + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed new file mode 100644 index 0000000000000..5ddf1faefe088 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed @@ -0,0 +1,32 @@ +// run-rustfix + +#[allow(dead_code)] +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +#[allow(dead_code)] +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-6.rs b/tests/ui/associated-types/impl-wf-cycle-6.rs new file mode 100644 index 0000000000000..28f6deb77ce1f --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-6.rs @@ -0,0 +1,33 @@ +// run-rustfix + +#[allow(dead_code)] +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +#[allow(dead_code)] +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + Self::A: Baz, +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-6.stderr b/tests/ui/associated-types/impl-wf-cycle-6.stderr new file mode 100644 index 0000000000000..1c7495033183f --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-6.stderr @@ -0,0 +1,29 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-6.rs:22:1 + | +LL | / impl Grault for (T,) +LL | | +LL | | where +LL | | Self::A: Baz, + | |_________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here + | +note: required for `(T,)` to implement `Grault` + --> $DIR/impl-wf-cycle-6.rs:22:17 + | +LL | impl Grault for (T,) + | ^^^^^^ ^^^^ +... +LL | Self::A: Baz, + | --- unsatisfied trait bound introduced here +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - where +LL - Self::A: Baz, + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/associated-types/issue-20005.stderr b/tests/ui/associated-types/issue-20005.stderr index 02470a4424919..f2983383fa623 100644 --- a/tests/ui/associated-types/issue-20005.stderr +++ b/tests/ui/associated-types/issue-20005.stderr @@ -4,11 +4,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | ) -> >::Result where Dst: From { | ^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `From` +note: required by an implicit `Sized` bound in `From` --> $DIR/issue-20005.rs:1:12 | LL | trait From { - | ^^^ required by this bound in `From` + | ^^^ required by the implicit `Sized` requirement on this type parameter in `From` help: consider further restricting `Self` | LL | ) -> >::Result where Dst: From, Self: Sized { diff --git a/tests/ui/associated-types/issue-38821.rs b/tests/ui/associated-types/issue-38821.rs index 6753860e9ff80..34c35d7acf1db 100644 --- a/tests/ui/associated-types/issue-38821.rs +++ b/tests/ui/associated-types/issue-38821.rs @@ -22,7 +22,22 @@ pub trait Column: Expression {} #[derive(Debug, Copy, Clone)] //~^ ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied pub enum ColumnInsertValue where +//~^ ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied Col: Column, Expr: Expression::Nullable>, { diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr index 8b628f5ae6d19..50d622c89bb57 100644 --- a/tests/ui/associated-types/issue-38821.stderr +++ b/tests/ui/associated-types/issue-38821.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:17 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^ the trait `NotNull` is not implemented for `::SqlType` + | ^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -17,6 +17,272 @@ help: consider further restricting the associated type LL | Expr: Expression::Nullable>, ::SqlType: NotNull, | +++++++++++++++++++++++++++++++++++++++ -error: aborting due to 1 previous error +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:38:1 + | +LL | pub enum ColumnInsertValue where + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +help: consider extending the `where` clause, but there might be an alternative better way to express this requirement + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:38:1 + | +LL | / pub enum ColumnInsertValue where +LL | | +LL | | +LL | | Col: Column, +... | +LL | | Default(Col), +LL | | } + | |_^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +help: consider extending the `where` clause, but there might be an alternative better way to express this requirement + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:17 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType`, which is required by `::SqlType: IntoNullable` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-43784-associated-type.stderr b/tests/ui/associated-types/issue-43784-associated-type.stderr index 529fc1f119a9c..b2cbe8ee86e56 100644 --- a/tests/ui/associated-types/issue-43784-associated-type.stderr +++ b/tests/ui/associated-types/issue-43784-associated-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-associated-type.rs:14:18 | LL | type Assoc = T; - | ^ the trait `Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T`, which is required by `::Assoc: Partial` | note: required for `::Assoc` to implement `Partial` --> $DIR/issue-43784-associated-type.rs:1:11 diff --git a/tests/ui/associated-types/issue-65774-1.stderr b/tests/ui/associated-types/issue-65774-1.stderr index 9c77a25c4320d..9748a8fbbf491 100644 --- a/tests/ui/associated-types/issue-65774-1.stderr +++ b/tests/ui/associated-types/issue-65774-1.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied --> $DIR/issue-65774-1.rs:44:76 | LL | let closure = |config: &mut ::MpuConfig| writer.my_write(&config); - | ^^^^^^^ the trait `MyDisplay` is not implemented for `T` + | ^^^^^^^ the trait `MyDisplay` is not implemented for `T`, which is required by `&mut T: MyDisplay` | = help: the trait `MyDisplay` is implemented for `&'a mut T` note: required for `&mut T` to implement `MyDisplay` diff --git a/tests/ui/associated-types/substs-ppaux.normal.stderr b/tests/ui/associated-types/substs-ppaux.normal.stderr index 015b22f790f8a..93118616f02c7 100644 --- a/tests/ui/associated-types/substs-ppaux.normal.stderr +++ b/tests/ui/associated-types/substs-ppaux.normal.stderr @@ -76,7 +76,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | >::bar; | ^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'_, '_, u8>` note: required for `str` to implement `Foo<'_, '_, u8>` --> $DIR/substs-ppaux.rs:11:17 | diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr index 484581b10288b..13d3156fb8018 100644 --- a/tests/ui/associated-types/substs-ppaux.verbose.stderr +++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr @@ -76,7 +76,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | >::bar; | ^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'?0, '?1, u8>` note: required for `str` to implement `Foo<'?0, '?1, u8>` --> $DIR/substs-ppaux.rs:11:17 | diff --git a/tests/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/tests/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr index 99a46dedcdce6..8154441411323 100644 --- a/tests/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr +++ b/tests/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | trait ArithmeticOps: Add + Sub + Mul + Div {} | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Add` +note: required by an implicit `Sized` bound in `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting `Self` | diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr index b360aab6b595f..057906b49a37b 100644 --- a/tests/ui/async-await/async-await-let-else.stderr +++ b/tests/ui/async-await/async-await-let-else.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo(Some(true))); | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/async-await-let-else.rs:8:15 | @@ -29,7 +29,7 @@ LL | is_send(foo2(Some(true))); | | | required by a bound introduced by this call | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future: Send` note: required because it's used within this `async` fn body --> $DIR/async-await-let-else.rs:24:29 | @@ -61,7 +61,7 @@ error: future cannot be sent between threads safely LL | is_send(foo3(Some(true))); | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/async-await-let-else.rs:30:29 | @@ -81,7 +81,7 @@ error: future cannot be sent between threads safely LL | is_send(foo4(Some(true))); | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/async-await-let-else.rs:38:15 | diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs index f8ff9186842b8..2a3e382e11868 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -1,10 +1,11 @@ // edition:2018 -// check-pass #![feature(async_closure)] fn foo() -> Box> { let x = 0u32; Box::new((async || x)()) + //~^ ERROR cannot return value referencing local variable `x` + //~| ERROR cannot return value referencing temporary value } fn main() { diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr new file mode 100644 index 0000000000000..be67c78221a7c --- /dev/null +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr @@ -0,0 +1,21 @@ +error[E0515]: cannot return value referencing local variable `x` + --> $DIR/async-borrowck-escaping-closure-error.rs:6:5 + | +LL | Box::new((async || x)()) + | ^^^^^^^^^------------^^^ + | | | + | | `x` is borrowed here + | returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing temporary value + --> $DIR/async-borrowck-escaping-closure-error.rs:6:5 + | +LL | Box::new((async || x)()) + | ^^^^^^^^^------------^^^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/async-await/async-closures/arg-mismatch.rs b/tests/ui/async-await/async-closures/arg-mismatch.rs new file mode 100644 index 0000000000000..650e13677bc95 --- /dev/null +++ b/tests/ui/async-await/async-closures/arg-mismatch.rs @@ -0,0 +1,15 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let c = async |x| {}; + c(1i32).await; + c(2usize).await; + //~^ ERROR mismatched types + }); +} diff --git a/tests/ui/async-await/async-closures/arg-mismatch.stderr b/tests/ui/async-await/async-closures/arg-mismatch.stderr new file mode 100644 index 0000000000000..70853ae28156f --- /dev/null +++ b/tests/ui/async-await/async-closures/arg-mismatch.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/arg-mismatch.rs:12:11 + | +LL | c(2usize).await; + | - ^^^^^^ expected `i32`, found `usize` + | | + | arguments to this function are incorrect + | +note: closure parameter defined here + --> $DIR/arg-mismatch.rs:10:24 + | +LL | let c = async |x| {}; + | ^ +help: change the type of the numeric literal from `usize` to `i32` + | +LL | c(2i32).await; + | ~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs new file mode 100644 index 0000000000000..f73b43dd152f0 --- /dev/null +++ b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs @@ -0,0 +1,21 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. +// ignore-pass (test emits codegen-time warnings) + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async || {}; + + async fn needs_async_fn_mut(mut x: impl async FnMut()) { + x().await; + } + needs_async_fn_mut(x).await; + }); +} diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs new file mode 100644 index 0000000000000..0ba323a71cd13 --- /dev/null +++ b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs @@ -0,0 +1,21 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. +// ignore-pass (test emits codegen-time warnings) + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async || {}; + + async fn needs_async_fn_once(x: impl async FnOnce()) { + x().await; + } + needs_async_fn_once(x).await; + }); +} diff --git a/tests/ui/async-await/async-closures/auxiliary/block-on.rs b/tests/ui/async-await/async-closures/auxiliary/block-on.rs new file mode 100644 index 0000000000000..902e033cfe711 --- /dev/null +++ b/tests/ui/async-await/async-closures/auxiliary/block-on.rs @@ -0,0 +1,20 @@ +// edition: 2021 + +#![feature(async_closure, noop_waker)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match unsafe { fut.as_mut().poll(ctx) } { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} diff --git a/tests/ui/async-await/async-closures/await-inference-guidance.rs b/tests/ui/async-await/async-closures/await-inference-guidance.rs new file mode 100644 index 0000000000000..3702915cbadd1 --- /dev/null +++ b/tests/ui/async-await/async-closures/await-inference-guidance.rs @@ -0,0 +1,16 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async |x: &str| -> String { x.to_owned() }; + let mut s = x("hello, world").await; + s.truncate(4); + println!("{s}"); + }); +} diff --git a/tests/ui/async-await/async-closures/brand.rs b/tests/ui/async-await/async-closures/brand.rs new file mode 100644 index 0000000000000..26d2ed5a6ef65 --- /dev/null +++ b/tests/ui/async-await/async-closures/brand.rs @@ -0,0 +1,25 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass + +#![feature(async_closure)] + +extern crate block_on; + +use std::future::Future; +use std::marker::PhantomData; + +struct S; +struct B<'b>(PhantomData<&'b mut &'b mut ()>); + +impl S { + async fn q)>(self, f: F) { + f(B(PhantomData)).await; + } +} + +fn main() { + block_on::block_on(async { + S.q(async |b: B<'_>| { println!("...") }).await; + }); +} diff --git a/tests/ui/async-await/async-closures/def-path.rs b/tests/ui/async-await/async-closures/def-path.rs new file mode 100644 index 0000000000000..87e99ddda64b3 --- /dev/null +++ b/tests/ui/async-await/async-closures/def-path.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zverbose-internals +// edition:2021 + +#![feature(async_closure)] + +fn main() { + let x = async || {}; + //~^ NOTE the expected `async` closure body + let () = x(); + //~^ ERROR mismatched types + //~| NOTE this expression has type `{static main::{closure#0}::{closure#0}< + //~| NOTE expected `async` closure body, found `()` + //~| NOTE expected `async` closure body `{static main::{closure#0}::{closure#0}< +} diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr new file mode 100644 index 0000000000000..dae45825f370d --- /dev/null +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/def-path.rs:9:9 + | +LL | let x = async || {}; + | -- the expected `async` closure body +LL | +LL | let () = x(); + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t witness=?6t}` + | | + | expected `async` closure body, found `()` + | + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t witness=?6t}` + found unit type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/drop.rs b/tests/ui/async-await/async-closures/drop.rs new file mode 100644 index 0000000000000..a243d20774d27 --- /dev/null +++ b/tests/ui/async-await/async-closures/drop.rs @@ -0,0 +1,38 @@ +// aux-build:block-on.rs +// edition:2018 +// run-pass +// check-run-results + +#![feature(async_closure)] +#![allow(unused)] + +extern crate block_on; + +struct DropMe(i32); + +impl Drop for DropMe { + fn drop(&mut self) { + println!("{} was dropped", self.0); + } +} + +async fn call_once(f: impl async FnOnce()) { + println!("before call"); + let fut = Box::pin(f()); + println!("after call"); + drop(fut); + println!("future dropped"); +} + +fn main() { + block_on::block_on(async { + let d = DropMe(42); + let async_closure = async move || { + let d = &d; + println!("called"); + }; + + call_once(async_closure).await; + println!("after"); + }); +} diff --git a/tests/ui/async-await/async-closures/drop.run.stdout b/tests/ui/async-await/async-closures/drop.run.stdout new file mode 100644 index 0000000000000..ab233f491ba65 --- /dev/null +++ b/tests/ui/async-await/async-closures/drop.run.stdout @@ -0,0 +1,5 @@ +before call +after call +42 was dropped +future dropped +after diff --git a/tests/ui/async-await/async-closures/higher-ranked-return.rs b/tests/ui/async-await/async-closures/higher-ranked-return.rs new file mode 100644 index 0000000000000..d98779c6ea320 --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked-return.rs @@ -0,0 +1,18 @@ +// aux-build:block-on.rs +// edition:2021 + +// known-bug: unknown +// Borrow checking doesn't like that higher-ranked output... + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async move |x: &str| -> &str { + x + }; + let s = x("hello!").await; + }); +} diff --git a/tests/ui/async-await/async-closures/higher-ranked-return.stderr b/tests/ui/async-await/async-closures/higher-ranked-return.stderr new file mode 100644 index 0000000000000..268631f67cddf --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked-return.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/higher-ranked-return.rs:13:46 + | +LL | let x = async move |x: &str| -> &str { + | ________________________________-________----_^ + | | | | + | | | return type of async closure `{async closure body@$DIR/higher-ranked-return.rs:13:46: 15:10}` contains a lifetime `'2` + | | let's call the lifetime of this reference `'1` +LL | | x +LL | | }; + | |_________^ returning this value requires that `'1` must outlive `'2` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-closures/higher-ranked.rs b/tests/ui/async-await/async-closures/higher-ranked.rs new file mode 100644 index 0000000000000..17b5116cceb02 --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked.rs @@ -0,0 +1,16 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async move |x: &str| { + println!("{x}"); + }; + x("hello!").await; + }); +} diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs new file mode 100644 index 0000000000000..94c8e8563bd9e --- /dev/null +++ b/tests/ui/async-await/async-closures/is-not-fn.rs @@ -0,0 +1,12 @@ +// edition:2021 + +#![feature(async_closure)] + +fn main() { + fn needs_fn(x: impl FnOnce()) {} + needs_fn(async || {}); + //~^ ERROR expected a `FnOnce()` closure, found `{coroutine-closure@ + // FIXME(async_closures): This should explain in more detail how async fns don't + // implement the regular `Fn` traits. Or maybe we should just fix it and make them + // when there are no upvars or whatever. +} diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.stderr new file mode 100644 index 0000000000000..12da4b1fc6fb7 --- /dev/null +++ b/tests/ui/async-await/async-closures/is-not-fn.stderr @@ -0,0 +1,19 @@ +error[E0277]: expected a `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` + --> $DIR/is-not-fn.rs:7:14 + | +LL | needs_fn(async || {}); + | -------- ^^^^^^^^^^^ expected an `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<()>` is not implemented for `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` + = note: wrap the `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `needs_fn` + --> $DIR/is-not-fn.rs:6:25 + | +LL | fn needs_fn(x: impl FnOnce()) {} + | ^^^^^^^^ required by this bound in `needs_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-closures/mangle.rs b/tests/ui/async-await/async-closures/mangle.rs new file mode 100644 index 0000000000000..9d231d551765e --- /dev/null +++ b/tests/ui/async-await/async-closures/mangle.rs @@ -0,0 +1,35 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass +// revisions: v0 legacy +//[v0] compile-flags: -Csymbol-mangling-version=v0 +//[legacy] compile-flags: -Csymbol-mangling-version=legacy -Zunstable-options + +// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. +// ignore-pass (test emits codegen-time warnings) + +#![feature(async_closure, noop_waker)] + +extern crate block_on; + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +async fn call_mut(f: &mut impl async FnMut()) { + f().await; +} + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +fn main() { + block_on::block_on(async { + let mut async_closure = async move || { + println!("called"); + }; + call_mut(&mut async_closure).await; + call_once(async_closure).await; + }); +} diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.rs b/tests/ui/async-await/async-closures/move-consuming-capture.rs new file mode 100644 index 0000000000000..b8964c571f92e --- /dev/null +++ b/tests/ui/async-await/async-closures/move-consuming-capture.rs @@ -0,0 +1,20 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +struct NoCopy; + +fn main() { + block_on::block_on(async { + let s = NoCopy; + let x = async move || { + drop(s); + }; + x().await; + x().await; + //~^ ERROR use of moved value: `x` + }); +} diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.stderr b/tests/ui/async-await/async-closures/move-consuming-capture.stderr new file mode 100644 index 0000000000000..2c2a0d1162d17 --- /dev/null +++ b/tests/ui/async-await/async-closures/move-consuming-capture.stderr @@ -0,0 +1,17 @@ +error[E0382]: use of moved value: `x` + --> $DIR/move-consuming-capture.rs:17:9 + | +LL | let x = async move || { + | - move occurs because `x` has type `{coroutine-closure@$DIR/move-consuming-capture.rs:13:17: 13:30}`, which does not implement the `Copy` trait +... +LL | x().await; + | --- `x` moved due to this method call +LL | x().await; + | ^ value used here after move + | +note: `async_call_once` takes ownership of the receiver `self`, which moves `x` + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/async-await/async-closures/move-is-async-fn.rs b/tests/ui/async-await/async-closures/move-is-async-fn.rs new file mode 100644 index 0000000000000..943c062954185 --- /dev/null +++ b/tests/ui/async-await/async-closures/move-is-async-fn.rs @@ -0,0 +1,21 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let s = String::from("hello, world"); + let c = async move || { + println!("{s}"); + }; + c().await; + c().await; + + fn is_static(_: T) {} + is_static(c); + }); +} diff --git a/tests/ui/async-await/async-closures/mutate.rs b/tests/ui/async-await/async-closures/mutate.rs new file mode 100644 index 0000000000000..cc1df5f034ff0 --- /dev/null +++ b/tests/ui/async-await/async-closures/mutate.rs @@ -0,0 +1,19 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let mut prefix = String::from("Hello"); + let mut c = async move |x: &str| { + prefix.push(','); + println!("{prefix} {x}!") + }; + c("world").await; + c("rust").await; + }); +} diff --git a/tests/ui/async-await/async-closures/not-lending.rs b/tests/ui/async-await/async-closures/not-lending.rs new file mode 100644 index 0000000000000..90832e1a0745d --- /dev/null +++ b/tests/ui/async-await/async-closures/not-lending.rs @@ -0,0 +1,21 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +// Make sure that we can't make an async closure that evaluates to a self-borrow. +// i.e. that the generator may reference captures, but the future's return type can't. + +fn main() { + block_on::block_on(async { + let s = String::new(); + let x = async move || -> &String { &s }; + //~^ ERROR lifetime may not live long enough + + let s = String::new(); + let x = async move || { &s }; + //~^ ERROR lifetime may not live long enough + }); +} diff --git a/tests/ui/async-await/async-closures/not-lending.stderr b/tests/ui/async-await/async-closures/not-lending.stderr new file mode 100644 index 0000000000000..1713e49b551e6 --- /dev/null +++ b/tests/ui/async-await/async-closures/not-lending.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/not-lending.rs:14:42 + | +LL | let x = async move || -> &String { &s }; + | ------------------------ ^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of async closure `{async closure body@$DIR/not-lending.rs:14:42: 14:48}` contains a lifetime `'2` + | lifetime `'1` represents this closure's body + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: lifetime may not live long enough + --> $DIR/not-lending.rs:18:31 + | +LL | let x = async move || { &s }; + | ------------- ^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of async closure `{async closure body@$DIR/not-lending.rs:18:31: 18:37}` contains a lifetime `'2` + | lifetime `'1` represents this closure's body + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/async-closures/return-type-mismatch.rs b/tests/ui/async-await/async-closures/return-type-mismatch.rs new file mode 100644 index 0000000000000..9ad6be0b6e61e --- /dev/null +++ b/tests/ui/async-await/async-closures/return-type-mismatch.rs @@ -0,0 +1,14 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async || -> i32 { 0 }; + let y: usize = x().await; + //~^ ERROR mismatched types + }); +} diff --git a/tests/ui/async-await/async-closures/return-type-mismatch.stderr b/tests/ui/async-await/async-closures/return-type-mismatch.stderr new file mode 100644 index 0000000000000..53841f62777e6 --- /dev/null +++ b/tests/ui/async-await/async-closures/return-type-mismatch.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/return-type-mismatch.rs:11:24 + | +LL | let y: usize = x().await; + | ^^^^^^^^^ expected `usize`, found `i32` + | +help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit + | +LL | let y: usize = x().await.try_into().unwrap(); + | ++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs new file mode 100644 index 0000000000000..f86cee3e0709e --- /dev/null +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -0,0 +1,16 @@ +// edition:2021 + +// FIXME(async_closures): This needs a better error message! + +#![feature(async_closure)] + +fn main() { + fn needs_async_fn(_: impl async Fn()) {} + + let mut x = 1; + needs_async_fn(async || { + //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper + // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. + x += 1; + }); +} diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr new file mode 100644 index 0000000000000..4ef8484cc34cd --- /dev/null +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not satisfied + --> $DIR/wrong-fn-kind.rs:11:20 + | +LL | needs_async_fn(async || { + | _____--------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. +LL | | x += 1; +LL | | }); + | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not implemented for `i16` + | +note: required by a bound in `needs_async_fn` + --> $DIR/wrong-fn-kind.rs:8:31 + | +LL | fn needs_async_fn(_: impl async Fn()) {} + | ^^^^^^^^^^ required by this bound in `needs_async_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-fn-nonsend.stderr b/tests/ui/async-await/async-fn-nonsend.stderr index 0ced6c36f4715..8b245281da991 100644 --- a/tests/ui/async-await/async-fn-nonsend.stderr +++ b/tests/ui/async-await/async-fn-nonsend.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:33:26 | @@ -24,7 +24,7 @@ error: future cannot be sent between threads safely LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `dyn std::fmt::Write` + = help: within `impl Future`, the trait `Send` is not implemented for `dyn std::fmt::Write`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:46:15 | diff --git a/tests/ui/async-await/async-fn/dyn-pos.rs b/tests/ui/async-await/async-fn/dyn-pos.rs new file mode 100644 index 0000000000000..3201fb8dbf309 --- /dev/null +++ b/tests/ui/async-await/async-fn/dyn-pos.rs @@ -0,0 +1,14 @@ +// edition:2018 + +#![feature(async_closure)] + +fn foo(x: &dyn async Fn()) {} +//~^ ERROR the trait `AsyncFn` cannot be made into an object +//~| ERROR the trait `AsyncFn` cannot be made into an object +//~| ERROR the trait `AsyncFn` cannot be made into an object +//~| ERROR the trait `AsyncFn` cannot be made into an object +//~| ERROR the trait `AsyncFnMut` cannot be made into an object +//~| ERROR the trait `AsyncFnMut` cannot be made into an object +//~| ERROR the trait `AsyncFnMut` cannot be made into an object + +fn main() {} diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr new file mode 100644 index 0000000000000..c93235265160b --- /dev/null +++ b/tests/ui/async-await/async-fn/dyn-pos.stderr @@ -0,0 +1,87 @@ +error[E0038]: the trait `AsyncFn` cannot be made into an object + --> $DIR/dyn-pos.rs:5:16 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^ `AsyncFn` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` + +error[E0038]: the trait `AsyncFnMut` cannot be made into an object + --> $DIR/dyn-pos.rs:5:16 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^ `AsyncFnMut` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + +error[E0038]: the trait `AsyncFn` cannot be made into an object + --> $DIR/dyn-pos.rs:5:16 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^ `AsyncFn` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `AsyncFnMut` cannot be made into an object + --> $DIR/dyn-pos.rs:5:16 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^ `AsyncFnMut` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `AsyncFn` cannot be made into an object + --> $DIR/dyn-pos.rs:5:16 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^ `AsyncFn` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `AsyncFnMut` cannot be made into an object + --> $DIR/dyn-pos.rs:5:16 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^ `AsyncFnMut` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `AsyncFn` cannot be made into an object + --> $DIR/dyn-pos.rs:5:12 + | +LL | fn foo(x: &dyn async Fn()) {} + | ^^^^^^^^^^^^^^ `AsyncFn` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` + ::: $SRC_DIR/core/src/ops/async_function.rs:LL:COL + | + = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs new file mode 100644 index 0000000000000..6436787b665d7 --- /dev/null +++ b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs @@ -0,0 +1,10 @@ +// check-pass +// Make sure that we don't eagerly recover `async ::Bound` in edition 2015. + +mod async { + pub trait Foo {} +} + +fn test(x: impl async ::Foo) {} + +fn main() {} diff --git a/tests/ui/async-await/async-fn/edition-2015.rs b/tests/ui/async-await/async-fn/edition-2015.rs new file mode 100644 index 0000000000000..83b9d415ddab4 --- /dev/null +++ b/tests/ui/async-await/async-fn/edition-2015.rs @@ -0,0 +1,7 @@ +fn foo(x: impl async Fn()) -> impl async Fn() { x } +//~^ ERROR `async` trait bounds are only allowed in Rust 2018 or later +//~| ERROR `async` trait bounds are only allowed in Rust 2018 or later +//~| ERROR async closures are unstable +//~| ERROR async closures are unstable + +fn main() {} diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr new file mode 100644 index 0000000000000..0029d53868d4f --- /dev/null +++ b/tests/ui/async-await/async-fn/edition-2015.stderr @@ -0,0 +1,43 @@ +error: `async` trait bounds are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:1:16 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: `async` trait bounds are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:1:36 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0658]: async closures are unstable + --> $DIR/edition-2015.rs:1:16 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error[E0658]: async closures are unstable + --> $DIR/edition-2015.rs:1:36 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/async-fn/impl-header.rs b/tests/ui/async-await/async-fn/impl-header.rs new file mode 100644 index 0000000000000..fb1844384ae08 --- /dev/null +++ b/tests/ui/async-await/async-fn/impl-header.rs @@ -0,0 +1,8 @@ +// edition:2018 + +struct F; + +impl async Fn<()> for F {} +//~^ ERROR expected type, found keyword `async` + +fn main() {} diff --git a/tests/ui/async-await/async-fn/impl-header.stderr b/tests/ui/async-await/async-fn/impl-header.stderr new file mode 100644 index 0000000000000..02cb432624274 --- /dev/null +++ b/tests/ui/async-await/async-fn/impl-header.stderr @@ -0,0 +1,8 @@ +error: expected type, found keyword `async` + --> $DIR/impl-header.rs:5:6 + | +LL | impl async Fn<()> for F {} + | ^^^^^ expected type + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-fn/impl-trait.rs b/tests/ui/async-await/async-fn/impl-trait.rs new file mode 100644 index 0000000000000..97f6696fe1434 --- /dev/null +++ b/tests/ui/async-await/async-fn/impl-trait.rs @@ -0,0 +1,15 @@ +// edition:2018 +// check-pass + +#![feature(async_closure, type_alias_impl_trait)] + +type Tait = impl async Fn(); +fn tait() -> Tait { + || async {} +} + +fn foo(x: impl async Fn()) -> impl async Fn() { x } + +fn param() {} + +fn main() {} diff --git a/tests/ui/async-await/async-fn/method-call-pos.rs b/tests/ui/async-await/async-fn/method-call-pos.rs new file mode 100644 index 0000000000000..aaa0245b9868f --- /dev/null +++ b/tests/ui/async-await/async-fn/method-call-pos.rs @@ -0,0 +1,7 @@ +// edition:2018 + +fn main() { + <_ as async Fn()>(|| async {}); + //~^ ERROR expected identifier, found keyword `async` + //~| ERROR expected one of +} diff --git a/tests/ui/async-await/async-fn/method-call-pos.stderr b/tests/ui/async-await/async-fn/method-call-pos.stderr new file mode 100644 index 0000000000000..527515a1b44cc --- /dev/null +++ b/tests/ui/async-await/async-fn/method-call-pos.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found keyword `async` + --> $DIR/method-call-pos.rs:4:11 + | +LL | <_ as async Fn()>(|| async {}); + | ^^^^^ expected identifier, found keyword + +error: expected one of `(`, `::`, `<`, or `>`, found `Fn` + --> $DIR/method-call-pos.rs:4:17 + | +LL | <_ as async Fn()>(|| async {}); + | ^^ expected one of `(`, `::`, `<`, or `>` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/async-fn/not-a-trait.rs b/tests/ui/async-await/async-fn/not-a-trait.rs new file mode 100644 index 0000000000000..a8fa21e556888 --- /dev/null +++ b/tests/ui/async-await/async-fn/not-a-trait.rs @@ -0,0 +1,13 @@ +// edition:2018 + +#![feature(async_closure)] + +struct S; + +fn test(x: impl async S) {} +//~^ ERROR expected trait, found struct `S` + +fn missing(x: impl async Missing) {} +//~^ ERROR cannot find trait `Missing` in this scope + +fn main() {} diff --git a/tests/ui/async-await/async-fn/not-a-trait.stderr b/tests/ui/async-await/async-fn/not-a-trait.stderr new file mode 100644 index 0000000000000..d49f7d7d2fc16 --- /dev/null +++ b/tests/ui/async-await/async-fn/not-a-trait.stderr @@ -0,0 +1,16 @@ +error[E0404]: expected trait, found struct `S` + --> $DIR/not-a-trait.rs:7:23 + | +LL | fn test(x: impl async S) {} + | ^ not a trait + +error[E0405]: cannot find trait `Missing` in this scope + --> $DIR/not-a-trait.rs:10:26 + | +LL | fn missing(x: impl async Missing) {} + | ^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0404, E0405. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs new file mode 100644 index 0000000000000..99a5d56a3093b --- /dev/null +++ b/tests/ui/async-await/async-fn/simple.rs @@ -0,0 +1,16 @@ +// edition: 2021 +// check-pass + +#![feature(async_fn_traits)] + +use std::ops::AsyncFn; + +async fn foo() {} + +async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { + f(1).await +} + +fn main() { + let fut = call_asyncly(|x| async move { x + 1 }); +} diff --git a/tests/ui/async-await/async-fn/sugar.rs b/tests/ui/async-await/async-fn/sugar.rs new file mode 100644 index 0000000000000..868fb799ae4f9 --- /dev/null +++ b/tests/ui/async-await/async-fn/sugar.rs @@ -0,0 +1,14 @@ +// edition: 2021 +// check-pass + +#![feature(async_closure)] + +async fn foo() {} + +async fn call_asyncly(f: impl async Fn(i32) -> i32) -> i32 { + f(1).await +} + +fn main() { + let fut = call_asyncly(|x| async move { x + 1 }); +} diff --git a/tests/ui/async-await/async-fn/wrong-trait.rs b/tests/ui/async-await/async-fn/wrong-trait.rs new file mode 100644 index 0000000000000..c431a362b1ea9 --- /dev/null +++ b/tests/ui/async-await/async-fn/wrong-trait.rs @@ -0,0 +1,10 @@ +// edition:2018 + +#![feature(async_closure)] + +trait Foo {} + +fn test(x: impl async Foo) {} +//~^ ERROR `async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits + +fn main() {} diff --git a/tests/ui/async-await/async-fn/wrong-trait.stderr b/tests/ui/async-await/async-fn/wrong-trait.stderr new file mode 100644 index 0000000000000..b39f5aa623c10 --- /dev/null +++ b/tests/ui/async-await/async-fn/wrong-trait.stderr @@ -0,0 +1,8 @@ +error: `async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits + --> $DIR/wrong-trait.rs:7:23 + | +LL | fn test(x: impl async Foo) {} + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr index 99bce89e8d3bf..5d87fc747682a 100644 --- a/tests/ui/async-await/async-is-unwindsafe.stderr +++ b/tests/ui/async-await/async-is-unwindsafe.stderr @@ -1,19 +1,21 @@ error[E0277]: the type `&mut Context<'_>` may not be safely transferred across an unwind boundary --> $DIR/async-is-unwindsafe.rs:12:5 | -LL | is_unwindsafe(async { - | _____^^^^^^^^^^^^^_- - | | | - | | `&mut Context<'_>` may not be safely transferred across an unwind boundary -LL | | -LL | | use std::ptr::null; -LL | | use std::task::{Context, RawWaker, RawWakerVTable, Waker}; -... | -LL | | drop(cx_ref); -LL | | }); - | |_____- within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}` +LL | is_unwindsafe(async { + | _____^_____________- + | |_____| + | || +LL | || +LL | || use std::ptr::null; +LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker}; +... || +LL | || drop(cx_ref); +LL | || }); + | ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary + | |_____| + | within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}` | - = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>` + = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe` = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>` note: future does not implement `UnwindSafe` as this value is used across an await --> $DIR/async-is-unwindsafe.rs:25:18 diff --git a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr index 8c9d06c79ca42..eab5bea681cb1 100644 --- a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr +++ b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr @@ -7,7 +7,7 @@ LL | [0usize; 0xffff_ffff_ffff_ffff].await; | |`[usize; usize::MAX]` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `[usize; usize::MAX]` + = help: the trait `Future` is not implemented for `[usize; usize::MAX]`, which is required by `[usize; usize::MAX]: IntoFuture` = note: [usize; usize::MAX] must be a future or must implement `IntoFuture` to be awaited = note: required for `[usize; usize::MAX]` to implement `IntoFuture` diff --git a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr index 721e01062937e..53cdc9b61d32b 100644 --- a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr +++ b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr @@ -15,7 +15,7 @@ LL | None { value: (), ..Default::default() }.await; | |`Option<_>` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `Option<_>` + = help: the trait `Future` is not implemented for `Option<_>`, which is required by `Option<_>: IntoFuture` = note: Option<_> must be a future or must implement `IntoFuture` to be awaited = note: required for `Option<_>` to implement `IntoFuture` diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr index 9fce4d61b3b6f..ce2cee6ed4735 100644 --- a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(agent.handle()); | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/drop-track-field-assign-nonsend.rs:20:39 | diff --git a/tests/ui/async-await/field-assign-nonsend.stderr b/tests/ui/async-await/field-assign-nonsend.stderr index 418a0829c657e..525a2cc78b493 100644 --- a/tests/ui/async-await/field-assign-nonsend.stderr +++ b/tests/ui/async-await/field-assign-nonsend.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(agent.handle()); | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Rc` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/field-assign-nonsend.rs:20:39 | diff --git a/tests/ui/async-await/for-await-passthrough.rs b/tests/ui/async-await/for-await-passthrough.rs index 7fa133aaedcd7..b1a382958a157 100644 --- a/tests/ui/async-await/for-await-passthrough.rs +++ b/tests/ui/async-await/for-await-passthrough.rs @@ -25,8 +25,7 @@ async fn real_main() { fn main() { let future = real_main(); - let waker = std::task::Waker::noop(); - let mut cx = &mut core::task::Context::from_waker(&waker); + let mut cx = &mut core::task::Context::from_waker(std::task::Waker::noop()); let mut future = core::pin::pin!(future); while let core::task::Poll::Pending = future.as_mut().poll(&mut cx) {} } diff --git a/tests/ui/async-await/for-await.rs b/tests/ui/async-await/for-await.rs index 6345ceb0c2798..00dbdfb2389d5 100644 --- a/tests/ui/async-await/for-await.rs +++ b/tests/ui/async-await/for-await.rs @@ -17,8 +17,7 @@ async fn real_main() { fn main() { let future = real_main(); - let waker = std::task::Waker::noop(); - let mut cx = &mut core::task::Context::from_waker(&waker); + let mut cx = &mut core::task::Context::from_waker(std::task::Waker::noop()); let mut future = core::pin::pin!(future); while let core::task::Poll::Pending = future.as_mut().poll(&mut cx) {} } diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs index 491dfcc6ae0fd..8c01f1bddefd6 100644 --- a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs @@ -40,8 +40,7 @@ fn main() { let mut fut = pin!(async_main()); // Poll loop, just to test the future... - let waker = Waker::noop(); - let ctx = &mut Context::from_waker(&waker); + let ctx = &mut Context::from_waker(Waker::noop()); loop { match fut.as_mut().poll(ctx) { diff --git a/tests/ui/async-await/in-trait/auxiliary/bad-region.rs b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs new file mode 100644 index 0000000000000..02dc25aaa16bb --- /dev/null +++ b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs @@ -0,0 +1,7 @@ +// edition:2021 + +#[allow(async_fn_in_trait)] + +pub trait BleRadio<'a> { + async fn transmit(&mut self); +} diff --git a/tests/ui/async-await/in-trait/bad-region.rs b/tests/ui/async-await/in-trait/bad-region.rs new file mode 100644 index 0000000000000..444368e21a497 --- /dev/null +++ b/tests/ui/async-await/in-trait/bad-region.rs @@ -0,0 +1,17 @@ +// aux-build:bad-region.rs +// edition:2021 + +#![allow(async_fn_in_trait)] + +extern crate bad_region as jewel; + +use jewel::BleRadio; + +pub struct Radio {} + +impl BleRadio for Radio { +//~^ ERROR implicit elided lifetime not allowed here + async fn transmit(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/bad-region.stderr b/tests/ui/async-await/in-trait/bad-region.stderr new file mode 100644 index 0000000000000..9203fd790af78 --- /dev/null +++ b/tests/ui/async-await/in-trait/bad-region.stderr @@ -0,0 +1,14 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/bad-region.rs:12:6 + | +LL | impl BleRadio for Radio { + | ^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | impl BleRadio<'_> for Radio { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs index f21abf012ba99..e2fd9f9dfea4c 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs @@ -43,8 +43,7 @@ fn main() { let mut fut = pin!(async_main()); // Poll loop, just to test the future... - let waker = Waker::noop(); - let ctx = &mut Context::from_waker(&waker); + let ctx = &mut Context::from_waker(Waker::noop()); loop { match fut.as_mut().poll(ctx) { diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 0560cd9c5fe11..b7336485eb84d 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -21,7 +21,7 @@ LL | default async fn foo(_: T) -> &'static str { = note: specialization behaves in inconsistent and surprising ways with async functions in traits, and for now is disallowed error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future>` in the current scope - --> $DIR/dont-project-to-specializable-projection.rs:50:28 + --> $DIR/dont-project-to-specializable-projection.rs:49:28 | LL | match fut.as_mut().poll(ctx) { | ^^^^ method not found in `Pin<&mut impl Future>` diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr index aeabb5931dfc7..93f37a9a8e904 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_is_send(test::()); | ^^^^^^^^^^^ future returned by `test` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `impl Future` + = help: within `impl Future`, the trait `Send` is not implemented for `impl Future`, which is required by `impl Future: Send` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/missing-send-bound.rs:9:5 | diff --git a/tests/ui/async-await/in-trait/returning-possibly-unsized-self.rs b/tests/ui/async-await/in-trait/returning-possibly-unsized-self.rs new file mode 100644 index 0000000000000..72f02679d7712 --- /dev/null +++ b/tests/ui/async-await/in-trait/returning-possibly-unsized-self.rs @@ -0,0 +1,18 @@ +// check-pass +// edition:2021 + +#![deny(opaque_hidden_inferred_bound)] + +trait Repository /* : ?Sized */ { + async fn new() -> Self; +} + +struct MyRepository {} + +impl Repository for MyRepository { + async fn new() -> Self { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/async-await/issue-101715.stderr b/tests/ui/async-await/issue-101715.stderr index f6af15c00d621..3b429793b786f 100644 --- a/tests/ui/async-await/issue-101715.stderr +++ b/tests/ui/async-await/issue-101715.stderr @@ -7,7 +7,7 @@ LL | .await | |`()` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` diff --git a/tests/ui/async-await/issue-64130-1-sync.stderr b/tests/ui/async-await/issue-64130-1-sync.stderr index 5428d7ef71b30..15f49124f6fa0 100644 --- a/tests/ui/async-await/issue-64130-1-sync.stderr +++ b/tests/ui/async-await/issue-64130-1-sync.stderr @@ -4,7 +4,7 @@ error: future cannot be shared between threads safely LL | is_sync(bar()); | ^^^^^ future returned by `bar` is not `Sync` | - = help: within `impl Future`, the trait `Sync` is not implemented for `Foo` + = help: within `impl Future`, the trait `Sync` is not implemented for `Foo`, which is required by `impl Future: Sync` note: future is not `Sync` as this value is used across an await --> $DIR/issue-64130-1-sync.rs:15:11 | diff --git a/tests/ui/async-await/issue-64130-2-send.stderr b/tests/ui/async-await/issue-64130-2-send.stderr index f05e954d2d714..67368314b1b77 100644 --- a/tests/ui/async-await/issue-64130-2-send.stderr +++ b/tests/ui/async-await/issue-64130-2-send.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(bar()); | ^^^^^ future returned by `bar` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `Foo` + = help: within `impl Future`, the trait `Send` is not implemented for `Foo`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-2-send.rs:15:11 | diff --git a/tests/ui/async-await/issue-64130-3-other.stderr b/tests/ui/async-await/issue-64130-3-other.stderr index 3ac30bdc23e63..e3a73920c921a 100644 --- a/tests/ui/async-await/issue-64130-3-other.stderr +++ b/tests/ui/async-await/issue-64130-3-other.stderr @@ -5,7 +5,7 @@ LL | async fn bar() { | -------------- within this `impl Future` ... LL | is_qux(bar()); - | ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo` + | ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`, which is required by `impl Future: Qux` | note: future does not implement `Qux` as this value is used across an await --> $DIR/issue-64130-3-other.rs:18:11 diff --git a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr index d28807e223bef..bd890c838179e 100644 --- a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo()); | ^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-non-send-future-diags.rs:17:11 | diff --git a/tests/ui/async-await/issue-67252-unnamed-future.stderr b/tests/ui/async-await/issue-67252-unnamed-future.stderr index e1c5a22967e08..51c06b9c8afef 100644 --- a/tests/ui/async-await/issue-67252-unnamed-future.stderr +++ b/tests/ui/async-await/issue-67252-unnamed-future.stderr @@ -1,10 +1,14 @@ error: future cannot be sent between threads safely --> $DIR/issue-67252-unnamed-future.rs:18:5 | -LL | spawn(async { - | ^^^^^ future created by async block is not `Send` +LL | / spawn(async { +LL | | let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` +LL | | AFuture.await; +LL | | let _a = a; +LL | | }); + | |______^ future created by async block is not `Send` | - = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 22:6}`, the trait `Send` is not implemented for `*mut ()` + = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 22:6}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 22:6}: Send` note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:17 | diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr index 1cd8beac26035..f92ac5dd0bc56 100644 --- a/tests/ui/async-await/issue-68112.stderr +++ b/tests/ui/async-await/issue-68112.stderr @@ -2,9 +2,9 @@ error: future cannot be sent between threads safely --> $DIR/issue-68112.rs:34:5 | LL | require_send(send_fut); - | ^^^^^^^^^^^^ future created by async block is not `Send` + | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{async block@$DIR/issue-68112.rs:29:20: 33:6}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:31:17 @@ -21,9 +21,9 @@ error: future cannot be sent between threads safely --> $DIR/issue-68112.rs:43:5 | LL | require_send(send_fut); - | ^^^^^^^^^^^^ future created by async block is not `Send` + | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{async block@$DIR/issue-68112.rs:39:20: 42:6}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:40:17 @@ -40,9 +40,9 @@ error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:62:5 | LL | require_send(send_fut); - | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{async block@$DIR/issue-68112.rs:57:20: 61:6}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this `async` fn body diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index 14ef1cbb67c50..36e297ed88422 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -4,7 +4,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely LL | fn foo(x: NotSync) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:17:5: 21:6}: Send` note: required because it appears within the type `PhantomData<*mut ()>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `NotSync` diff --git a/tests/ui/async-await/issue-71137.stderr b/tests/ui/async-await/issue-71137.stderr index 8739c22a31048..75d72e425f57b 100644 --- a/tests/ui/async-await/issue-71137.stderr +++ b/tests/ui/async-await/issue-71137.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | fake_spawn(wrong_mutex()); | ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/issue-71137.rs:14:26 | diff --git a/tests/ui/async-await/issue-72590-type-error-sized.stderr b/tests/ui/async-await/issue-72590-type-error-sized.stderr index 778423578e169..1b822234d80cc 100644 --- a/tests/ui/async-await/issue-72590-type-error-sized.stderr +++ b/tests/ui/async-await/issue-72590-type-error-sized.stderr @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | async fn frob(self) {} | ^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `Sized` is not implemented for `str` + = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized` note: required because it appears within the type `Foo` --> $DIR/issue-72590-type-error-sized.rs:5:8 | diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs index 95683241aba26..904d28fb0a78d 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs @@ -12,6 +12,8 @@ pub async fn async_fn(x: &mut i32) -> &i32 { pub fn async_closure(x: &mut i32) -> impl Future { (async move || { + //~^ ERROR lifetime may not live long enough + //~| ERROR temporary value dropped while borrowed let y = &*x; *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed y @@ -20,6 +22,8 @@ pub fn async_closure(x: &mut i32) -> impl Future { pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { (async move || -> &i32 { + //~^ ERROR lifetime may not live long enough + //~| ERROR temporary value dropped while borrowed let y = &*x; *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed y diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr index 628ba1a481893..bdf2820887c8b 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -11,7 +11,7 @@ LL | y | - returning this value requires that `*x` is borrowed for `'1` error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:18:9 | LL | let y = &*x; | --- `*x` is borrowed here @@ -22,20 +22,92 @@ LL | y LL | })() | - return type of async closure is &'1 i32 +error: lifetime may not live long enough + --> $DIR/issue-74072-lifetime-name-annotations.rs:14:20 + | +LL | (async move || { + | ______-------------_^ + | | | | + | | | return type of async closure `{async closure body@$DIR/issue-74072-lifetime-name-annotations.rs:14:20: 20:6}` contains a lifetime `'2` + | | lifetime `'1` represents this closure's body +LL | | +LL | | +LL | | let y = &*x; +LL | | *x += 1; +LL | | y +LL | | })() + | |_____^ returning this value requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:14:5 + | +LL | pub fn async_closure(x: &mut i32) -> impl Future { + | - let's call the lifetime of this reference `'1` +LL | // (async move || { +LL | || +LL | || +LL | || let y = &*x; +LL | || *x += 1; +LL | || y +LL | || })() + | ||______^_- argument requires that borrow lasts for `'1` + | |_______| + | creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:24:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:28:9 | -LL | (async move || -> &i32 { - | - let's call the lifetime of this reference `'1` LL | let y = &*x; | --- `*x` is borrowed here LL | *x += 1; | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` +LL | })() + | - return type of async closure is &'1 i32 + +error: lifetime may not live long enough + --> $DIR/issue-74072-lifetime-name-annotations.rs:24:28 + | +LL | (async move || -> &i32 { + | ______---------------------_^ + | | | | + | | | return type of async closure `{async closure body@$DIR/issue-74072-lifetime-name-annotations.rs:24:28: 30:6}` contains a lifetime `'2` + | | lifetime `'1` represents this closure's body +LL | | +LL | | +LL | | let y = &*x; +LL | | *x += 1; +LL | | y +LL | | })() + | |_____^ returning this value requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:24:5 + | +LL | pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { + | - let's call the lifetime of this reference `'1` +LL | // (async move || -> &i32 { +LL | || +LL | || +LL | || let y = &*x; +LL | || *x += 1; +LL | || y +LL | || })() + | ||______^_- argument requires that borrow lasts for `'1` + | |_______| + | creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:36:9 | LL | let y = &*x; | --- `*x` is borrowed here @@ -46,6 +118,7 @@ LL | y LL | } | - return type of async block is &'1 i32 -error: aborting due to 4 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0506`. +Some errors have detailed explanations: E0506, E0716. +For more information about an error, try `rustc --explain E0506`. diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr index 90c1e976dcee6..12bbfc125521d 100644 --- a/tests/ui/async-await/issues/issue-67893.stderr +++ b/tests/ui/async-await/issues/issue-67893.stderr @@ -11,7 +11,7 @@ LL | g(issue_67893::run()) LL | pub async fn run() { | ------------------ within this `impl Future` | - = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `impl Future: Send` = note: required because it captures the following types: `Arc>`, `MutexGuard<'_, ()>`, `impl Future` note: required because it's used within this `async` fn body --> $DIR/auxiliary/issue_67893.rs:9:20 diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr index f088b118730aa..a6140c6db8286 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.stderr +++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr @@ -9,7 +9,7 @@ LL | gimme_send(foo()); LL | async fn foo() { | -------------- within this `impl Future` | - = help: within `impl Future`, the trait `Send` is not implemented for `NotSend` + = help: within `impl Future`, the trait `Send` is not implemented for `NotSend`, which is required by `impl Future: Send` = note: required because it appears within the type `(NotSend,)` = note: required because it captures the following types: `(NotSend,)`, `impl Future` note: required because it's used within this `async` fn body diff --git a/tests/ui/async-await/pin-needed-to-poll-2.stderr b/tests/ui/async-await/pin-needed-to-poll-2.stderr index 8eb671531e792..e22baabc25b53 100644 --- a/tests/ui/async-await/pin-needed-to-poll-2.stderr +++ b/tests/ui/async-await/pin-needed-to-poll-2.stderr @@ -2,7 +2,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned --> $DIR/pin-needed-to-poll-2.rs:43:18 | LL | Pin::new(&mut self.sleep).poll(cx) - | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned` + | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`, which is required by `Sleep: Unpin` | | | required by a bound introduced by this call | diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr index 620370a6113a3..8d81957653240 100644 --- a/tests/ui/async-await/unnecessary-await.stderr +++ b/tests/ui/async-await/unnecessary-await.stderr @@ -6,7 +6,7 @@ LL | boo().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` @@ -28,7 +28,7 @@ LL | e!().await; | |`()` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` @@ -44,7 +44,7 @@ LL | $expr.await LL | f!(()); | ------ in this macro invocation | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -58,7 +58,7 @@ LL | for x in [] {}.await | |`()` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` diff --git a/tests/ui/auto-traits/auto-trait-validation.fixed b/tests/ui/auto-traits/auto-trait-validation.fixed index da878ac6222bb..e37fed9faabae 100644 --- a/tests/ui/auto-traits/auto-trait-validation.fixed +++ b/tests/ui/auto-traits/auto-trait-validation.fixed @@ -1,4 +1,5 @@ #![feature(auto_traits)] +#![allow(dead_code)] // run-rustfix diff --git a/tests/ui/auto-traits/auto-trait-validation.rs b/tests/ui/auto-traits/auto-trait-validation.rs index d43055e270bd5..e209aa1322081 100644 --- a/tests/ui/auto-traits/auto-trait-validation.rs +++ b/tests/ui/auto-traits/auto-trait-validation.rs @@ -1,4 +1,5 @@ #![feature(auto_traits)] +#![allow(dead_code)] // run-rustfix diff --git a/tests/ui/auto-traits/auto-trait-validation.stderr b/tests/ui/auto-traits/auto-trait-validation.stderr index 89b63d23d4c8e..a6e5ac54869d2 100644 --- a/tests/ui/auto-traits/auto-trait-validation.stderr +++ b/tests/ui/auto-traits/auto-trait-validation.stderr @@ -1,5 +1,5 @@ error[E0567]: auto traits cannot have generic parameters - --> $DIR/auto-trait-validation.rs:5:19 + --> $DIR/auto-trait-validation.rs:6:19 | LL | auto trait Generic {} | -------^^^ help: remove the parameters @@ -7,7 +7,7 @@ LL | auto trait Generic {} | auto trait cannot have generic parameters error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/auto-trait-validation.rs:7:17 + --> $DIR/auto-trait-validation.rs:8:17 | LL | auto trait Bound : Copy {} | -----^^^^^^^ help: remove the super traits or lifetime bounds @@ -15,7 +15,7 @@ LL | auto trait Bound : Copy {} | auto traits cannot have super traits or lifetime bounds error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/auto-trait-validation.rs:9:25 + --> $DIR/auto-trait-validation.rs:10:25 | LL | auto trait LifetimeBound : 'static {} | -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds @@ -23,7 +23,7 @@ LL | auto trait LifetimeBound : 'static {} | auto traits cannot have super traits or lifetime bounds error[E0380]: auto traits cannot have associated items - --> $DIR/auto-trait-validation.rs:11:25 + --> $DIR/auto-trait-validation.rs:12:25 | LL | auto trait MyTrait { fn foo() {} } | ------- ---^^^----- diff --git a/tests/ui/auto-traits/auto-traits.rs b/tests/ui/auto-traits/auto-traits.rs index 6d8e1a52ec129..1e0fbcc1fdf63 100644 --- a/tests/ui/auto-traits/auto-traits.rs +++ b/tests/ui/auto-traits/auto-traits.rs @@ -19,8 +19,8 @@ fn take_auto_unsafe(_: T) {} fn main() { // Parse inside functions. - auto trait AutoInner {} - unsafe auto trait AutoUnsafeInner {} + auto trait AutoInner {} //~ WARN trait `AutoInner` is never used + unsafe auto trait AutoUnsafeInner {} //~ WARN trait `AutoUnsafeInner` is never used take_auto(0); take_auto(AutoBool(true)); diff --git a/tests/ui/auto-traits/auto-traits.stderr b/tests/ui/auto-traits/auto-traits.stderr new file mode 100644 index 0000000000000..34be8d3f67b8d --- /dev/null +++ b/tests/ui/auto-traits/auto-traits.stderr @@ -0,0 +1,16 @@ +warning: trait `AutoInner` is never used + --> $DIR/auto-traits.rs:22:16 + | +LL | auto trait AutoInner {} + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: trait `AutoUnsafeInner` is never used + --> $DIR/auto-traits.rs:23:23 + | +LL | unsafe auto trait AutoUnsafeInner {} + | ^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr index 80f9330eb8180..97f1a6032086e 100644 --- a/tests/ui/auto-traits/issue-83857-ub.stderr +++ b/tests/ui/auto-traits/issue-83857-ub.stderr @@ -4,7 +4,7 @@ error[E0277]: `Foo` cannot be sent between threads safely LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `Foo` + = help: the trait `Send` is not implemented for `Foo`, which is required by `Foo: WithAssoc` note: required for `Foo` to implement `WithAssoc` --> $DIR/issue-83857-ub.rs:15:15 | diff --git a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr index e1dae35be006d..ebd3a556e7579 100644 --- a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr +++ b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `[u8]: AutoTrait` is not satisfied in `str` --> $DIR/str-contains-slice-conceptually.rs:11:22 | LL | needs_auto_trait::(); - | ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]` + | ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]`, which is required by `str: AutoTrait` | = note: `str` is considered to contain a `[u8]` slice for auto trait purposes note: required by a bound in `needs_auto_trait` diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr index aa5585a5371f6..b7c9738991274 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)` --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:18 | LL | is_mytrait::<(MyS2, MyS)>(); - | ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2` + | ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`, which is required by `(MyS2, MyS): MyTrait` | = note: required because it appears within the type `(MyS2, MyS)` note: required by a bound in `is_mytrait` diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 2498af996eabd..e699422ae2b86 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied --> $DIR/typeck-default-trait-impl-precedence.rs:19:20 | LL | is_defaulted::<&'static u32>(); - | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32` + | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted` | note: required for `&'static u32` to implement `Defaulted` --> $DIR/typeck-default-trait-impl-precedence.rs:10:19 diff --git a/tests/ui/binding/match-range.rs b/tests/ui/binding/match-range.rs index 1dca84dfd45ff..cb7b93e7cc65f 100644 --- a/tests/ui/binding/match-range.rs +++ b/tests/ui/binding/match-range.rs @@ -1,5 +1,4 @@ // run-pass -#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620 #![feature(exclusive_range_pattern)] pub fn main() { diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index a98a2ab070666..8a226d712ff58 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -27,7 +27,7 @@ error[E0277]: can't compare `&{integer}` with `{integer}` LL | _ = foo == &0; | ^^ no implementation for `&{integer} == {integer}` | - = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}` + = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`, which is required by `&&{integer}: PartialEq<&{integer}>` = note: required for `&&{integer}` to implement `PartialEq<&{integer}>` help: consider dereferencing here | @@ -65,7 +65,7 @@ error[E0277]: can't compare `&&{integer}` with `{integer}` LL | _ = &&foo == &&0; | ^^ no implementation for `&&{integer} == {integer}` | - = help: the trait `PartialEq<{integer}>` is not implemented for `&&{integer}` + = help: the trait `PartialEq<{integer}>` is not implemented for `&&{integer}`, which is required by `&&&&{integer}: PartialEq<&&{integer}>` = note: required for `&&&{integer}` to implement `PartialEq<&{integer}>` = note: 1 redundant requirement hidden = note: required for `&&&&{integer}` to implement `PartialEq<&&{integer}>` @@ -119,7 +119,7 @@ error[E0277]: can't compare `{integer}` with `&{integer}` LL | _ = &0 == foo; | ^^ no implementation for `{integer} == &{integer}` | - = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}` + = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`, which is required by `&{integer}: PartialEq<&&{integer}>` = note: required for `&{integer}` to implement `PartialEq<&&{integer}>` help: consider dereferencing here | @@ -157,7 +157,7 @@ error[E0277]: can't compare `{integer}` with `&&{integer}` LL | _ = &&0 == &&foo; | ^^ no implementation for `{integer} == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `{integer}` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `{integer}`, which is required by `&&{integer}: PartialEq<&&&&{integer}>` = note: required for `&{integer}` to implement `PartialEq<&&&{integer}>` = note: 1 redundant requirement hidden = note: required for `&&{integer}` to implement `PartialEq<&&&&{integer}>` @@ -173,7 +173,7 @@ error[E0277]: can't compare `Box>` with `&&{integer}` LL | _ = &Box::new(Box::new(42)) == &foo; | ^^ no implementation for `Box> == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box>`, which is required by `&Box>: PartialEq<&&&{integer}>` = note: required for `&Box>` to implement `PartialEq<&&&{integer}>` help: consider dereferencing both sides of the expression | @@ -187,7 +187,7 @@ error[E0277]: can't compare `Box<{integer}>` with `&&{integer}` LL | _ = &Box::new(42) == &foo; | ^^ no implementation for `Box<{integer}> == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<{integer}>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<{integer}>`, which is required by `&Box<{integer}>: PartialEq<&&&{integer}>` = note: required for `&Box<{integer}>` to implement `PartialEq<&&&{integer}>` help: consider dereferencing both sides of the expression | @@ -201,7 +201,7 @@ error[E0277]: can't compare `Box>>>` with `&&{integer}` LL | _ = &Box::new(Box::new(Box::new(Box::new(42)))) == &foo; | ^^ no implementation for `Box>>> == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box>>>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box>>>`, which is required by `&Box>>>: PartialEq<&&&{integer}>` = note: required for `&Box>>>` to implement `PartialEq<&&&{integer}>` help: consider dereferencing both sides of the expression | @@ -215,7 +215,7 @@ error[E0277]: can't compare `&&{integer}` with `Box>>>` LL | _ = &foo == &Box::new(Box::new(Box::new(Box::new(42)))); | ^^ no implementation for `&&{integer} == Box>>>` | - = help: the trait `PartialEq>>>>` is not implemented for `&&{integer}` + = help: the trait `PartialEq>>>>` is not implemented for `&&{integer}`, which is required by `&&&{integer}: PartialEq<&Box>>>>` = note: required for `&&&{integer}` to implement `PartialEq<&Box>>>>` help: consider dereferencing both sides of the expression | diff --git a/tests/ui/block-result/issue-22645.stderr b/tests/ui/block-result/issue-22645.stderr index 1064848f5139e..2a267ce792fde 100644 --- a/tests/ui/block-result/issue-22645.stderr +++ b/tests/ui/block-result/issue-22645.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied --> $DIR/issue-22645.rs:15:5 | LL | b + 3 - | ^ the trait `Scalar` is not implemented for `{integer}` + | ^ the trait `Scalar` is not implemented for `{integer}`, which is required by `Bob: Add<_>` | = help: the trait `Scalar` is implemented for `f64` note: required for `Bob` to implement `Add<{integer}>` diff --git a/tests/ui/box/unit/unique-object-noncopyable.stderr b/tests/ui/box/unit/unique-object-noncopyable.stderr index 1b98d09ccddb0..8ea6edb48a7fc 100644 --- a/tests/ui/box/unit/unique-object-noncopyable.stderr +++ b/tests/ui/box/unit/unique-object-noncopyable.stderr @@ -1,24 +1,20 @@ error[E0599]: the method `clone` exists for struct `Box`, but its trait bounds were not satisfied --> $DIR/unique-object-noncopyable.rs:24:16 | -LL | trait Foo { - | --------- - | | - | doesn't satisfy `dyn Foo: Clone` - | doesn't satisfy `dyn Foo: Sized` +LL | trait Foo { + | --------- doesn't satisfy `dyn Foo: Clone` or `dyn Foo: Sized` ... -LL | let _z = y.clone(); - | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL - | - = note: doesn't satisfy `Box: Clone` +LL | let _z = y.clone(); + | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `dyn Foo: Sized` which is required by `Box: Clone` `dyn Foo: Clone` which is required by `Box: Clone` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `clone`, perhaps you need to implement it: + candidate #1: `Clone` error: aborting due to 1 previous error diff --git a/tests/ui/box/unit/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr index d662a2d6d0512..69428604b197f 100644 --- a/tests/ui/box/unit/unique-pinned-nocopy.stderr +++ b/tests/ui/box/unit/unique-pinned-nocopy.stderr @@ -1,22 +1,15 @@ error[E0599]: the method `clone` exists for struct `Box`, but its trait bounds were not satisfied --> $DIR/unique-pinned-nocopy.rs:12:16 | -LL | struct R { - | -------- doesn't satisfy `R: Clone` +LL | struct R { + | -------- doesn't satisfy `R: Clone` ... -LL | let _j = i.clone(); - | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL - | - = note: doesn't satisfy `Box: Clone` +LL | let _j = i.clone(); + | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `R: Clone` which is required by `Box: Clone` - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `Clone` help: consider annotating `R` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs index 2edc52c6f55f0..7e8820cb2c65d 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs +++ b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_imports)] diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs b/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs index 8d24771578444..50914b1de53f2 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs +++ b/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Simple test case of implementing a trait with super-builtin-kinds. // pretty-expanded FIXME #23616 diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs b/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs index f999dfff786eb..0577acc572ad5 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs +++ b/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Tests correct implementation of traits with super-builtin-kinds // using a bounded type parameter. diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs index 249481467e646..be6a6bb8b1755 100644 --- a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs +++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs @@ -8,7 +8,7 @@ trait Foo { fn foo(&self, _: T) -> u32 { 42 } } -trait Bar { +trait Bar { //~ WARN trait `Bar` is never used fn bar(&self) { println!("Bar!"); } } diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr new file mode 100644 index 0000000000000..952687e98d0ef --- /dev/null +++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/cast-rfc0401-vtable-kinds.rs:11:7 + | +LL | trait Bar { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/cast/fat-ptr-cast-rpass.rs b/tests/ui/cast/fat-ptr-cast-rpass.rs index f5747eb8b9666..c79468cadddd9 100644 --- a/tests/ui/cast/fat-ptr-cast-rpass.rs +++ b/tests/ui/cast/fat-ptr-cast-rpass.rs @@ -3,7 +3,7 @@ #![feature(ptr_metadata)] trait Foo { - fn foo(&self) {} + fn foo(&self) {} //~ WARN method `foo` is never used } struct Bar; diff --git a/tests/ui/cast/fat-ptr-cast-rpass.stderr b/tests/ui/cast/fat-ptr-cast-rpass.stderr new file mode 100644 index 0000000000000..d01688e0cc3b0 --- /dev/null +++ b/tests/ui/cast/fat-ptr-cast-rpass.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/fat-ptr-cast-rpass.rs:6:8 + | +LL | trait Foo { + | --- method in this trait +LL | fn foo(&self) {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs new file mode 100644 index 0000000000000..a6e68e1b7101c --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs @@ -0,0 +1,12 @@ +// #120427 +// This test checks we won't suggest more than 3 span suggestions for cfg names +// +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(foo,values("value")) --check-cfg=cfg(bar,values("value")) --check-cfg=cfg(bee,values("value")) --check-cfg=cfg(cow,values("value")) + +#[cfg(value)] +//~^ WARNING unexpected `cfg` condition name: `value` +fn x() {} + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr new file mode 100644 index 0000000000000..82d471d715b83 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition name: `value` + --> $DIR/cfg-value-for-cfg-name-duplicate.rs:8:7 + | +LL | #[cfg(value)] + | ^^^^^ + | + = help: expected names are: `bar`, `bee`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: to expect this configuration use `--check-cfg=cfg(value)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs new file mode 100644 index 0000000000000..edde6244ed1a9 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs @@ -0,0 +1,12 @@ +// #120427 +// This test checks that when a single cfg has a value for user's specified name +// +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(foo,values("my_value")) --check-cfg=cfg(bar,values("my_value")) + +#[cfg(my_value)] +//~^ WARNING unexpected `cfg` condition name: `my_value` +fn x() {} + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr new file mode 100644 index 0000000000000..b88ee71a156a2 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr @@ -0,0 +1,21 @@ +warning: unexpected `cfg` condition name: `my_value` + --> $DIR/cfg-value-for-cfg-name-multiple.rs:8:7 + | +LL | #[cfg(my_value)] + | ^^^^^^^^ + | + = help: expected names are: `bar`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: to expect this configuration use `--check-cfg=cfg(my_value)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: found config with similar value + | +LL | #[cfg(foo = "my_value")] + | ~~~~~~~~~~~~~~~~ +help: found config with similar value + | +LL | #[cfg(bar = "my_value")] + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs new file mode 100644 index 0000000000000..7a0c345b7ca76 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs @@ -0,0 +1,18 @@ +// #120427 +// This test checks that when a single cfg has a value for user's specified name +// suggest to use `#[cfg(target_os = "linux")]` instead of `#[cfg(linux)]` +// +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg() + +#[cfg(linux)] +//~^ WARNING unexpected `cfg` condition name: `linux` +fn x() {} + +// will not suggest if the cfg has a value +#[cfg(linux = "os-name")] +//~^ WARNING unexpected `cfg` condition name: `linux` +fn y() {} + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr new file mode 100644 index 0000000000000..c044755142419 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr @@ -0,0 +1,22 @@ +warning: unexpected `cfg` condition name: `linux` + --> $DIR/cfg-value-for-cfg-name.rs:9:7 + | +LL | #[cfg(linux)] + | ^^^^^ help: found config with similar value: `target_os = "linux"` + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: to expect this configuration use `--check-cfg=cfg(linux)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `linux` + --> $DIR/cfg-value-for-cfg-name.rs:14:7 + | +LL | #[cfg(linux = "os-name")] + | ^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(linux, values("os-name"))` + = note: see for more information about checking conditional configuration + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 9d134dcfcfd88..652e573d6ef32 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -143,7 +143,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -179,7 +179,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -208,7 +208,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, `wrs` + = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -252,7 +252,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` = note: see for more information about checking conditional configuration warning: 26 warnings emitted diff --git a/tests/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr b/tests/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr index d3cd8185f924b..e2a2db7c3f098 100644 --- a/tests/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr +++ b/tests/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr @@ -1,10 +1,13 @@ error[E0631]: type mismatch in closure arguments --> $DIR/expect-infer-var-appearing-twice.rs:14:5 | -LL | with_closure(|x: u32, y: i32| { - | ^^^^^^^^^^^^ ---------------- found signature defined here - | | - | expected due to this +LL | with_closure(|x: u32, y: i32| { + | ^ ---------------- found signature defined here + | _____| + | | +LL | | +LL | | }); + | |______^ expected due to this | = note: expected closure signature `fn(_, _) -> _` found closure signature `fn(u32, i32) -> _` diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr index c83ba41976bcd..8a2aaade66503 100644 --- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr @@ -5,8 +5,19 @@ LL | NUMBER_POINTER => (), | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/match-edge-cases_1.rs:29:13 + | +LL | NUMBER_POINTER => (), + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + diff --git a/tests/ui/closures/binder/async-closure-with-binder.rs b/tests/ui/closures/binder/async-closure-with-binder.rs index 4fa599d37cbd1..69d30f369e97d 100644 --- a/tests/ui/closures/binder/async-closure-with-binder.rs +++ b/tests/ui/closures/binder/async-closure-with-binder.rs @@ -1,8 +1,9 @@ // edition:2021 +// check-pass + #![feature(closure_lifetime_binder)] #![feature(async_closure)] + fn main() { - for<'a> async || (); - //~^ ERROR `for<...>` binders on `async` closures are not currently supported - //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + for<'a> async || -> () {}; } diff --git a/tests/ui/closures/binder/async-closure-with-binder.stderr b/tests/ui/closures/binder/async-closure-with-binder.stderr deleted file mode 100644 index 1d4628b1a494a..0000000000000 --- a/tests/ui/closures/binder/async-closure-with-binder.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: `for<...>` binders on `async` closures are not currently supported - --> $DIR/async-closure-with-binder.rs:5:5 - | -LL | for<'a> async || (); - | ^^^^^^^ - -error: implicit types in closure signatures are forbidden when `for<...>` is present - --> $DIR/async-closure-with-binder.rs:5:5 - | -LL | for<'a> async || (); - | -------^^^^^^^^^ - | | - | `for<...>` is here - -error: aborting due to 2 previous errors - diff --git a/tests/ui/closures/closure-move-sync.stderr b/tests/ui/closures/closure-move-sync.stderr index 2bb26b0c0b7d4..6cade0c09dd7e 100644 --- a/tests/ui/closures/closure-move-sync.stderr +++ b/tests/ui/closures/closure-move-sync.stderr @@ -10,7 +10,7 @@ LL | | LL | | }); | |_____^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>` + = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`, which is required by `{closure@$DIR/closure-move-sync.rs:6:27: 6:29}: Send` = note: required for `&std::sync::mpsc::Receiver<()>` to implement `Send` note: required because it's used within this closure --> $DIR/closure-move-sync.rs:6:27 diff --git a/tests/ui/closures/closure-return-type-must-be-sized.stderr b/tests/ui/closures/closure-return-type-must-be-sized.stderr index d4fc723fa8176..167d326e26edf 100644 --- a/tests/ui/closures/closure-return-type-must-be-sized.stderr +++ b/tests/ui/closures/closure-return-type-must-be-sized.stderr @@ -2,9 +2,9 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation --> $DIR/closure-return-type-must-be-sized.rs:54:5 | LL | a::foo:: dyn A>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | a::bar:: dyn A, _>(); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` note: required by a bound in `a::bar` --> $DIR/closure-return-type-must-be-sized.rs:14:19 @@ -25,18 +25,18 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation --> $DIR/closure-return-type-must-be-sized.rs:56:5 | LL | a::baz:: dyn A>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time --> $DIR/closure-return-type-must-be-sized.rs:61:5 | LL | b::foo:: dyn A>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -45,7 +45,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | b::bar:: dyn A, _>(); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: Fn()` = note: required because it appears within the type `fn() -> dyn A` note: required by a bound in `b::bar` --> $DIR/closure-return-type-must-be-sized.rs:28:19 @@ -57,18 +57,18 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation --> $DIR/closure-return-type-must-be-sized.rs:63:5 | LL | b::baz:: dyn A>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time --> $DIR/closure-return-type-must-be-sized.rs:68:5 | LL | c::foo:: dyn A>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -77,7 +77,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | c::bar:: dyn A, _>(); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnMut()` = note: required because it appears within the type `fn() -> dyn A` note: required by a bound in `c::bar` --> $DIR/closure-return-type-must-be-sized.rs:42:19 @@ -89,9 +89,9 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation --> $DIR/closure-return-type-must-be-sized.rs:70:5 | LL | c::baz:: dyn A>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` = note: required because it appears within the type `fn() -> dyn A` error: aborting due to 9 previous errors diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index 937bdf3bea255..ff46b10d005dc 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -17,7 +17,7 @@ LL | println!("{:?}", foo); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn Foo` -note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug` +note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'a>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/closures/issue-78720.rs b/tests/ui/closures/issue-78720.rs index 4cdb9f491130c..0e1f78ae3c69b 100644 --- a/tests/ui/closures/issue-78720.rs +++ b/tests/ui/closures/issue-78720.rs @@ -1,6 +1,7 @@ fn server() -> impl { //~^ ERROR at least one trait must be specified ().map2(|| "") + //~^ ERROR type annotations needed } trait FilterBase2 { diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr index 5d65c87b0fd61..d8d3811af5a74 100644 --- a/tests/ui/closures/issue-78720.stderr +++ b/tests/ui/closures/issue-78720.stderr @@ -5,7 +5,7 @@ LL | fn server() -> impl { | ^^^^ error[E0412]: cannot find type `F` in this scope - --> $DIR/issue-78720.rs:13:12 + --> $DIR/issue-78720.rs:14:12 | LL | _func: F, | ^ @@ -22,8 +22,14 @@ help: you might be missing a type parameter LL | struct Map2 { | +++ +error[E0282]: type annotations needed + --> $DIR/issue-78720.rs:3:5 + | +LL | ().map2(|| "") + | ^^^^^^^^^^^^^^ cannot infer type + error[E0308]: mismatched types - --> $DIR/issue-78720.rs:7:39 + --> $DIR/issue-78720.rs:8:39 | LL | fn map2(self, f: F) -> Map2 {} | ^^ expected `Map2`, found `()` @@ -32,7 +38,7 @@ LL | fn map2(self, f: F) -> Map2 {} found unit type `()` error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/issue-78720.rs:7:16 + --> $DIR/issue-78720.rs:8:16 | LL | fn map2(self, f: F) -> Map2 {} | ^^^^ doesn't have a size known at compile-time @@ -47,7 +53,7 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn map2(&self, f: F) -> Map2 {} | + -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0277, E0308, E0412. +Some errors have detailed explanations: E0277, E0282, E0308, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/closures/multiple-fn-bounds.stderr b/tests/ui/closures/multiple-fn-bounds.stderr index 325652ef14ce5..9a49fc99ac31a 100644 --- a/tests/ui/closures/multiple-fn-bounds.stderr +++ b/tests/ui/closures/multiple-fn-bounds.stderr @@ -2,8 +2,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/multiple-fn-bounds.rs:10:5 | LL | foo(move |x| v); - | ^^^ -------- found signature defined here - | | + | ^^^^--------^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `fn(_) -> _` diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index 02d75ff1228d6..b71cfc503339c 100644 --- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{mod1::f::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}` + found closure `{mod1::f::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr index a536768898988..88f4dc9b92ab4 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{f::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}` + found closure `{f::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-verbose.stderr b/tests/ui/closures/print/closure-print-verbose.stderr index fca8f25792ac3..204a86b633022 100644 --- a/tests/ui/closures/print/closure-print-verbose.stderr +++ b/tests/ui/closures/print/closure-print-verbose.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}` + found closure `{main::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn((u8,)) -> u8 upvar_tys=?4t}` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-print-verbose.rs:10:39 | diff --git a/tests/ui/codegen/issue-99551.rs b/tests/ui/codegen/issue-99551.rs index 9e203fba113c9..b223aff4e9492 100644 --- a/tests/ui/codegen/issue-99551.rs +++ b/tests/ui/codegen/issue-99551.rs @@ -1,4 +1,5 @@ // build-pass +#![feature(trait_upcasting)] pub trait A {} pub trait B {} diff --git a/tests/ui/codegen/mismatched-data-layout.json b/tests/ui/codegen/mismatched-data-layout.json new file mode 100644 index 0000000000000..4cb0602dc75b5 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layout.json @@ -0,0 +1,13 @@ +{ + "llvm-target": "x86_64-unknown-none-gnu", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "unknown", + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "executables": true +} + diff --git a/tests/ui/codegen/mismatched-data-layouts.rs b/tests/ui/codegen/mismatched-data-layouts.rs new file mode 100644 index 0000000000000..047ec155fdca6 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layouts.rs @@ -0,0 +1,14 @@ +// This test checks that data layout mismatches emit an error. +// +// build-fail +// needs-llvm-components: x86 +// compile-flags: --crate-type=lib --target={{src-base}}/codegen/mismatched-data-layout.json -Z unstable-options +// error-pattern: differs from LLVM target's +// normalize-stderr-test: "`, `[A-Za-z0-9-:]*`" -> "`, `normalized data layout`" +// normalize-stderr-test: "layout, `[A-Za-z0-9-:]*`" -> "layout, `normalized data layout`" + +#![feature(lang_items, no_core, auto_traits)] +#![no_core] + +#[lang = "sized"] +trait Sized {} diff --git a/tests/ui/codegen/mismatched-data-layouts.stderr b/tests/ui/codegen/mismatched-data-layouts.stderr new file mode 100644 index 0000000000000..1fe242266dff7 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layouts.stderr @@ -0,0 +1,4 @@ +error: data-layout for target `mismatched-data-layout-7814813422914914169`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout` + +error: aborting due to 1 previous error + diff --git a/tests/ui/coercion/issue-14589.rs b/tests/ui/coercion/issue-14589.rs index f92385f8d7275..6f95b30be06ae 100644 --- a/tests/ui/coercion/issue-14589.rs +++ b/tests/ui/coercion/issue-14589.rs @@ -19,6 +19,6 @@ impl Test { fn send(&self, _: T) {} } -trait Foo { fn dummy(&self) { }} +trait Foo { fn dummy(&self) { }} //~ WARN method `dummy` is never used struct Output(#[allow(dead_code)] isize); impl Foo for Output {} diff --git a/tests/ui/coercion/issue-14589.stderr b/tests/ui/coercion/issue-14589.stderr new file mode 100644 index 0000000000000..37b7fce7462b3 --- /dev/null +++ b/tests/ui/coercion/issue-14589.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-14589.rs:22:16 + | +LL | trait Foo { fn dummy(&self) { }} + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/coercion/issue-53475.rs b/tests/ui/coercion/issue-53475.rs index 3770c024fb92e..f389169f95405 100644 --- a/tests/ui/coercion/issue-53475.rs +++ b/tests/ui/coercion/issue-53475.rs @@ -3,7 +3,7 @@ use std::any::Any; use std::ops::CoerceUnsized; -struct Foo { +struct Foo { data: Box, } diff --git a/tests/ui/coherence/coherence-multidispatch-tuple.rs b/tests/ui/coherence/coherence-multidispatch-tuple.rs index fa1d4bbb49665..b04b2a296b5b4 100644 --- a/tests/ui/coherence/coherence-multidispatch-tuple.rs +++ b/tests/ui/coherence/coherence-multidispatch-tuple.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_imports)] // pretty-expanded FIXME #23616 diff --git a/tests/ui/command/command-create-pidfd.rs b/tests/ui/command/command-create-pidfd.rs deleted file mode 100644 index 4df443c66d65b..0000000000000 --- a/tests/ui/command/command-create-pidfd.rs +++ /dev/null @@ -1,56 +0,0 @@ -// run-pass -// only-linux - pidfds are a linux-specific concept - -#![feature(linux_pidfd)] -#![feature(rustc_private)] - -extern crate libc; - -use std::io::Error; -use std::os::linux::process::{ChildExt, CommandExt}; -use std::process::Command; - -fn has_clone3() -> bool { - let res = unsafe { libc::syscall(libc::SYS_clone3, 0, 0) }; - let err = (res == -1) - .then(|| Error::last_os_error()) - .expect("probe syscall should not succeed"); - - // If the `clone3` syscall is not implemented in the current kernel version it should return an - // `ENOSYS` error. Docker also blocks the whole syscall inside unprivileged containers, and - // returns `EPERM` (instead of `ENOSYS`) when a program tries to invoke the syscall. Because of - // that we need to check for *both* `ENOSYS` and `EPERM`. - // - // Note that Docker's behavior is breaking other projects (notably glibc), so they're planning - // to update their filtering to return `ENOSYS` in a future release: - // - // https://github.com/moby/moby/issues/42680 - // - err.raw_os_error() != Some(libc::ENOSYS) && err.raw_os_error() != Some(libc::EPERM) -} - -fn main() { - // pidfds require the clone3 syscall - if !has_clone3() { - return; - } - - // We don't assert the precise value, since the standard library - // might have opened other file descriptors before our code runs. - let _ = Command::new("echo") - .create_pidfd(true) - .spawn() - .unwrap() - .pidfd().expect("failed to obtain pidfd"); - - let _ = Command::new("echo") - .create_pidfd(false) - .spawn() - .unwrap() - .pidfd().expect_err("pidfd should not have been created when create_pid(false) is set"); - - let _ = Command::new("echo") - .spawn() - .unwrap() - .pidfd().expect_err("pidfd should not have been created"); -} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr index 1177965d0d2c2..771d661f615ec 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -2,7 +2,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_bad_empty_array.rs:10:13 | LL | check::<[NotParam; 0]>(); - | ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy` | = note: required for `[NotParam; 0]` to implement `ConstParamTy` note: required by a bound in `check` diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index 86d1c94e87f96..83c34c41f1059 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -2,7 +2,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13 | LL | check::<&NotParam>(); - | ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: ConstParamTy` | = note: required for `&NotParam` to implement `ConstParamTy` note: required by a bound in `check` @@ -15,7 +15,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 | LL | check::<[NotParam]>(); - | ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: ConstParamTy` | = note: required for `[NotParam]` to implement `ConstParamTy` note: required by a bound in `check` @@ -28,7 +28,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 | LL | check::<[NotParam; 17]>(); - | ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: ConstParamTy` | = note: required for `[NotParam; 17]` to implement `ConstParamTy` note: required by a bound in `check` diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs index 7174d1ec4f206..dfb8a36ec5350 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -8,13 +8,11 @@ impl std::marker::ConstParamTy for ImplementsConstParamTy {} struct CantParam(ImplementsConstParamTy); impl std::marker::ConstParamTy for CantParam {} -//~^ error: the type `CantParam` does not `#[derive(Eq)]` -//~| error: the type `CantParam` does not `#[derive(PartialEq)]` +//~^ error: the type `CantParam` does not `#[derive(PartialEq)]` //~| the trait bound `CantParam: Eq` is not satisfied #[derive(std::marker::ConstParamTy)] -//~^ error: the type `CantParamDerive` does not `#[derive(Eq)]` -//~| error: the type `CantParamDerive` does not `#[derive(PartialEq)]` +//~^ error: the type `CantParamDerive` does not `#[derive(PartialEq)]` //~| the trait bound `CantParamDerive: Eq` is not satisfied struct CantParamDerive(ImplementsConstParamTy); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index 2cf7cc07dbe5e..e213808cf7bd6 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -21,17 +21,8 @@ LL | impl std::marker::ConstParamTy for CantParam {} note: required by a bound in `ConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL -error[E0277]: the type `CantParam` does not `#[derive(Eq)]` - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36 - | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParam` - | -note: required by a bound in `ConstParamTy` - --> $SRC_DIR/core/src/marker.rs:LL:COL - error[E0277]: the trait bound `CantParamDerive: Eq` is not satisfied - --> $DIR/const_param_ty_impl_no_structural_eq.rs:15:10 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | LL | #[derive(std::marker::ConstParamTy)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` @@ -46,7 +37,7 @@ LL | struct CantParamDerive(ImplementsConstParamTy); | error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_no_structural_eq.rs:15:10 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | LL | #[derive(std::marker::ConstParamTy)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive` @@ -55,16 +46,6 @@ note: required by a bound in `ConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the type `CantParamDerive` does not `#[derive(Eq)]` - --> $DIR/const_param_ty_impl_no_structural_eq.rs:15:10 - | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParamDerive` - | -note: required by a bound in `ConstParamTy` - --> $SRC_DIR/core/src/marker.rs:LL:COL - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs index c04e96c569b41..f2986f9cc60d5 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params, structural_match)] +#![feature(adt_const_params)] union Union { a: u8, @@ -11,7 +11,6 @@ impl PartialEq for Union { } } impl Eq for Union {} -impl std::marker::StructuralEq for Union {} impl std::marker::ConstParamTy for Union {} //~^ ERROR the type `Union` does not `#[derive(PartialEq)]` @@ -28,7 +27,6 @@ impl PartialEq for UnionDerive { } } impl Eq for UnionDerive {} -impl std::marker::StructuralEq for UnionDerive {} fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr index 985b933c40c79..4c937db6c3ab5 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr @@ -1,11 +1,11 @@ error: this trait cannot be derived for unions - --> $DIR/const_param_ty_impl_union.rs:19:10 + --> $DIR/const_param_ty_impl_union.rs:18:10 | LL | #[derive(std::marker::ConstParamTy)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the type `Union` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_union.rs:16:36 + --> $DIR/const_param_ty_impl_union.rs:15:36 | LL | impl std::marker::ConstParamTy for Union {} | ^^^^^ the trait `StructuralPartialEq` is not implemented for `Union` diff --git a/tests/ui/const-generics/associated-type-bound.rs b/tests/ui/const-generics/associated-type-bound.rs index 3044736b47e05..0a57352c10da1 100644 --- a/tests/ui/const-generics/associated-type-bound.rs +++ b/tests/ui/const-generics/associated-type-bound.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass trait Bar {} trait Foo { diff --git a/tests/ui/const-generics/bad-generic-in-copy-impl.rs b/tests/ui/const-generics/bad-generic-in-copy-impl.rs index b5663464cf422..092a7af236bad 100644 --- a/tests/ui/const-generics/bad-generic-in-copy-impl.rs +++ b/tests/ui/const-generics/bad-generic-in-copy-impl.rs @@ -2,6 +2,7 @@ pub struct Foo { x: [u8; SIZE], //~^ ERROR mismatched types + //~| ERROR mismatched types } const SIZE: u32 = 1; diff --git a/tests/ui/const-generics/bad-generic-in-copy-impl.stderr b/tests/ui/const-generics/bad-generic-in-copy-impl.stderr index d60d8ec0e90d3..fbd546d42fb52 100644 --- a/tests/ui/const-generics/bad-generic-in-copy-impl.stderr +++ b/tests/ui/const-generics/bad-generic-in-copy-impl.stderr @@ -4,6 +4,14 @@ error[E0308]: mismatched types LL | x: [u8; SIZE], | ^^^^ expected `usize`, found `u32` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/bad-generic-in-copy-impl.rs:3:13 + | +LL | x: [u8; SIZE], + | ^^^^ expected `usize`, found `u32` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs index e13dfbacd2422..376b18c15b8ae 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.rs +++ b/tests/ui/const-generics/bad-subst-const-kind.rs @@ -11,3 +11,4 @@ impl Q for [u8; N] { } pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() } +//~^ ERROR: the constant `13` is not of type `u64` diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr index 6f5bc567c378b..c04a05573bed0 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.stderr +++ b/tests/ui/const-generics/bad-subst-const-kind.stderr @@ -1,9 +1,23 @@ +error: the constant `13` is not of type `u64` + --> $DIR/bad-subst-const-kind.rs:13:24 + | +LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() } + | ^^^^^^^^ expected `u64`, found `usize` + | +note: required for `[u8; 13]` to implement `Q` + --> $DIR/bad-subst-const-kind.rs:8:20 + | +LL | impl Q for [u8; N] { + | ------------ ^ ^^^^^^^ + | | + | unsatisfied trait bound introduced here + error[E0308]: mismatched types --> $DIR/bad-subst-const-kind.rs:8:31 | LL | impl Q for [u8; N] { | ^ expected `usize`, found `u64` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/condition-in-trait-const-arg.rs b/tests/ui/const-generics/condition-in-trait-const-arg.rs index 6f85237cf0aaf..74a663a53ec6b 100644 --- a/tests/ui/const-generics/condition-in-trait-const-arg.rs +++ b/tests/ui/const-generics/condition-in-trait-const-arg.rs @@ -1,5 +1,5 @@ // Checks that `impl Trait<{anon_const}> for Type` evaluates successfully. -// run-pass +// check-pass // revisions: full min #![cfg_attr(full, feature(generic_const_exprs))] diff --git a/tests/ui/const-generics/defaults/rp_impl_trait_fail.rs b/tests/ui/const-generics/defaults/rp_impl_trait_fail.rs index 80013e7b4b230..ba41bf38a3379 100644 --- a/tests/ui/const-generics/defaults/rp_impl_trait_fail.rs +++ b/tests/ui/const-generics/defaults/rp_impl_trait_fail.rs @@ -25,6 +25,6 @@ fn owo() -> impl Traitor { fn main() { rawr(); - uwu(); + uwu(); //~ ERROR: type annotations needed owo(); } diff --git a/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr index a46bd53520b53..4ed1c0ded9f86 100644 --- a/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -31,6 +31,18 @@ LL | 1_u64 | = help: the trait `Traitor<1, 2>` is implemented for `u64` -error: aborting due to 3 previous errors +error[E0282]: type annotations needed + --> $DIR/rp_impl_trait_fail.rs:28:5 + | +LL | uwu(); + | ^^^ cannot infer the value of the const parameter `N` declared on the function `uwu` + | +help: consider specifying the generic argument + | +LL | uwu::(); + | +++++ + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0282. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/dyn-supertraits.rs b/tests/ui/const-generics/dyn-supertraits.rs index 3dee326a186e9..bb4924529824b 100644 --- a/tests/ui/const-generics/dyn-supertraits.rs +++ b/tests/ui/const-generics/dyn-supertraits.rs @@ -4,7 +4,7 @@ trait Foo { fn myfun(&self) -> usize; } trait Bar : Foo {} -trait Baz: Foo<3> {} +trait Baz: Foo<3> {} //~ WARN trait `Baz` is never used struct FooType; struct BarType; @@ -23,10 +23,10 @@ impl Foo<3> for BazType { impl Baz for BazType {} trait Foz {} -trait Boz: Foo<3> + Foz {} +trait Boz: Foo<3> + Foz {} //~ WARN trait `Boz` is never used trait Bok: Foo + Foz {} -struct FozType; +struct FozType; //~ WARN struct `FozType` is never constructed struct BozType; struct BokType; diff --git a/tests/ui/const-generics/dyn-supertraits.stderr b/tests/ui/const-generics/dyn-supertraits.stderr new file mode 100644 index 0000000000000..38b67ef4403a1 --- /dev/null +++ b/tests/ui/const-generics/dyn-supertraits.stderr @@ -0,0 +1,22 @@ +warning: trait `Baz` is never used + --> $DIR/dyn-supertraits.rs:7:7 + | +LL | trait Baz: Foo<3> {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: trait `Boz` is never used + --> $DIR/dyn-supertraits.rs:26:7 + | +LL | trait Boz: Foo<3> + Foz {} + | ^^^ + +warning: struct `FozType` is never constructed + --> $DIR/dyn-supertraits.rs:29:8 + | +LL | struct FozType; + | ^^^^^^^ + +warning: 3 warnings emitted + diff --git a/tests/ui/const-generics/ensure_is_evaluatable.stderr b/tests/ui/const-generics/ensure_is_evaluatable.stderr index a6f362308200a..b9bd9160b13c2 100644 --- a/tests/ui/const-generics/ensure_is_evaluatable.stderr +++ b/tests/ui/const-generics/ensure_is_evaluatable.stderr @@ -2,7 +2,7 @@ error: unconstrained generic constant --> $DIR/ensure_is_evaluatable.rs:9:5 | LL | bar() - | ^^^ + | ^^^^^ | = help: try adding a `where` bound using this expression: `where [(); N + 1]:` note: required by a bound in `bar` diff --git a/tests/ui/const-generics/fn_with_two_const_inputs.stderr b/tests/ui/const-generics/fn_with_two_const_inputs.stderr index ad32a688c03f7..ec31e02f144b8 100644 --- a/tests/ui/const-generics/fn_with_two_const_inputs.stderr +++ b/tests/ui/const-generics/fn_with_two_const_inputs.stderr @@ -2,7 +2,7 @@ error: unconstrained generic constant --> $DIR/fn_with_two_const_inputs.rs:12:5 | LL | bar() - | ^^^ + | ^^^^^ | = help: try adding a `where` bound using this expression: `where [(); N + 1]:` note: required by a bound in `bar` diff --git a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr index a6b736261e09c..6d8dd017734c0 100644 --- a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr +++ b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr @@ -10,14 +10,14 @@ error: expected identifier, found reserved identifier `_` LL | fn bad_infer_fn<_>() {} | ^ expected identifier, found reserved identifier -error[E0392]: parameter `_` is never used +error[E0392]: type parameter `_` is never used --> $DIR/infer-arg-test.rs:7:17 | LL | struct BadInfer<_>; - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `_` to be a const parameter, use `const _: usize` instead + = help: if you intended `_` to be a const parameter, use `const _: /* Type */` instead error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supplied --> $DIR/infer-arg-test.rs:18:10 diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index f2cc17bc517cd..6d3b0b8508c07 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -2,7 +2,7 @@ error[E0283]: type annotations needed for `Mask<_, N>` --> $DIR/issue-91614.rs:6:9 | LL | let y = Mask::<_, _>::splat(false); - | ^ ------------------- type must be known at this point + | ^ -------------------------- type must be known at this point | = note: cannot satisfy `_: MaskElement` = help: the following types implement trait `MaskElement`: diff --git a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr index cdf97bd88fd23..bd6fd67b89d74 100644 --- a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr +++ b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr @@ -20,7 +20,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:17:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }` | = note: expected constant `{ N as u128 }` found constant `{ O as u128 }` @@ -52,7 +52,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:20:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }` | = note: expected constant `{ N as _ }` found constant `{ O as u128 }` @@ -66,7 +66,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:23:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13` | = note: expected constant `12` found constant `13` @@ -80,7 +80,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:25:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14` | = note: expected constant `13` found constant `14` @@ -112,7 +112,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:35:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }` | = note: expected constant `{ N as u128 }` found constant `{ O as u128 }` @@ -144,7 +144,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:38:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }` | = note: expected constant `{ N as _ }` found constant `{ O as u128 }` @@ -158,7 +158,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:41:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13` | = note: expected constant `12` found constant `13` @@ -172,7 +172,7 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:43:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14` | = note: expected constant `13` found constant `14` diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr index 0742db398c9c4..87e26ce85dcfd 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr @@ -15,6 +15,18 @@ LL | ArrayHolder([0; Self::SIZE]) | = help: try adding a `where` bound using this expression: `where [(); Self::SIZE]:` -error: aborting due to 2 previous errors +error[E0282]: type annotations needed for `ArrayHolder` + --> $DIR/issue-62504.rs:26:9 + | +LL | let mut array = ArrayHolder::new(); + | ^^^^^^^^^ + | +help: consider giving `array` an explicit type, where the value of const parameter `X` is specified + | +LL | let mut array: ArrayHolder = ArrayHolder::new(); + | ++++++++++++++++ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr index 65822856e1d7c..1664669eee05a 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr @@ -22,6 +22,18 @@ note: tuple struct defined here LL | struct ArrayHolder([u32; X]); | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0282]: type annotations needed for `ArrayHolder` + --> $DIR/issue-62504.rs:26:9 + | +LL | let mut array = ArrayHolder::new(); + | ^^^^^^^^^ + | +help: consider giving `array` an explicit type, where the value of const parameter `X` is specified + | +LL | let mut array: ArrayHolder = ArrayHolder::new(); + | ++++++++++++++++ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.rs b/tests/ui/const-generics/generic_const_exprs/issue-62504.rs index a97f4b8ff3131..6f40a9abfa796 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.rs @@ -24,4 +24,5 @@ impl ArrayHolder { fn main() { let mut array = ArrayHolder::new(); + //~^ ERROR: type annotations needed } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr index 9391b1c1a170a..3acccba026f26 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied --> $DIR/issue-85848.rs:24:29 | LL | writes_to_specific_path(&cap); - | ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()` + | ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`, which is required by `&C: Delegates<()>` | | | required by a bound introduced by this call | @@ -58,7 +58,7 @@ error[E0308]: mismatched types --> $DIR/issue-85848.rs:24:5 | LL | writes_to_specific_path(&cap); - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `{ contains::() }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `{ contains::() }` | = note: expected constant `true` found constant `{ contains::() }` diff --git a/tests/ui/const-generics/generic_const_exprs/obligation-cause.stderr b/tests/ui/const-generics/generic_const_exprs/obligation-cause.stderr index eba8b9b6257e5..7f6a154865ceb 100644 --- a/tests/ui/const-generics/generic_const_exprs/obligation-cause.stderr +++ b/tests/ui/const-generics/generic_const_exprs/obligation-cause.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/obligation-cause.rs:20:5 | LL | g::(); - | ^^^^^^^^^^ expected `false`, found `true` + | ^^^^^^^^^^^^ expected `false`, found `true` | = note: expected constant `false` found constant `true` diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs index 5813f09818410..6b0d9e047dbc3 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs @@ -7,7 +7,10 @@ trait Q { impl Q for [u8; N] {} //~^ ERROR not all trait items implemented +//~| ERROR mismatched types pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} +//~^ ERROR the constant `13` is not of type `u64` +//~| ERROR mismatched types pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr index c73d1022ed312..bb6d650b7ab27 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr @@ -7,6 +7,35 @@ LL | const ASSOC: usize; LL | impl Q for [u8; N] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation -error: aborting due to 1 previous error +error: the constant `13` is not of type `u64` + --> $DIR/type_mismatch.rs:12:26 + | +LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} + | ^^^^^^^^ expected `u64`, found `usize` + | +note: required for `[u8; 13]` to implement `Q` + --> $DIR/type_mismatch.rs:8:20 + | +LL | impl Q for [u8; N] {} + | ------------ ^ ^^^^^^^ + | | + | unsatisfied trait bound introduced here + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:12:20 + | +LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} + | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `[u8; <[u8; 13] as Q>::ASSOC]`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:8:31 + | +LL | impl Q for [u8; N] {} + | ^ expected `usize`, found `u64` + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0046, E0308. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr index 3bae93ccb83fb..220fcd38b0976 100644 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq)]` --> $DIR/typeid-equality-by-subtyping.rs:18:9 | LL | WHAT_A_TYPE => 0, | ^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issue-46511.stderr b/tests/ui/const-generics/issue-46511.stderr index d57295fa2fae1..75d59ee40b3b7 100644 --- a/tests/ui/const-generics/issue-46511.stderr +++ b/tests/ui/const-generics/issue-46511.stderr @@ -7,11 +7,11 @@ LL | _a: [u8; std::mem::size_of::<&'a mut u8>()] = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/issue-46511.rs:3:12 | LL | struct Foo<'a> - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/const-generics/issues/issue-61336-2.stderr b/tests/ui/const-generics/issues/issue-61336-2.stderr index 0af6f87a68df8..b0864689f7400 100644 --- a/tests/ui/const-generics/issues/issue-61336-2.stderr +++ b/tests/ui/const-generics/issues/issue-61336-2.stderr @@ -5,6 +5,8 @@ LL | [x; { N }] | ^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider restricting type parameter `T` | LL | fn g(x: T) -> [T; N] { diff --git a/tests/ui/const-generics/issues/issue-61336.stderr b/tests/ui/const-generics/issues/issue-61336.stderr index 4132e511240ae..111afbda343f7 100644 --- a/tests/ui/const-generics/issues/issue-61336.stderr +++ b/tests/ui/const-generics/issues/issue-61336.stderr @@ -5,6 +5,8 @@ LL | [x; N] | ^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider restricting type parameter `T` | LL | fn g(x: T) -> [T; N] { diff --git a/tests/ui/const-generics/issues/issue-67185-2.stderr b/tests/ui/const-generics/issues/issue-67185-2.stderr index a2e5b8053688b..24a2d60f2e1f0 100644 --- a/tests/ui/const-generics/issues/issue-67185-2.stderr +++ b/tests/ui/const-generics/issues/issue-67185-2.stderr @@ -26,7 +26,7 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied --> $DIR/issue-67185-2.rs:21:6 | LL | impl Foo for FooImpl {} - | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | ^^^ the trait `Bar` is not implemented for `[u16; 3]`, which is required by `::Quaks: Bar` | = help: the following other types implement trait `Bar`: [u16; 4] @@ -44,7 +44,7 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied --> $DIR/issue-67185-2.rs:21:6 | LL | impl Foo for FooImpl {} - | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`, which is required by `[::Quaks; 2]: Bar` | = help: the following other types implement trait `Bar`: [u16; 4] diff --git a/tests/ui/const-generics/issues/issue-67375.min.stderr b/tests/ui/const-generics/issues/issue-67375.min.stderr index 7671e3c468876..e871203ed9b89 100644 --- a/tests/ui/const-generics/issues/issue-67375.min.stderr +++ b/tests/ui/const-generics/issues/issue-67375.min.stderr @@ -7,14 +7,14 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }], = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-67375.rs:5:12 | LL | struct Bug { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-67945-1.min.stderr b/tests/ui/const-generics/issues/issue-67945-1.min.stderr index 1d071da903fa1..1de607644f570 100644 --- a/tests/ui/const-generics/issues/issue-67945-1.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-1.min.stderr @@ -16,14 +16,14 @@ LL | let b = &*(&x as *const _ as *const S); = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0392]: parameter `S` is never used +error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-1.rs:7:12 | LL | struct Bug { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead + = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/issues/issue-67945-3.min.stderr b/tests/ui/const-generics/issues/issue-67945-3.min.stderr index e34869c79386b..0ccba18e953cf 100644 --- a/tests/ui/const-generics/issues/issue-67945-3.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-3.min.stderr @@ -7,14 +7,14 @@ LL | let x: Option = None; = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0392]: parameter `S` is never used +error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-3.rs:9:12 | LL | struct Bug { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead + = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-67945-4.min.stderr b/tests/ui/const-generics/issues/issue-67945-4.min.stderr index 280c6f4f2cdfe..83ae68e2dbf0e 100644 --- a/tests/ui/const-generics/issues/issue-67945-4.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-4.min.stderr @@ -7,14 +7,14 @@ LL | let x: Option> = None; = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0392]: parameter `S` is never used +error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-4.rs:8:12 | LL | struct Bug { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead + = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.rs b/tests/ui/const-generics/issues/issue-69654-run-pass.rs index 63d7fde78ac8a..21d6270b1fafa 100644 --- a/tests/ui/const-generics/issues/issue-69654-run-pass.rs +++ b/tests/ui/const-generics/issues/issue-69654-run-pass.rs @@ -1,5 +1,5 @@ // run-pass -trait Bar {} +trait Bar {} //~ WARN trait `Bar` is never used impl Bar for [u8; 7] {} struct Foo {} diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.stderr b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr new file mode 100644 index 0000000000000..7b3cd4f375fd0 --- /dev/null +++ b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/issue-69654-run-pass.rs:2:7 + | +LL | trait Bar {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/const-generics/issues/issue-74950.min.stderr b/tests/ui/const-generics/issues/issue-74950.min.stderr index 54ef1ea1e94c0..a573dac608753 100644 --- a/tests/ui/const-generics/issues/issue-74950.min.stderr +++ b/tests/ui/const-generics/issues/issue-74950.min.stderr @@ -1,5 +1,5 @@ error: `Inner` is forbidden as the type of a const generic parameter - --> $DIR/issue-74950.rs:20:23 + --> $DIR/issue-74950.rs:19:23 | LL | struct Outer; | ^^^^^ @@ -8,7 +8,7 @@ LL | struct Outer; = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types error: `Inner` is forbidden as the type of a const generic parameter - --> $DIR/issue-74950.rs:20:23 + --> $DIR/issue-74950.rs:19:23 | LL | struct Outer; | ^^^^^ @@ -18,7 +18,7 @@ LL | struct Outer; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `Inner` is forbidden as the type of a const generic parameter - --> $DIR/issue-74950.rs:20:23 + --> $DIR/issue-74950.rs:19:23 | LL | struct Outer; | ^^^^^ @@ -28,7 +28,7 @@ LL | struct Outer; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `Inner` is forbidden as the type of a const generic parameter - --> $DIR/issue-74950.rs:20:23 + --> $DIR/issue-74950.rs:19:23 | LL | struct Outer; | ^^^^^ @@ -37,15 +37,5 @@ LL | struct Outer; = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `Inner` is forbidden as the type of a const generic parameter - --> $DIR/issue-74950.rs:20:23 - | -LL | struct Outer; - | ^^^^^ - | - = note: the only supported types are integers, `bool` and `char` - = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/issues/issue-74950.rs b/tests/ui/const-generics/issues/issue-74950.rs index 43bb322656b3e..f1f9bd16ebe1d 100644 --- a/tests/ui/const-generics/issues/issue-74950.rs +++ b/tests/ui/const-generics/issues/issue-74950.rs @@ -15,13 +15,11 @@ struct Inner; // - impl PartialEq // - impl Eq // - impl StructuralPartialEq -// - impl StructuralEq #[derive(PartialEq, Eq)] struct Outer; //[min]~^ `Inner` is forbidden //[min]~| `Inner` is forbidden //[min]~| `Inner` is forbidden //[min]~| `Inner` is forbidden -//[min]~| `Inner` is forbidden fn main() {} diff --git a/tests/ui/const-generics/issues/issue-79674.stderr b/tests/ui/const-generics/issues/issue-79674.stderr index 1e7878e8da95c..595bb6faf8c00 100644 --- a/tests/ui/const-generics/issues/issue-79674.stderr +++ b/tests/ui/const-generics/issues/issue-79674.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-79674.rs:26:5 | LL | requires_distinct("str", 12); - | ^^^^^^^^^^^^^^^^^ expected `true`, found `false` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `false` | = note: expected constant `true` found constant `false` diff --git a/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr b/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr index 07da6ede7251b..989be74d1b0d9 100644 --- a/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr +++ b/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr @@ -2,7 +2,7 @@ error[E0284]: type annotations needed --> $DIR/parent_generics_of_encoding_impl_trait.rs:9:5 | LL | generics_of_parent_impl_trait::foo([()]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `foo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `foo` | note: required by a bound in `foo` --> $DIR/auxiliary/generics_of_parent_impl_trait.rs:6:48 diff --git a/tests/ui/const-generics/unused-type-param-suggestion.rs b/tests/ui/const-generics/unused-type-param-suggestion.rs index 2251512c4596e..fb0ccb4fdcd72 100644 --- a/tests/ui/const-generics/unused-type-param-suggestion.rs +++ b/tests/ui/const-generics/unused-type-param-suggestion.rs @@ -1,4 +1,27 @@ #![crate_type="lib"] -struct Example; -//~^ ERROR parameter +struct S; +//~^ ERROR type parameter `N` is never used +//~| HELP consider removing `N` +//~| HELP if you intended `N` to be a const parameter + +// Ensure that we don't emit the const param suggestion here: +struct T; +//~^ ERROR type parameter `N` is never used +//~| HELP consider removing `N` + +type A = (); +//~^ ERROR type parameter `N` is never used +//~| HELP consider removing `N` +//~| HELP if you intended `N` to be a const parameter + +// Ensure that we don't emit the const param suggestion here: +type B = (); +//~^ ERROR type parameter `N` is never used +//~| HELP consider removing `N` +type C = (); +//~^ ERROR type parameter `N` is never used +//~| HELP consider removing `N` +type D = (); +//~^ ERROR type parameter `N` is never used +//~| HELP consider removing `N` diff --git a/tests/ui/const-generics/unused-type-param-suggestion.stderr b/tests/ui/const-generics/unused-type-param-suggestion.stderr index 6e985f56666bd..67b704d8bc725 100644 --- a/tests/ui/const-generics/unused-type-param-suggestion.stderr +++ b/tests/ui/const-generics/unused-type-param-suggestion.stderr @@ -1,12 +1,54 @@ -error[E0392]: parameter `N` is never used - --> $DIR/unused-type-param-suggestion.rs:3:16 +error[E0392]: type parameter `N` is never used + --> $DIR/unused-type-param-suggestion.rs:3:10 | -LL | struct Example; - | ^ unused parameter +LL | struct S; + | ^ unused type parameter | = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `N` to be a const parameter, use `const N: usize` instead + = help: if you intended `N` to be a const parameter, use `const N: /* Type */` instead -error: aborting due to 1 previous error +error[E0392]: type parameter `N` is never used + --> $DIR/unused-type-param-suggestion.rs:9:10 + | +LL | struct T; + | ^ unused type parameter + | + = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0091]: type parameter `N` is never used + --> $DIR/unused-type-param-suggestion.rs:13:8 + | +LL | type A = (); + | ^ unused type parameter + | + = help: consider removing `N` or referring to it in the body of the type alias + = help: if you intended `N` to be a const parameter, use `const N: /* Type */` instead + +error[E0091]: type parameter `N` is never used + --> $DIR/unused-type-param-suggestion.rs:19:8 + | +LL | type B = (); + | ^ unused type parameter + | + = help: consider removing `N` or referring to it in the body of the type alias + +error[E0091]: type parameter `N` is never used + --> $DIR/unused-type-param-suggestion.rs:22:8 + | +LL | type C = (); + | ^ unused type parameter + | + = help: consider removing `N` or referring to it in the body of the type alias + +error[E0091]: type parameter `N` is never used + --> $DIR/unused-type-param-suggestion.rs:25:8 + | +LL | type D = (); + | ^ unused type parameter + | + = help: consider removing `N` or referring to it in the body of the type alias + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0392`. +Some errors have detailed explanations: E0091, E0392. +For more information about an error, try `rustc --explain E0091`. diff --git a/tests/ui/consts/const-address-of-mut.rs b/tests/ui/consts/const-address-of-mut.rs index 3788088b810b9..5f0c76d628555 100644 --- a/tests/ui/consts/const-address-of-mut.rs +++ b/tests/ui/consts/const-address-of-mut.rs @@ -1,14 +1,14 @@ #![feature(raw_ref_op)] -const A: () = { let mut x = 2; &raw mut x; }; //~ mutable reference +const A: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer -static B: () = { let mut x = 2; &raw mut x; }; //~ mutable reference +static B: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer -static mut C: () = { let mut x = 2; &raw mut x; }; //~ mutable reference +static mut C: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer const fn foo() { let mut x = 0; - let y = &raw mut x; //~ mutable reference + let y = &raw mut x; //~ mutable pointer } fn main() {} diff --git a/tests/ui/consts/const-address-of-mut.stderr b/tests/ui/consts/const-address-of-mut.stderr index 2a69bb8be97d4..1b371fcee984b 100644 --- a/tests/ui/consts/const-address-of-mut.stderr +++ b/tests/ui/consts/const-address-of-mut.stderr @@ -1,4 +1,4 @@ -error[E0658]: raw mutable references are not allowed in constants +error[E0658]: raw mutable pointers are not allowed in constants --> $DIR/const-address-of-mut.rs:3:32 | LL | const A: () = { let mut x = 2; &raw mut x; }; @@ -8,7 +8,7 @@ LL | const A: () = { let mut x = 2; &raw mut x; }; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: raw mutable references are not allowed in statics +error[E0658]: raw mutable pointers are not allowed in statics --> $DIR/const-address-of-mut.rs:5:33 | LL | static B: () = { let mut x = 2; &raw mut x; }; @@ -18,7 +18,7 @@ LL | static B: () = { let mut x = 2; &raw mut x; }; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: raw mutable references are not allowed in statics +error[E0658]: raw mutable pointers are not allowed in statics --> $DIR/const-address-of-mut.rs:7:37 | LL | static mut C: () = { let mut x = 2; &raw mut x; }; @@ -28,7 +28,7 @@ LL | static mut C: () = { let mut x = 2; &raw mut x; }; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: raw mutable references are not allowed in constant functions +error[E0658]: raw mutable pointers are not allowed in constant functions --> $DIR/const-address-of-mut.rs:11:13 | LL | let y = &raw mut x; diff --git a/tests/ui/consts/const-block-item.rs b/tests/ui/consts/const-block-item.rs index cf0d4441d4a9b..a04f4db263bb2 100644 --- a/tests/ui/consts/const-block-item.rs +++ b/tests/ui/consts/const-block-item.rs @@ -2,7 +2,7 @@ #![allow(unused_imports)] mod foo { - pub trait Value { + pub trait Value { //~ WARN trait `Value` is never used fn value(&self) -> usize; } } diff --git a/tests/ui/consts/const-block-item.stderr b/tests/ui/consts/const-block-item.stderr new file mode 100644 index 0000000000000..04658742b56ce --- /dev/null +++ b/tests/ui/consts/const-block-item.stderr @@ -0,0 +1,10 @@ +warning: trait `Value` is never used + --> $DIR/const-block-item.rs:5:15 + | +LL | pub trait Value { + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr index b13df67b423bb..14bce10f78744 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/fn-call-in-non-const.rs:14:32 | LL | let _: [Option; 2] = [no_copy(); 2]; - | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar` + | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array diff --git a/tests/ui/consts/const-blocks/migrate-fail.stderr b/tests/ui/consts/const-blocks/migrate-fail.stderr index d1896f755d530..3887658f74835 100644 --- a/tests/ui/consts/const-blocks/migrate-fail.stderr +++ b/tests/ui/consts/const-blocks/migrate-fail.stderr @@ -2,10 +2,12 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/migrate-fail.rs:11:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar` + | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Bar` with `#[derive(Copy)]` | LL + #[derive(Copy)] @@ -16,10 +18,12 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/migrate-fail.rs:17:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar` + | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Bar` with `#[derive(Copy)]` | LL + #[derive(Copy)] diff --git a/tests/ui/consts/const-blocks/nll-fail.stderr b/tests/ui/consts/const-blocks/nll-fail.stderr index 807c964a51d6f..a2ea833f650e3 100644 --- a/tests/ui/consts/const-blocks/nll-fail.stderr +++ b/tests/ui/consts/const-blocks/nll-fail.stderr @@ -2,10 +2,12 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/nll-fail.rs:11:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar` + | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Bar` with `#[derive(Copy)]` | LL + #[derive(Copy)] @@ -16,10 +18,12 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/nll-fail.rs:17:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar` + | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Bar` with `#[derive(Copy)]` | LL + #[derive(Copy)] diff --git a/tests/ui/consts/const-blocks/trait-error.stderr b/tests/ui/consts/const-blocks/trait-error.stderr index 36249bf3f6d4e..b0b1378bb7de0 100644 --- a/tests/ui/consts/const-blocks/trait-error.stderr +++ b/tests/ui/consts/const-blocks/trait-error.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trait-error.rs:5:6 | LL | [Foo(String::new()); 4]; - | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`, which is required by `Foo: Copy` | note: required for `Foo` to implement `Copy` --> $DIR/trait-error.rs:1:10 diff --git a/tests/ui/consts/const-err-late.stderr b/tests/ui/consts/const-err-late.stderr index 35c3d000117ef..53badeafa35b6 100644 --- a/tests/ui/consts/const-err-late.stderr +++ b/tests/ui/consts/const-err-late.stderr @@ -30,6 +30,14 @@ LL | black_box((S::::FOO, S::::FOO)); | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +note: erroneous constant encountered + --> $DIR/const-err-late.rs:19:31 + | +LL | black_box((S::::FOO, S::::FOO)); + | ^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr index c748af608d1e6..2fcb3d41dd927 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -7,7 +7,6 @@ LL | const X: i32 = 1 / 0; query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `X` #1 [eval_to_const_value_raw] simplifying constant for the type system `X` -#2 [eval_to_const_value_raw] simplifying constant for the type system `X` -#3 [lint_mod] linting top-level module -#4 [analysis] running analysis passes on this crate +#2 [lint_mod] linting top-level module +#3 [analysis] running analysis passes on this crate end of query stack diff --git a/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs new file mode 100644 index 0000000000000..3f1f208459d17 --- /dev/null +++ b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs @@ -0,0 +1,5 @@ +// Regression test for issue #120615. + +fn main() { + [(); loop {}].field; //~ ERROR constant evaluation is taking a long time +} diff --git a/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr new file mode 100644 index 0000000000000..9d62bbc2187f7 --- /dev/null +++ b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr @@ -0,0 +1,17 @@ +error: constant evaluation is taking a long time + --> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10 + | +LL | [(); loop {}].field; + | ^^^^^^^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10 + | +LL | [(); loop {}].field; + | ^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index 0a8fc7bcaac55..6bc5faac532cc 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -5,6 +5,7 @@ use std::intrinsics; const FOO: &i32 = foo(); +const FOO_RAW: *const i32 = foo(); const fn foo() -> &'static i32 { let t = unsafe { @@ -15,5 +16,6 @@ const fn foo() -> &'static i32 { unsafe { &*t } } fn main() { - assert_eq!(*FOO, 20) + assert_eq!(*FOO, 20); + assert_eq!(unsafe { *FOO_RAW }, 20); } diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs deleted file mode 100644 index 9ae906bbb7397..0000000000000 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(core_intrinsics)] -#![feature(const_heap)] -#![feature(const_mut_refs)] -use std::intrinsics; - -const FOO: *const i32 = foo(); -//~^ ERROR unsupported untyped pointer in constant - -const fn foo() -> &'static i32 { - let t = unsafe { - let i = intrinsics::const_allocate(4, 4) as *mut i32; - *i = 20; - i - }; - unsafe { &*t } -} -fn main() { -} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr deleted file mode 100644 index dfaecfbcd8f1e..0000000000000 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unsupported untyped pointer in constant - --> $DIR/alloc_intrinsic_nontransient_fail.rs:6:1 - | -LL | const FOO: *const i32 = foo(); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: memory only reachable via raw pointers is not supported - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs index 1354b3c33b31d..105e8e38d84eb 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -4,6 +4,6 @@ use std::intrinsics; const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; -//~^ error: unsupported untyped pointer in constant +//~^ error: mutable pointer in final value of constant fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr index 3903ccd6ade7b..bd82e6781be1e 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -1,10 +1,8 @@ -error: unsupported untyped pointer in constant +error: encountered mutable pointer in final value of constant --> $DIR/alloc_intrinsic_untyped.rs:6:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ - | - = note: memory only reachable via raw pointers is not supported error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs index a717a5f829217..6ede6f5339ca4 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -5,7 +5,7 @@ use std::intrinsics; const _X: &'static u8 = unsafe { - //~^ error: dangling pointer in final constant + //~^ error: dangling pointer in final value of constant let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 4); &*ptr diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index 5f4630f6f4bc8..59f5f79a95f38 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -1,4 +1,4 @@ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of constant --> $DIR/dealloc_intrinsic_dangling.rs:7:1 | LL | const _X: &'static u8 = unsafe { diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 3341f3c78e0d6..47105de453cb1 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -1,4 +1,4 @@ -#![feature(const_mut_refs)] +#![feature(const_mut_refs, const_intrinsic_copy)] const MISALIGNED_LOAD: () = unsafe { diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr index 8eee392d15cd5..40fc4a876e9e5 100644 --- a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr @@ -40,7 +40,6 @@ help: the constant being evaluated | LL | const Y: u32 = simple_loop(35); | ^^^^^^^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: constant evaluation is taking a long time --> $DIR/ctfe-simple-loop.rs:9:5 diff --git a/tests/ui/consts/const-fn-in-vec.stderr b/tests/ui/consts/const-fn-in-vec.stderr index 4593034bfaea3..12098e8199cd7 100644 --- a/tests/ui/consts/const-fn-in-vec.stderr +++ b/tests/ui/consts/const-fn-in-vec.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:1:47 | LL | static _MAYBE_STRINGS: [Option; 5] = [None; 5]; - | ^^^^ the trait `Copy` is not implemented for `String` + | ^^^^ the trait `Copy` is not implemented for `String`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array @@ -31,7 +31,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:9:48 | LL | let _maybe_strings: [Option; 5] = [None; 5]; - | ^^^^ the trait `Copy` is not implemented for `String` + | ^^^^ the trait `Copy` is not implemented for `String`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs index a7d329f125be4..93197d5bce494 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -44,6 +44,21 @@ static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); // the enclosing scope rule. const BAR: NotAMutex<&i32> = NotAMutex(UnsafeCell::new(&42)); +struct SyncPtr { x : *const T } +unsafe impl Sync for SyncPtr {} + +// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. +// (This relies on `SyncPtr` being a curly brace struct.) +// However, we intern the inner memory as read-only, so this must be rejected. +static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; +//~^ ERROR mutable references are not allowed +static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; +//~^ ERROR mutable references are not allowed +const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; +//~^ ERROR mutable references are not allowed +const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; +//~^ ERROR mutable references are not allowed + fn main() { println!("{}", unsafe { *A }); unsafe { *B = 4 } // Bad news diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index 78c58b5ab092b..59e6aa4011c23 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -54,7 +54,31 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | | creates a temporary value which is freed while still in use | using this value as a static requires that borrow lasts for `'static` -error: aborting due to 6 previous errors +error[E0764]: mutable references are not allowed in the final value of statics + --> $DIR/mut_ref_in_final.rs:53:53 + | +LL | static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ + +error[E0764]: mutable references are not allowed in the final value of statics + --> $DIR/mut_ref_in_final.rs:55:54 + | +LL | static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ + +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/mut_ref_in_final.rs:57:52 + | +LL | const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ + +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/mut_ref_in_final.rs:59:53 + | +LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ + +error: aborting due to 10 previous errors Some errors have detailed explanations: E0716, E0764. For more information about an error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr index 33d4fec70166c..87420a0375147 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr @@ -1,16 +1,16 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:17:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:15:1 | LL | const A: Option<&mut i32> = helper(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered mutable reference in a `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered mutable reference in a `const` or `static` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 2a 00 00 00 │ *... } -error: encountered dangling pointer in final constant - --> $DIR/mut_ref_in_final_dynamic_check.rs:24:1 +error: encountered dangling pointer in final value of constant + --> $DIR/mut_ref_in_final_dynamic_check.rs:22:1 | LL | const B: Option<&mut i32> = helper2(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr index 9eb2675856f3d..fc68207512c09 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr @@ -1,16 +1,16 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:17:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:15:1 | LL | const A: Option<&mut i32> = helper(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered mutable reference in a `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered mutable reference in a `const` or `static` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 2a 00 00 00 00 00 00 00 │ *....... } -error: encountered dangling pointer in final constant - --> $DIR/mut_ref_in_final_dynamic_check.rs:24:1 +error: encountered dangling pointer in final value of constant + --> $DIR/mut_ref_in_final_dynamic_check.rs:22:1 | LL | const B: Option<&mut i32> = helper2(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index 22e7a74e5fbab..455b557b97c4e 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -12,8 +12,6 @@ const fn helper() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (integer as pointer), who doesn't love tests like this. Some(&mut *(42 as *mut i32)) } } -// The error is an evaluation error and not a validation error, so the error is reported -// directly at the site where it occurs. const A: Option<&mut i32> = helper(); //~ ERROR it is undefined behavior to use this value //~^ encountered mutable reference in a `const` @@ -21,6 +19,6 @@ const fn helper2() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (dangling pointer), who doesn't love tests like this. Some(&mut *(&mut 42 as *mut i32)) } } -const B: Option<&mut i32> = helper2(); //~ ERROR encountered dangling pointer in final constant +const B: Option<&mut i32> = helper2(); //~ ERROR encountered dangling pointer in final value of constant fn main() {} diff --git a/tests/ui/consts/const-points-to-static.32bit.stderr b/tests/ui/consts/const-points-to-static.32bit.stderr deleted file mode 100644 index 73fbf5e1837e2..0000000000000 --- a/tests/ui/consts/const-points-to-static.32bit.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/const-points-to-static.rs:6:1 - | -LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ - } - -warning: skipping const checks - | -help: skipping check that does not even have a feature gate - --> $DIR/const-points-to-static.rs:6:20 - | -LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^ - -error: aborting due to 1 previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-points-to-static.64bit.stderr b/tests/ui/consts/const-points-to-static.64bit.stderr deleted file mode 100644 index 42088bbb2c4a9..0000000000000 --- a/tests/ui/consts/const-points-to-static.64bit.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/const-points-to-static.rs:6:1 - | -LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ - } - -warning: skipping const checks - | -help: skipping check that does not even have a feature gate - --> $DIR/const-points-to-static.rs:6:20 - | -LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^ - -error: aborting due to 1 previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-points-to-static.rs b/tests/ui/consts/const-points-to-static.rs deleted file mode 100644 index ca825a1f5ed65..0000000000000 --- a/tests/ui/consts/const-points-to-static.rs +++ /dev/null @@ -1,13 +0,0 @@ -// compile-flags: -Zunleash-the-miri-inside-of-you -// stderr-per-bitwidth - -#![allow(dead_code)] - -const TEST: &u8 = &MY_STATIC; -//~^ ERROR it is undefined behavior to use this value -//~| encountered a reference pointing to a static variable - -static MY_STATIC: u8 = 4; - -fn main() { -} diff --git a/tests/ui/consts/const-size_of-cycle.stderr b/tests/ui/consts/const-size_of-cycle.stderr index a5679400c2f0e..cd0ea55642545 100644 --- a/tests/ui/consts/const-size_of-cycle.stderr +++ b/tests/ui/consts/const-size_of-cycle.stderr @@ -7,11 +7,6 @@ LL | bytes: [u8; std::mem::size_of::()] note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | -LL | bytes: [u8; std::mem::size_of::()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... - --> $DIR/const-size_of-cycle.rs:4:17 - | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs index 1f56f581c0270..69b4e75c62236 100644 --- a/tests/ui/consts/const_in_pattern/accept_structural.rs +++ b/tests/ui/consts/const_in_pattern/accept_structural.rs @@ -63,4 +63,18 @@ fn main() { const ADDR_OF: &OND = &None; match &None { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + + // These ones are more subtle: the final value is fine, but statically analyzing the expression + // that computes the value would likely (incorrectly) have us conclude that this may match on + // values that do not have structural equality. + const INDEX: Option = [None, Some(NoDerive(10))][0]; + match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + + const fn build() -> Option { None } + const CALL: Option = build(); + match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; + + impl NoDerive { const fn none() -> Option { None } } + const METHOD_CALL: Option = NoDerive::none(); + match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; } diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs index ab297f54dff3e..69f5e66f5af70 100644 --- a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -11,14 +11,14 @@ fn main() { let _ = Defaulted; match None { consts::SOME => panic!(), - //~^ must be annotated with `#[derive(PartialEq, Eq)]` + //~^ must be annotated with `#[derive(PartialEq)]` _ => {} } match None { ::SOME => panic!(), - //~^ must be annotated with `#[derive(PartialEq, Eq)]` + //~^ must be annotated with `#[derive(PartialEq)]` _ => {} } diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr index 2f6786999ed4d..067f2b6e6747a 100644 --- a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -1,20 +1,20 @@ -error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq)]` --> $DIR/cross-crate-fail.rs:13:9 | LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq)]` --> $DIR/cross-crate-fail.rs:20:9 | LL | ::SOME => panic!(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs index a38731ceb8a86..ac89b7925ffec 100644 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs +++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs @@ -12,6 +12,7 @@ impl PartialEq for CustomEq { } #[derive(PartialEq, Eq)] +#[allow(unused)] enum Foo { Bar, Baz, @@ -21,7 +22,7 @@ enum Foo { const BAR_BAZ: Foo = if 42 == 42 { Foo::Bar } else { - Foo::Baz + Foo::Qux(CustomEq) // dead arm }; fn main() { diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs deleted file mode 100644 index 41de5e7b4fe2e..0000000000000 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs +++ /dev/null @@ -1,38 +0,0 @@ -// check-pass - -struct CustomEq; - -impl Eq for CustomEq {} -impl PartialEq for CustomEq { - fn eq(&self, _: &Self) -> bool { - false - } -} - -#[derive(PartialEq, Eq)] -enum Foo { - Bar, - Baz, - Qux(CustomEq), -} - -// We know that `BAR_BAZ` will always be `Foo::Bar` and thus eligible for structural matching, but -// dataflow will be more conservative. -const BAR_BAZ: Foo = if 42 == 42 { - Foo::Bar -} else { - Foo::Qux(CustomEq) -}; - -fn main() { - match Foo::Qux(CustomEq) { - BAR_BAZ => panic!(), - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details - //~| WARN this was previously accepted - //~| NOTE see issue #73448 - //~| NOTE `#[warn(nontrivial_structural_match)]` on by default - _ => {} - } -} diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr deleted file mode 100644 index 3f19c67d223ef..0000000000000 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/custom-eq-branch-warn.rs:29:9 - | -LL | BAR_BAZ => panic!(), - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `#[warn(nontrivial_structural_match)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.rs b/tests/ui/consts/const_in_pattern/incomplete-slice.rs index e1ccda71d40ea..4984acaaf7985 100644 --- a/tests/ui/consts/const_in_pattern/incomplete-slice.rs +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.rs @@ -7,9 +7,7 @@ const E_SL: &[E] = &[E::A]; fn main() { match &[][..] { - //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004] + //~^ ERROR non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered [E0004] E_SL => {} - //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN this was previously accepted by the compiler but is being phased out } } diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr index 4ecfb3f1c5a48..bd61f43727be9 100644 --- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr @@ -1,28 +1,16 @@ -warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/incomplete-slice.rs:11:9 - | -LL | E_SL => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `#[warn(indirect_structural_match)]` on by default - -error[E0004]: non-exhaustive patterns: `&_` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/incomplete-slice.rs:9:11 | LL | match &[][..] { - | ^^^^^^^ pattern `&_` not covered + | ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered | = note: the matched value is of type `&[E]` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ E_SL => {}, -LL + &_ => todo!() +LL + &[] | &[_, _, ..] => todo!() | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr index 1546f23908c6f..bc1015c173426 100644 --- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr +++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr @@ -5,7 +5,7 @@ LL | C => {} | ^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 | @@ -19,7 +19,7 @@ LL | C_INNER => {} | ^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9 @@ -28,7 +28,7 @@ LL | D => {} | ^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9 @@ -37,7 +37,67 @@ LL | STR => {} | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 error: aborting due to 4 previous errors +Future incompatibility report: Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:10:9 + | +LL | C => {} + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:18:9 + | +LL | C_INNER => {} + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9 + | +LL | D => {} + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9 + | +LL | STR => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr index 441aeecbc6d95..f5931f0cad08b 100644 --- a/tests/ui/consts/const_in_pattern/issue-44333.stderr +++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr @@ -5,7 +5,7 @@ LL | FOO => println!("foo"), | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-44333.rs:3:9 | @@ -19,7 +19,37 @@ LL | BAR => println!("bar"), | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/const_in_pattern/issue-73431.stderr b/tests/ui/consts/const_in_pattern/issue-73431.stderr deleted file mode 100644 index c82dea4aa50df..0000000000000 --- a/tests/ui/consts/const_in_pattern/issue-73431.stderr +++ /dev/null @@ -1 +0,0 @@ -WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448. diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs deleted file mode 100644 index 88b5d68cb6017..0000000000000 --- a/tests/ui/consts/const_in_pattern/issue-78057.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![deny(unreachable_patterns)] - -#[derive(PartialEq)] -struct Opaque(i32); - -impl Eq for Opaque {} - -const FOO: Opaque = Opaque(42); - -fn main() { - match FOO { - FOO => {}, - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - _ => {} - } -} diff --git a/tests/ui/consts/const_in_pattern/issue-78057.stderr b/tests/ui/consts/const_in_pattern/issue-78057.stderr deleted file mode 100644 index 719295c96a5bd..0000000000000 --- a/tests/ui/consts/const_in_pattern/issue-78057.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: to use a constant of type `Opaque` in a pattern, `Opaque` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/issue-78057.rs:12:9 - | -LL | FOO => {}, - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs index fc80d51c72daa..141d87d9b7038 100644 --- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs +++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs @@ -19,7 +19,7 @@ const BAR_BAZ: Foo = if 42 == 42 { fn main() { match Foo::Qux(NoEq) { BAR_BAZ => panic!(), - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` _ => {} } } diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr index 1979c297ae44e..b29f959de972d 100644 --- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr +++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]` --> $DIR/no-eq-branch-fail.rs:21:9 | LL | BAR_BAZ => panic!(), | ^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs b/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs index 436a2d0de74b1..515c79d9457b0 100644 --- a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs +++ b/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs @@ -1,6 +1,4 @@ // run-pass -// Eventually this will be rejected (when the future-compat lints are turned into hard errors), and -// then this test can be removed. But meanwhile we should ensure that this works and does not ICE. struct NoDerive(#[allow(dead_code)] i32); #[derive(PartialEq)] @@ -11,8 +9,6 @@ const WRAP_UNSAFE_EMBEDDED: &&WrapEmbedded = &&WrapEmbedded(std::ptr::null()); fn main() { let b = match WRAP_UNSAFE_EMBEDDED { WRAP_UNSAFE_EMBEDDED => true, - //~^ WARN: must be annotated with `#[derive(PartialEq, Eq)]` - //~| previously accepted _ => false, }; assert!(b); diff --git a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr b/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr deleted file mode 100644 index c186d349e721c..0000000000000 --- a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: to use a constant of type `WrapEmbedded` in a pattern, `WrapEmbedded` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/null-raw-ptr-issue-119270.rs:13:9 - | -LL | WRAP_UNSAFE_EMBEDDED => true, - | ^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `#[warn(indirect_structural_match)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs index a8216901c027f..86d971044fe1c 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs @@ -26,7 +26,7 @@ fn main() { match None { NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` _ => panic!("whoops"), } } diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr index d3628a8decb16..88b82d5004b5c 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_partial_eq.rs:28:9 | LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), | ^^^^^^^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs index df772740ab122..71d4138104db1 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -40,65 +40,65 @@ fn main() { const ENUM: Derive = Derive::Some(NoDerive); match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const FIELD: OND = TrivialEq(Some(NoDerive)).0; match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const NO_DERIVE_SOME: OND = Some(NoDerive); const INDIRECT: OND = NO_DERIVE_SOME; match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const TUPLE: (OND, OND) = (None, Some(NoDerive)); match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND); match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const ARRAY: [OND; 2] = [None, Some(NoDerive)]; match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const REPEAT: [OND; 2] = [Some(NoDerive); 2]; match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details trait Trait: Sized { const ASSOC: Option; } impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const BLOCK: OND = { NoDerive; Some(NoDerive) }; match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details const ADDR_OF: &OND = &Some(NoDerive); match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| NOTE the traits must be derived - //~| NOTE StructuralEq.html for details + //~| NOTE StructuralPartialEq.html for details //~| WARN previously accepted by the compiler but is being phased out - //~| NOTE for more information, see issue #62411 + //~| NOTE for more information, see } diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index 72bb0aeafa466..2c7aaf89aa787 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -1,94 +1,94 @@ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:42:36 | LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; | ^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:48:28 | LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; | ^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:55:27 | LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; | ^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:61:36 | LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; | ^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:67:28 | LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:73:36 | LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; | ^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:79:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:86:28 | LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:92:28 | LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; | ^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/reject_non_structural.rs:98:29 | LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; | ^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here --> $DIR/reject_non_structural.rs:14:9 | @@ -97,3 +97,20 @@ LL | #![warn(indirect_structural_match)] error: aborting due to 9 previous errors; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/reject_non_structural.rs:98:29 + | +LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/reject_non_structural.rs:14:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs deleted file mode 100644 index d23d85335f898..0000000000000 --- a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs +++ /dev/null @@ -1,41 +0,0 @@ -// run-pass - -// This test is checking our logic for structural match checking by enumerating -// the different kinds of const expressions. This test is collecting cases where -// we have accepted the const expression as a pattern in the past but we want -// to begin warning the user that a future version of Rust may start rejecting -// such const expressions. - -// The specific corner cases we are exploring here are instances where the -// const-evaluator computes a value that *does* meet the conditions for -// structural-match, but the const expression itself has abstractions (like -// calls to const functions) that may fit better with a type-based analysis -// rather than a commitment to a specific value. - -#![warn(indirect_structural_match)] - -#[derive(Copy, Clone, Debug)] -struct NoDerive(#[allow(dead_code)] u32); - -// This impl makes `NoDerive` irreflexive. -impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } -impl Eq for NoDerive { } - -fn main() { - const INDEX: Option = [None, Some(NoDerive(10))][0]; - match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN this was previously accepted - - const fn build() -> Option { None } - const CALL: Option = build(); - match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN this was previously accepted - - impl NoDerive { const fn none() -> Option { None } } - const METHOD_CALL: Option = NoDerive::none(); - match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN this was previously accepted -} diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr deleted file mode 100644 index 8c01d2f65ec90..0000000000000 --- a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/warn_corner_cases.rs:26:47 - | -LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `#[warn(nontrivial_structural_match)]` on by default - -warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/warn_corner_cases.rs:32:47 - | -LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - -warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/warn_corner_cases.rs:38:47 - | -LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; - | ^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - -warning: 3 warnings emitted - diff --git a/tests/ui/consts/dangling-alloc-id-ice.rs b/tests/ui/consts/dangling-alloc-id-ice.rs index d591bfc731ce4..d9f458f3770a8 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.rs +++ b/tests/ui/consts/dangling-alloc-id-ice.rs @@ -6,7 +6,7 @@ union Foo<'a> { } const FOO: &() = { -//~^ ERROR encountered dangling pointer in final constant +//~^ ERROR encountered dangling pointer in final value of constant let y = (); unsafe { Foo { y: &y }.long_live_the_unit } }; diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr index e14204c09e54b..8322b18d692dc 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.stderr +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -1,4 +1,4 @@ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of constant --> $DIR/dangling-alloc-id-ice.rs:8:1 | LL | const FOO: &() = { diff --git a/tests/ui/consts/dangling_raw_ptr.rs b/tests/ui/consts/dangling_raw_ptr.rs index ddd1fb1ba76e1..0ab3643f1216b 100644 --- a/tests/ui/consts/dangling_raw_ptr.rs +++ b/tests/ui/consts/dangling_raw_ptr.rs @@ -1,4 +1,4 @@ -const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final constant +const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final value of constant let x = 42; &x }; diff --git a/tests/ui/consts/dangling_raw_ptr.stderr b/tests/ui/consts/dangling_raw_ptr.stderr index 5a428355034aa..28a58ae7be292 100644 --- a/tests/ui/consts/dangling_raw_ptr.stderr +++ b/tests/ui/consts/dangling_raw_ptr.stderr @@ -1,4 +1,4 @@ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of constant --> $DIR/dangling_raw_ptr.rs:1:1 | LL | const FOO: *const u32 = { diff --git a/tests/ui/consts/invalid-union.32bit.stderr b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr similarity index 82% rename from tests/ui/consts/invalid-union.32bit.stderr rename to tests/ui/consts/interior-mut-const-via-union.32bit.stderr index 177e4f03e837c..e9e9f1a4545d9 100644 --- a/tests/ui/consts/invalid-union.32bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr @@ -1,8 +1,8 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:35:1 + --> $DIR/interior-mut-const-via-union.rs:35:1 | LL | fn main() { - | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -10,13 +10,13 @@ LL | fn main() { } note: erroneous constant encountered - --> $DIR/invalid-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ note: erroneous constant encountered - --> $DIR/invalid-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ diff --git a/tests/ui/consts/invalid-union.64bit.stderr b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr similarity index 82% rename from tests/ui/consts/invalid-union.64bit.stderr rename to tests/ui/consts/interior-mut-const-via-union.64bit.stderr index 09c648c3cda36..9cc98975ca9b5 100644 --- a/tests/ui/consts/invalid-union.64bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr @@ -1,8 +1,8 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:35:1 + --> $DIR/interior-mut-const-via-union.rs:35:1 | LL | fn main() { - | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -10,13 +10,13 @@ LL | fn main() { } note: erroneous constant encountered - --> $DIR/invalid-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ note: erroneous constant encountered - --> $DIR/invalid-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ diff --git a/tests/ui/consts/invalid-union.rs b/tests/ui/consts/interior-mut-const-via-union.rs similarity index 100% rename from tests/ui/consts/invalid-union.rs rename to tests/ui/consts/interior-mut-const-via-union.rs diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.rs b/tests/ui/consts/invalid-inline-const-in-match-arm.rs index 4d2d8fb1303ce..0654fd82fbc59 100644 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.rs +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.rs @@ -1,4 +1,3 @@ -#![allow(incomplete_features)] #![feature(inline_const_pat)] fn main() { diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr index db7db4b613181..a88c16158f324 100644 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const closure in constants - --> $DIR/invalid-inline-const-in-match-arm.rs:6:17 + --> $DIR/invalid-inline-const-in-match-arm.rs:5:17 | LL | const { (|| {})() } => {} | ^^^^^^^^^ diff --git a/tests/ui/consts/is_val_statically_known.rs b/tests/ui/consts/is_val_statically_known.rs new file mode 100644 index 0000000000000..b0565842eb4e2 --- /dev/null +++ b/tests/ui/consts/is_val_statically_known.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(core_intrinsics)] +#![feature(is_val_statically_known)] + +use std::intrinsics::is_val_statically_known; + +const CONST_TEST: bool = unsafe { is_val_statically_known(0) }; + +fn main() { + if CONST_TEST { + unreachable!("currently expected to return false during const eval"); + // but note that this is not a guarantee! + } +} diff --git a/tests/ui/consts/issue-104609.rs b/tests/ui/consts/issue-104609.rs index 01fd1c48cf803..9ee83b409c16f 100644 --- a/tests/ui/consts/issue-104609.rs +++ b/tests/ui/consts/issue-104609.rs @@ -5,6 +5,7 @@ fn foo() { unsafe fn bar() { std::mem::transmute::<_, *mut _>(1_u8); + //~^ ERROR: type annotations needed } fn main() {} diff --git a/tests/ui/consts/issue-104609.stderr b/tests/ui/consts/issue-104609.stderr index 8d0526978ed9e..fe84d83725fd2 100644 --- a/tests/ui/consts/issue-104609.stderr +++ b/tests/ui/consts/issue-104609.stderr @@ -4,6 +4,13 @@ error[E0425]: cannot find value `oops` in this scope LL | oops; | ^^^^ not found in this scope -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/issue-104609.rs:7:5 + | +LL | std::mem::transmute::<_, *mut _>(1_u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Dst` declared on the function `transmute` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0282, E0425. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr index 4f2d92ba3cde0..de70a457f16f2 100644 --- a/tests/ui/consts/issue-36163.stderr +++ b/tests/ui/consts/issue-36163.stderr @@ -20,11 +20,17 @@ note: ...which requires const-evaluating + checking `A`... LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^ = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle -note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}` - --> $DIR/issue-36163.rs:4:9 +note: cycle used when collecting item types in top-level module + --> $DIR/issue-36163.rs:1:1 | -LL | B = A, - | ^ +LL | / const A: isize = Foo::B as isize; +LL | | +LL | | enum Foo { +LL | | B = A, +LL | | } +LL | | +LL | | fn main() {} + | |____________^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-44415.stderr b/tests/ui/consts/issue-44415.stderr index adb5747c42408..641945fce9fd4 100644 --- a/tests/ui/consts/issue-44415.stderr +++ b/tests/ui/consts/issue-44415.stderr @@ -7,11 +7,6 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::() }], note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/issue-44415.rs:6:17 | -LL | bytes: [u8; unsafe { intrinsics::size_of::() }], - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... - --> $DIR/issue-44415.rs:6:17 - | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr index 03c47030c0e3f..b8c983eb7b81c 100644 --- a/tests/ui/consts/issue-54954.stderr +++ b/tests/ui/consts/issue-54954.stderr @@ -11,7 +11,7 @@ error[E0790]: cannot call associated function on trait without specifying the co --> $DIR/issue-54954.rs:1:24 | LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait ... LL | / const fn const_val() -> usize { LL | | diff --git a/tests/ui/consts/issue-65348.rs b/tests/ui/consts/issue-65348.rs index 5eafa831d6317..01bf2a3fa4287 100644 --- a/tests/ui/consts/issue-65348.rs +++ b/tests/ui/consts/issue-65348.rs @@ -8,15 +8,16 @@ impl Generic { const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, [])); } -pub const fn array() -> &'static T { +pub const fn array() -> &'static T { + #[allow(unconditional_panic)] &Generic::::ARRAY[0] } -pub const fn newtype_array() -> &'static T { +pub const fn newtype_array() -> &'static T { &Generic::::NEWTYPE_ARRAY.0[0] } -pub const fn array_field() -> &'static T { +pub const fn array_field() -> &'static T { &(Generic::::ARRAY_FIELD.0).1[0] } diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr new file mode 100644 index 0000000000000..d5c5f76b90a01 --- /dev/null +++ b/tests/ui/consts/issue-89088.stderr @@ -0,0 +1,17 @@ +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `Cow<'_, str>` in a pattern, `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]` + --> $DIR/issue-89088.rs:19:9 + | +LL | FOO => todo!(), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/issue-89088.rs:5:10 + | +LL | #![allow(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs new file mode 100644 index 0000000000000..7da6b7ca285c1 --- /dev/null +++ b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs @@ -0,0 +1,10 @@ +// check-pass +#![feature(never_type)] +#[derive(Copy, Clone)] +pub enum E { A(!), } +pub union U { u: (), e: E, } +pub const C: () = { + let E::A(ref a) = unsafe { &(&U { u: () }).e}; +}; + +fn main() {} diff --git a/tests/ui/consts/match_ice.rs b/tests/ui/consts/match_ice.rs index 632335c841e3a..ed1fd78809b12 100644 --- a/tests/ui/consts/match_ice.rs +++ b/tests/ui/consts/match_ice.rs @@ -9,7 +9,7 @@ fn main() { const C: &S = &S; match C { C => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` } const K: &T = &T; match K { diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr index fb5cbe0ed8980..472c24a5cbe31 100644 --- a/tests/ui/consts/match_ice.stderr +++ b/tests/ui/consts/match_ice.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq)]` --> $DIR/match_ice.rs:11:9 | LL | C => {} | ^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/consts/min_const_fn/address_of.rs b/tests/ui/consts/min_const_fn/address_of.rs index 40d1882d7d2ad..aa75423ca4d64 100644 --- a/tests/ui/consts/min_const_fn/address_of.rs +++ b/tests/ui/consts/min_const_fn/address_of.rs @@ -2,7 +2,7 @@ const fn mutable_address_of_in_const() { let mut a = 0; - let b = &raw mut a; //~ ERROR mutable reference + let b = &raw mut a; //~ ERROR mutable pointer } struct X; @@ -10,7 +10,7 @@ struct X; impl X { const fn inherent_mutable_address_of_in_const() { let mut a = 0; - let b = &raw mut a; //~ ERROR mutable reference + let b = &raw mut a; //~ ERROR mutable pointer } } diff --git a/tests/ui/consts/min_const_fn/address_of.stderr b/tests/ui/consts/min_const_fn/address_of.stderr index 4c23ba6cd5190..143760c0943d2 100644 --- a/tests/ui/consts/min_const_fn/address_of.stderr +++ b/tests/ui/consts/min_const_fn/address_of.stderr @@ -1,4 +1,4 @@ -error[E0658]: raw mutable references are not allowed in constant functions +error[E0658]: raw mutable pointers are not allowed in constant functions --> $DIR/address_of.rs:5:13 | LL | let b = &raw mut a; @@ -8,7 +8,7 @@ LL | let b = &raw mut a; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: raw mutable references are not allowed in constant functions +error[E0658]: raw mutable pointers are not allowed in constant functions --> $DIR/address_of.rs:13:17 | LL | let b = &raw mut a; diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr index ab33b0c00c907..5fe8e250df912 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr @@ -38,6 +38,17 @@ LL | const READ_IMMUT: &usize = { ╾ALLOC1╼ │ ╾──╼ } +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static.rs:34:1 + | +LL | const REF_IMMUT: &u8 = &MY_STATIC; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC2╼ │ ╾──╼ + } + warning: skipping const checks | help: skipping check that does not even have a feature gate @@ -75,7 +86,12 @@ help: skipping check that does not even have a feature gate | LL | &FOO | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:34:25 + | +LL | const REF_IMMUT: &u8 = &MY_STATIC; + | ^^^^^^^^^ -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr index f1f58d9ca6d6f..a80b07056a30f 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr @@ -38,6 +38,17 @@ LL | const READ_IMMUT: &usize = { ╾ALLOC1╼ │ ╾──────╼ } +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static.rs:34:1 + | +LL | const REF_IMMUT: &u8 = &MY_STATIC; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC2╼ │ ╾──────╼ + } + warning: skipping const checks | help: skipping check that does not even have a feature gate @@ -75,7 +86,12 @@ help: skipping check that does not even have a feature gate | LL | &FOO | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:34:25 + | +LL | const REF_IMMUT: &u8 = &MY_STATIC; + | ^^^^^^^^^ -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs index 7ed5a48d996c6..df2563d8d7f2d 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -30,4 +30,9 @@ const READ_IMMUT: &usize = { //~ ERROR it is undefined behavior to use this valu &FOO }; +static MY_STATIC: u8 = 4; +const REF_IMMUT: &u8 = &MY_STATIC; +//~^ ERROR it is undefined behavior to use this value +//~| encountered a reference pointing to a static variable + fn main() {} diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index c9da91a959775..2df80020fdc91 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -1,54 +1,199 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:15:1 +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:17:1 | LL | const MUH: Meh = Meh { - | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:27:1 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:32:1 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC0╼ │ ╾──╼ } +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:35:1 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ + error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:25:1 + --> $DIR/mutable_references_err.rs:40:1 | -LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in a `const` +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC1╼ ╾ALLOC2╼ │ ╾──╼╾──╼ + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC1╼ │ ╾──╼ } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:29:1 + --> $DIR/mutable_references_err.rs:47:1 | -LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` +LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾ALLOC3╼ │ ╾──╼ + ╾ALLOC2╼ │ ╾──╼ } +error[E0080]: evaluation of constant value failed + --> $DIR/mutable_references_err.rs:51:43 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^^^ constant accesses static + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:55:1 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:57:1 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:59:1 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:69:1 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:71:1 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:73:1 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:16:8 + --> $DIR/mutable_references_err.rs:18:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:25:27 + --> $DIR/mutable_references_err.rs:27:27 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:29:25 + --> $DIR/mutable_references_err.rs:32:40 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:32:40 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:32:35 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:35:25 | LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references_err.rs:40:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references_err.rs:40:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:40:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:47:44 + | +LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:47:44 + | +LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:50:36 + | +LL | static mut MUTABLE_REF: &mut i32 = &mut 42; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:51:45 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:51:45 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:55:45 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:57:46 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:59:47 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:69:51 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:71:50 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:73:51 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 13 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index 71be616b7ed73..3ff6811ea61fb 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -1,54 +1,199 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:15:1 +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:17:1 | LL | const MUH: Meh = Meh { - | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:27:1 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:32:1 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC0╼ │ ╾──────╼ } +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:35:1 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ + error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:25:1 + --> $DIR/mutable_references_err.rs:40:1 | -LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in a `const` +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC1╼ ╾ALLOC2╼ │ ╾──────╼╾──────╼ + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC1╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:29:1 + --> $DIR/mutable_references_err.rs:47:1 | -LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` +LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾ALLOC3╼ │ ╾──────╼ + ╾ALLOC2╼ │ ╾──────╼ } +error[E0080]: evaluation of constant value failed + --> $DIR/mutable_references_err.rs:51:43 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^^^ constant accesses static + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:55:1 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:57:1 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:59:1 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:69:1 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:71:1 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references_err.rs:73:1 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:16:8 + --> $DIR/mutable_references_err.rs:18:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:25:27 + --> $DIR/mutable_references_err.rs:27:27 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:29:25 + --> $DIR/mutable_references_err.rs:32:40 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:32:40 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:32:35 + | +LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; + | ^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:35:25 | LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references_err.rs:40:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references_err.rs:40:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:40:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:47:44 + | +LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:47:44 + | +LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:50:36 + | +LL | static mut MUTABLE_REF: &mut i32 = &mut 42; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:51:45 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:51:45 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:55:45 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:57:46 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:59:47 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:69:51 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:71:50 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:73:51 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 13 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs index 6399b122bb1fb..83a460dadd0ef 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.rs @@ -1,6 +1,8 @@ // stderr-per-bitwidth // compile-flags: -Zunleash-the-miri-inside-of-you +#![allow(invalid_reference_casting, static_mut_ref)] +use std::sync::atomic::*; use std::cell::UnsafeCell; // this test ensures that our mutability story is sound @@ -12,7 +14,7 @@ unsafe impl Sync for Meh {} // the following will never be ok! no interior mut behind consts, because // all allocs interned here will be marked immutable. -const MUH: Meh = Meh { //~ ERROR: it is undefined behavior to use this value +const MUH: Meh = Meh { //~ ERROR: mutable pointer in final value x: &UnsafeCell::new(42), }; @@ -23,11 +25,53 @@ unsafe impl Sync for Synced {} // Make sure we also catch this behind a type-erased `dyn Trait` reference. const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: mutable pointer in final value -// Make sure we also catch mutable references. +// Make sure we also catch mutable references in values that shouldn't have them. +static mut FOO: i32 = 0; +const SUBTLE: &mut i32 = unsafe { &mut FOO }; +//~^ ERROR: it is undefined behavior to use this value +//~| static const BLUNT: &mut i32 = &mut 42; +//~^ ERROR: mutable pointer in final value + +// Check for mutable references to read-only memory. +static READONLY: i32 = 0; +static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; //~^ ERROR: it is undefined behavior to use this value +//~| pointing to read-only memory + +// Check for consts pointing to mutable memory. +// Currently it's not even possible to create such a const. +static mut MUTABLE: i32 = 42; +const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; +//~^ ERROR: undefined behavior to use this value +//~| pointing to a static +static mut MUTABLE_REF: &mut i32 = &mut 42; +const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; +//~^ ERROR: evaluation of constant value failed +//~| accesses static + +const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; +//~^ ERROR: mutable pointer in final value +const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; +//~^ ERROR: mutable pointer in final value +const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; +//~^ ERROR: mutable pointer in final value + +struct SyncPtr { x : *const T } +unsafe impl Sync for SyncPtr {} + +// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. +// (This relies on `SyncPtr` being a curly brace struct.) +// However, we intern the inner memory as read-only, so this must be rejected. +// (Also see `static-no-inner-mut` for similar tests on `static`.) +const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; +//~^ ERROR mutable pointer in final value +const RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; +//~^ ERROR mutable pointer in final value +const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; +//~^ ERROR mutable pointer in final value fn main() { unsafe { diff --git a/tests/ui/consts/miri_unleashed/raw_mutable_const.rs b/tests/ui/consts/miri_unleashed/raw_mutable_const.rs deleted file mode 100644 index adb1f8bf3ec55..0000000000000 --- a/tests/ui/consts/miri_unleashed/raw_mutable_const.rs +++ /dev/null @@ -1,8 +0,0 @@ -// compile-flags: -Zunleash-the-miri-inside-of-you - -use std::cell::UnsafeCell; - -const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; -//~^ ERROR: unsupported untyped pointer in constant - -fn main() {} diff --git a/tests/ui/consts/miri_unleashed/raw_mutable_const.stderr b/tests/ui/consts/miri_unleashed/raw_mutable_const.stderr deleted file mode 100644 index f4abaecac5e15..0000000000000 --- a/tests/ui/consts/miri_unleashed/raw_mutable_const.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: unsupported untyped pointer in constant - --> $DIR/raw_mutable_const.rs:5:1 - | -LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: memory only reachable via raw pointers is not supported - -warning: skipping const checks - | -help: skipping check that does not even have a feature gate - --> $DIR/raw_mutable_const.rs:5:38 - | -LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error; 1 warning emitted - diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr new file mode 100644 index 0000000000000..e8ed6742fab3a --- /dev/null +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr @@ -0,0 +1,82 @@ +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:9:1 + | +LL | static REF: &AtomicI32 = &AtomicI32::new(42); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:10:1 + | +LL | static REFMUT: &mut i32 = &mut 0; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:13:1 + | +LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:14:1 + | +LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:29:1 + | +LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:31:1 + | +LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:33:1 + | +LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:9:26 + | +LL | static REF: &AtomicI32 = &AtomicI32::new(42); + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:10:27 + | +LL | static REFMUT: &mut i32 = &mut 0; + | ^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:13:56 + | +LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; + | ^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:14:44 + | +LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; + | ^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:29:52 + | +LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:31:51 + | +LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:33:52 + | +LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ + +error: aborting due to 7 previous errors; 1 warning emitted + diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr new file mode 100644 index 0000000000000..e8ed6742fab3a --- /dev/null +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr @@ -0,0 +1,82 @@ +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:9:1 + | +LL | static REF: &AtomicI32 = &AtomicI32::new(42); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:10:1 + | +LL | static REFMUT: &mut i32 = &mut 0; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:13:1 + | +LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:14:1 + | +LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:29:1 + | +LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:31:1 + | +LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/static-no-inner-mut.rs:33:1 + | +LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:9:26 + | +LL | static REF: &AtomicI32 = &AtomicI32::new(42); + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:10:27 + | +LL | static REFMUT: &mut i32 = &mut 0; + | ^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:13:56 + | +LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; + | ^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:14:44 + | +LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; + | ^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:29:52 + | +LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:31:51 + | +LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/static-no-inner-mut.rs:33:52 + | +LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ + +error: aborting due to 7 previous errors; 1 warning emitted + diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs new file mode 100644 index 0000000000000..a4033eb56834e --- /dev/null +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs @@ -0,0 +1,36 @@ +// stderr-per-bitwidth +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_refs_to_cell, const_mut_refs)] +// All "inner" allocations that come with a `static` are interned immutably. This means it is +// crucial that we do not accept any form of (interior) mutability there. + +use std::sync::atomic::*; + +static REF: &AtomicI32 = &AtomicI32::new(42); //~ERROR mutable pointer in final value +static REFMUT: &mut i32 = &mut 0; //~ERROR mutable pointer in final value + +// Different way of writing this that avoids promotion. +static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; //~ERROR mutable pointer in final value +static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; //~ERROR mutable pointer in final value + +// This one is obvious, since it is non-Sync. (It also suppresses the other errors, so it is +// commented out.) +// static RAW: *const AtomicI32 = &AtomicI32::new(42); + +struct SyncPtr { x : *const T } +unsafe impl Sync for SyncPtr {} + +// All of these pass the lifetime checks because of the "tail expression" / "outer scope" rule. +// (This relies on `SyncPtr` being a curly brace struct.) +// Then they get interned immutably, which is not great. +// `mut_ref_in_final.rs` and `std/cell.rs` ensure that we don't accept this even with the feature +// fate, but for unleashed Miri there's not really any way we can reject them: it's just +// non-dangling raw pointers. +static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; +//~^ ERROR mutable pointer in final value +static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; +//~^ ERROR mutable pointer in final value +static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; +//~^ ERROR mutable pointer in final value + +fn main() {} diff --git a/tests/ui/consts/raw-ptr-const.rs b/tests/ui/consts/raw-ptr-const.rs index 541c5fd1ab134..24a77db9ffc5d 100644 --- a/tests/ui/consts/raw-ptr-const.rs +++ b/tests/ui/consts/raw-ptr-const.rs @@ -1,8 +1,8 @@ +// check-pass + // This is a regression test for a `span_delayed_bug` during interning when a constant -// evaluates to a (non-dangling) raw pointer. For now this errors; potentially it -// could also be allowed. +// evaluates to a (non-dangling) raw pointer. const CONST_RAW: *const Vec = &Vec::new() as *const _; -//~^ ERROR unsupported untyped pointer in constant fn main() {} diff --git a/tests/ui/consts/raw-ptr-const.stderr b/tests/ui/consts/raw-ptr-const.stderr deleted file mode 100644 index 9aef78505c087..0000000000000 --- a/tests/ui/consts/raw-ptr-const.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unsupported untyped pointer in constant - --> $DIR/raw-ptr-const.rs:5:1 - | -LL | const CONST_RAW: *const Vec = &Vec::new() as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: memory only reachable via raw pointers is not supported - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/raw-ptr-temp-const.rs b/tests/ui/consts/raw-ptr-temp-const.rs new file mode 100644 index 0000000000000..deb51cd505c7a --- /dev/null +++ b/tests/ui/consts/raw-ptr-temp-const.rs @@ -0,0 +1,6 @@ +// A variant of raw-ptr-const that directly constructs a raw pointer. + +const CONST_RAW: *const Vec = std::ptr::addr_of!(Vec::new()); +//~^ ERROR cannot take address of a temporary + +fn main() {} diff --git a/tests/ui/consts/raw-ptr-temp-const.stderr b/tests/ui/consts/raw-ptr-temp-const.stderr new file mode 100644 index 0000000000000..601671f71aec7 --- /dev/null +++ b/tests/ui/consts/raw-ptr-temp-const.stderr @@ -0,0 +1,9 @@ +error[E0745]: cannot take address of a temporary + --> $DIR/raw-ptr-temp-const.rs:3:55 + | +LL | const CONST_RAW: *const Vec = std::ptr::addr_of!(Vec::new()); + | ^^^^^^^^^^ temporary value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0745`. diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index 3bbb685a67819..5b4a0418b1e9a 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ - = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + | + = note: ...which immediately requires const-evaluating + checking `FOO` again note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index 3bbb685a67819..5b4a0418b1e9a 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ - = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + | + = note: ...which immediately requires const-evaluating + checking `FOO` again note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | diff --git a/tests/ui/consts/refs-to-cell-in-final.rs b/tests/ui/consts/refs-to-cell-in-final.rs new file mode 100644 index 0000000000000..6a849ff0df929 --- /dev/null +++ b/tests/ui/consts/refs-to-cell-in-final.rs @@ -0,0 +1,18 @@ +#![feature(const_refs_to_cell)] + +use std::cell::*; + +struct SyncPtr { x : *const T } +unsafe impl Sync for SyncPtr {} + +// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. +// (This relies on `SyncPtr` being a curly brace struct.) +// However, we intern the inner memory as read-only. +// The resulting constant would pass all validation checks, so it is crucial that this gets rejected +// by static const checks! +static RAW_SYNC_S: SyncPtr> = SyncPtr { x: &Cell::new(42) }; +//~^ ERROR: cannot refer to interior mutable data +const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; +//~^ ERROR: cannot refer to interior mutable data + +fn main() {} diff --git a/tests/ui/consts/refs-to-cell-in-final.stderr b/tests/ui/consts/refs-to-cell-in-final.stderr new file mode 100644 index 0000000000000..fae16fa01251c --- /dev/null +++ b/tests/ui/consts/refs-to-cell-in-final.stderr @@ -0,0 +1,17 @@ +error[E0492]: statics cannot refer to interior mutable data + --> $DIR/refs-to-cell-in-final.rs:13:54 + | +LL | static RAW_SYNC_S: SyncPtr> = SyncPtr { x: &Cell::new(42) }; + | ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value + | + = help: to fix this, the value can be extracted to a separate `static` item and then referenced + +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/refs-to-cell-in-final.rs:15:53 + | +LL | const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; + | ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/std/cell.stderr b/tests/ui/consts/std/cell.stderr index 937fa7db0c8c0..873b797a466db 100644 --- a/tests/ui/consts/std/cell.stderr +++ b/tests/ui/consts/std/cell.stderr @@ -1,22 +1,22 @@ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of static --> $DIR/cell.rs:6:1 | LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of constant --> $DIR/cell.rs:8:1 | LL | const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of constant --> $DIR/cell.rs:22:1 | LL | const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: encountered dangling pointer in final constant +error: encountered dangling pointer in final value of constant --> $DIR/cell.rs:27:1 | LL | const FOO2: *mut u32 = Cell::new(42).as_ptr(); diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index 843d6d9e04ba7..4089c850c8021 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -22,13 +22,13 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: - <[A; N] as PartialEq<[B; N]>> - <[A; N] as PartialEq<[B]>> - <[A; N] as PartialEq<&[B]>> - <[A; N] as PartialEq<&mut [B]>> + <[T; N] as PartialEq<[U; N]>> + <[T; N] as PartialEq<[U]>> + <[T; N] as PartialEq<&[U]>> + <[T; N] as PartialEq<&mut [U]>> <[T] as PartialEq>> - <[A] as PartialEq<[B]>> - <[B] as PartialEq<[A; N]>> + <[T] as PartialEq<[U; N]>> + <[T] as PartialEq<[U]>> <&[T] as PartialEq>> and 3 others diff --git a/tests/ui/consts/underscore_const_names.rs b/tests/ui/consts/underscore_const_names.rs index d0e625bf1997a..e2ae5a9d53aac 100644 --- a/tests/ui/consts/underscore_const_names.rs +++ b/tests/ui/consts/underscore_const_names.rs @@ -2,12 +2,12 @@ #![deny(unused)] -trait Trt {} +pub trait Trt {} pub struct Str {} impl Trt for Str {} macro_rules! check_impl { - ($struct:ident,$trait:ident) => { + ($struct:ident, $trait:ident) => { const _ : () = { use std::marker::PhantomData; struct ImplementsTrait(PhantomData); diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index 5665e56439e01..caee433a6813a 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -5,17 +5,12 @@ LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer error[E0391]: cycle detected when const-evaluating + checking `C` - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:34 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^ - = note: ...which again requires const-evaluating + checking `C`, completing the cycle + | + = note: ...which immediately requires const-evaluating + checking `C` again note: cycle used when linting top-level module --> $DIR/write-to-static-mut-in-static.rs:1:1 | diff --git a/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs b/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs index aac74d3eacba8..80c0b69a6f7ed 100644 --- a/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs +++ b/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs @@ -11,7 +11,6 @@ async gen fn gen_fn() -> &'static str { pub fn main() { let async_iterator = pin!(gen_fn()); - let waker = Waker::noop(); - let ctx = &mut Context::from_waker(&waker); + let ctx = &mut Context::from_waker(Waker::noop()); async_iterator.poll_next(ctx); } diff --git a/tests/ui/coroutine/async_gen_fn_iter.rs b/tests/ui/coroutine/async_gen_fn_iter.rs index ec6464d004877..604156b4d373f 100644 --- a/tests/ui/coroutine/async_gen_fn_iter.rs +++ b/tests/ui/coroutine/async_gen_fn_iter.rs @@ -74,8 +74,7 @@ fn main() { let mut fut = pin!(async_main()); // Poll loop, just to test the future... - let waker = Waker::noop(); - let ctx = &mut Context::from_waker(&waker); + let ctx = &mut Context::from_waker(Waker::noop()); loop { match fut.as_mut().poll(ctx) { diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index 82a6d0495c003..1d4804501d8bc 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -5,7 +5,7 @@ LL | let gen_clone_0 = move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}: Copy` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:40:14 @@ -25,7 +25,7 @@ LL | let gen_clone_0 = move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield --> $DIR/clone-impl.rs:38:9 @@ -47,7 +47,7 @@ LL | let gen_clone_1 = move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}: Copy` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:56:14 @@ -67,7 +67,7 @@ LL | let gen_clone_1 = move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield --> $DIR/clone-impl.rs:52:9 @@ -90,7 +90,7 @@ LL | let gen_non_clone = move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Copy` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}: Copy` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:64:14 @@ -115,7 +115,7 @@ LL | let gen_non_clone = move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Clone` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}: Clone` | note: captured value does not implement `Clone` --> $DIR/clone-impl.rs:64:14 diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.stderr b/tests/ui/coroutine/drop-tracking-parent-expression.stderr index 6cd4ec83377d9..21aa35b9579bc 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.stderr +++ b/tests/ui/coroutine/drop-tracking-parent-expression.stderr @@ -2,7 +2,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/drop-tracking-parent-expression.rs:23:13 | LL | assert_send(g); - | ^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^ coroutine is not `Send` ... LL | / type_combinations!( LL | | // OK @@ -13,7 +13,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | @@ -42,7 +42,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/drop-tracking-parent-expression.rs:23:13 | LL | assert_send(g); - | ^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^ coroutine is not `Send` ... LL | / type_combinations!( LL | | // OK @@ -53,7 +53,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | @@ -82,7 +82,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/drop-tracking-parent-expression.rs:23:13 | LL | assert_send(g); - | ^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^ coroutine is not `Send` ... LL | / type_combinations!( LL | | // OK @@ -93,7 +93,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | diff --git a/tests/ui/coroutine/drop-yield-twice.stderr b/tests/ui/coroutine/drop-yield-twice.stderr index b37c27015fb2e..c6a9e20b8b51f 100644 --- a/tests/ui/coroutine/drop-yield-twice.stderr +++ b/tests/ui/coroutine/drop-yield-twice.stderr @@ -1,10 +1,15 @@ error: coroutine cannot be sent between threads safely --> $DIR/drop-yield-twice.rs:7:5 | -LL | assert_send(|| { - | ^^^^^^^^^^^ coroutine is not `Send` +LL | / assert_send(|| { +LL | | let guard = Foo(42); +LL | | yield; +LL | | drop(guard); +LL | | yield; +LL | | }) + | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}`, the trait `Send` is not implemented for `Foo` + = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-yield-twice.rs:9:9 | diff --git a/tests/ui/coroutine/issue-105084.stderr b/tests/ui/coroutine/issue-105084.stderr index 38f114ff7747f..c8a6522dbd938 100644 --- a/tests/ui/coroutine/issue-105084.stderr +++ b/tests/ui/coroutine/issue-105084.stderr @@ -29,7 +29,7 @@ LL | let mut g = || { | -- within this `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}` ... LL | let mut h = copy(g); - | ^^^^ within `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}`, the trait `Copy` is not implemented for `Box<(i32, ())>` + | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield --> $DIR/issue-105084.rs:21:22 diff --git a/tests/ui/coroutine/issue-68112.stderr b/tests/ui/coroutine/issue-68112.stderr index 5efa72ad5fe02..ded325eda544c 100644 --- a/tests/ui/coroutine/issue-68112.stderr +++ b/tests/ui/coroutine/issue-68112.stderr @@ -2,9 +2,9 @@ error: coroutine cannot be sent between threads safely --> $DIR/issue-68112.rs:40:5 | LL | require_send(send_gen); - | ^^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{coroutine@$DIR/issue-68112.rs:33:20: 33:22}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: coroutine is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:36:9 @@ -24,9 +24,9 @@ error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:64:5 | LL | require_send(send_gen); - | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{coroutine@$DIR/issue-68112.rs:60:20: 60:22}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this coroutine diff --git a/tests/ui/coroutine/not-send-sync.stderr b/tests/ui/coroutine/not-send-sync.stderr index b33a1e63aafd2..9228340c710dd 100644 --- a/tests/ui/coroutine/not-send-sync.stderr +++ b/tests/ui/coroutine/not-send-sync.stderr @@ -1,10 +1,15 @@ error: coroutine cannot be shared between threads safely --> $DIR/not-send-sync.rs:14:5 | -LL | assert_sync(|| { - | ^^^^^^^^^^^ coroutine is not `Sync` - | - = help: within `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}`, the trait `Sync` is not implemented for `NotSync` +LL | / assert_sync(|| { +LL | | +LL | | let a = NotSync; +LL | | yield; +LL | | drop(a); +LL | | }); + | |______^ coroutine is not `Sync` + | + = help: within `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}: Sync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:17:9 | @@ -21,10 +26,15 @@ LL | fn assert_sync(_: T) {} error: coroutine cannot be sent between threads safely --> $DIR/not-send-sync.rs:21:5 | -LL | assert_send(|| { - | ^^^^^^^^^^^ coroutine is not `Send` +LL | / assert_send(|| { +LL | | +LL | | let a = NotSend; +LL | | yield; +LL | | drop(a); +LL | | }); + | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}`, the trait `Send` is not implemented for `NotSend` + = help: within `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/not-send-sync.rs:24:9 | diff --git a/tests/ui/coroutine/parent-expression.stderr b/tests/ui/coroutine/parent-expression.stderr index 6b611bc3f103e..5b3737069e6c1 100644 --- a/tests/ui/coroutine/parent-expression.stderr +++ b/tests/ui/coroutine/parent-expression.stderr @@ -2,7 +2,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/parent-expression.rs:23:13 | LL | assert_send(g); - | ^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^ coroutine is not `Send` ... LL | / type_combinations!( LL | | // OK @@ -13,7 +13,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client` + = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | @@ -42,7 +42,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/parent-expression.rs:23:13 | LL | assert_send(g); - | ^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^ coroutine is not `Send` ... LL | / type_combinations!( LL | | // OK @@ -53,7 +53,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client` + = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | @@ -82,7 +82,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/parent-expression.rs:23:13 | LL | assert_send(g); - | ^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^ coroutine is not `Send` ... LL | / type_combinations!( LL | | // OK @@ -93,7 +93,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client` + = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr index bcdcbc154cf0a..1b9ca632f0cb6 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr @@ -2,9 +2,9 @@ error: coroutine cannot be sent between threads safely --> $DIR/coroutine-print-verbose-1.rs:37:5 | LL | require_send(send_gen); - | ^^^^^^^^^^^^ coroutine is not `Send` + | ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{test1::{closure#0} upvar_tys=() witness={test1::{closure#0}}}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-1.rs:35:9 @@ -23,9 +23,9 @@ error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/coroutine-print-verbose-1.rs:56:5 | LL | require_send(send_gen); - | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{test2::{closure#0} upvar_tys=() witness={test2::{closure#0}}}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this coroutine diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index e9c7a8ffcaab6..26c9c27743c01 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -1,10 +1,15 @@ error: coroutine cannot be shared between threads safely --> $DIR/coroutine-print-verbose-2.rs:17:5 | -LL | assert_sync(|| { - | ^^^^^^^^^^^ coroutine is not `Sync` - | - = help: within `{main::{closure#0} upvar_tys=() {main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync` +LL | / assert_sync(|| { +LL | | +LL | | let a = NotSync; +LL | | yield; +LL | | drop(a); +LL | | }); + | |______^ coroutine is not `Sync` + | + = help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}: Sync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:20:9 | @@ -21,10 +26,15 @@ LL | fn assert_sync(_: T) {} error: coroutine cannot be sent between threads safely --> $DIR/coroutine-print-verbose-2.rs:24:5 | -LL | assert_send(|| { - | ^^^^^^^^^^^ coroutine is not `Send` +LL | / assert_send(|| { +LL | | +LL | | let a = NotSend; +LL | | yield; +LL | | drop(a); +LL | | }); + | |______^ coroutine is not `Send` | - = help: within `{main::{closure#1} upvar_tys=() {main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend` + = help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`, which is required by `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:27:9 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index 100993bd33cf6..e2973cde6d3cc 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{main::{closure#0} upvar_tys=(unavailable)}` + found coroutine `{main::{closure#0} upvar_tys=?4t witness=?6t}` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr index 7f18c6fba775f..0f91bcf40533f 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.stderr +++ b/tests/ui/coroutine/ref-upvar-not-send.stderr @@ -10,7 +10,7 @@ LL | | let _x = x; LL | | }); | |_____^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `*mut ()` + = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:17: 15:24}: Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` --> $DIR/ref-upvar-not-send.rs:19:18 | @@ -34,7 +34,7 @@ LL | | let _y = y; LL | | }); | |_____^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}`, the trait `Send` is not implemented for `*mut ()` + = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}: Send` note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send` --> $DIR/ref-upvar-not-send.rs:27:18 | diff --git a/tests/ui/coroutine/sized-yield.stderr b/tests/ui/coroutine/sized-yield.stderr index bbecaffa95a12..4e8dc13201de3 100644 --- a/tests/ui/coroutine/sized-yield.stderr +++ b/tests/ui/coroutine/sized-yield.stderr @@ -18,7 +18,7 @@ LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` -note: required by a bound in `CoroutineState` +note: required by an implicit `Sized` bound in `CoroutineState` --> $SRC_DIR/core/src/ops/coroutine.rs:LL:COL error: aborting due to 2 previous errors diff --git a/tests/ui/coroutine/unresolved-ct-var.stderr b/tests/ui/coroutine/unresolved-ct-var.stderr index da2ec272f9fff..8b87bac05acb2 100644 --- a/tests/ui/coroutine/unresolved-ct-var.stderr +++ b/tests/ui/coroutine/unresolved-ct-var.stderr @@ -8,7 +8,7 @@ LL | let s = std::array::from_fn(|_| ()).await; | | help: remove the `.await` | this call returns `[(); _]` | - = help: the trait `Future` is not implemented for `[(); _]` + = help: the trait `Future` is not implemented for `[(); _]`, which is required by `[(); _]: IntoFuture` = note: [(); _] must be a future or must implement `IntoFuture` to be awaited = note: required for `[(); _]` to implement `IntoFuture` diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr index f28f8913508f2..8f8bec9945847 100644 --- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr +++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr @@ -10,7 +10,7 @@ error[E0277]: `{integer}` is not an iterator LL | yield || for i in 0 { } | ^ `{integer}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{integer}` + = help: the trait `Iterator` is not implemented for `{integer}`, which is required by `{integer}: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{integer}` to implement `IntoIterator` diff --git a/tests/ui/default-method-parsing.rs b/tests/ui/default-method-parsing.rs index 9ffb8d94a59b3..5001d58f0a48e 100644 --- a/tests/ui/default-method-parsing.rs +++ b/tests/ui/default-method-parsing.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/delegation/target-expr-pass.rs b/tests/ui/delegation/target-expr-pass.rs index 56068dfce01d7..4ccb81c292aa5 100644 --- a/tests/ui/delegation/target-expr-pass.rs +++ b/tests/ui/delegation/target-expr-pass.rs @@ -14,14 +14,14 @@ reuse to_reuse::foo {{ x + self }} -trait Trait { +trait Trait { //~ WARN trait `Trait` is never used fn bar(&self, x: i32) -> i32 { x } } -struct F; +struct F; //~ WARN struct `F` is never constructed impl Trait for F {} -struct S(F); +struct S(F); //~ WARN struct `S` is never constructed impl Trait for S { reuse ::bar { #[allow(unused_imports)] diff --git a/tests/ui/delegation/target-expr-pass.stderr b/tests/ui/delegation/target-expr-pass.stderr index ea594f8a26a5b..dd1f3a14e0bd8 100644 --- a/tests/ui/delegation/target-expr-pass.stderr +++ b/tests/ui/delegation/target-expr-pass.stderr @@ -7,5 +7,25 @@ LL | #![feature(fn_delegation)] = note: see issue #118212 for more information = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +warning: trait `Trait` is never used + --> $DIR/target-expr-pass.rs:17:7 + | +LL | trait Trait { + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: struct `F` is never constructed + --> $DIR/target-expr-pass.rs:21:8 + | +LL | struct F; + | ^ + +warning: struct `S` is never constructed + --> $DIR/target-expr-pass.rs:24:8 + | +LL | struct S(F); + | ^ + +warning: 4 warnings emitted diff --git a/tests/ui/derives/derive-assoc-type-not-impl.stderr b/tests/ui/derives/derive-assoc-type-not-impl.stderr index 6cbcb455f87e9..13ba80243a5eb 100644 --- a/tests/ui/derives/derive-assoc-type-not-impl.stderr +++ b/tests/ui/derives/derive-assoc-type-not-impl.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `clone` exists for struct `Bar`, but its trai --> $DIR/derive-assoc-type-not-impl.rs:18:30 | LL | struct Bar { - | ------------------ - | | - | method `clone` not found for this struct - | doesn't satisfy `Bar: Clone` + | ------------------ method `clone` not found for this struct because it doesn't satisfy `Bar: Clone` ... LL | struct NotClone; | --------------- doesn't satisfy `NotClone: Clone` @@ -18,9 +15,6 @@ note: trait bound `NotClone: Clone` was not satisfied | LL | #[derive(Clone)] | ^^^^^ unsatisfied trait bound introduced in this `derive` macro - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `Clone` help: consider annotating `NotClone` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr index 3f6c39bf9396e..b10805ac8f06f 100644 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -7,7 +7,7 @@ LL | #[derive(Debug)] LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error` + = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr index eaeffaeb84956..0329744390166 100644 --- a/tests/ui/derives/derives-span-Debug-enum.stderr +++ b/tests/ui/derives/derives-span-Debug-enum.stderr @@ -7,7 +7,7 @@ LL | #[derive(Debug)] LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error` + = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr index 4a725e260deae..369c0b56ac4e8 100644 --- a/tests/ui/derives/derives-span-Debug-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-struct.stderr @@ -7,7 +7,7 @@ LL | struct Struct { LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error` + = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr index 2f816e1c85b25..abfef9ef35425 100644 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -7,7 +7,7 @@ LL | struct Struct( LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error` + = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr index 0eaca7e236098..96f51a4e7a2b4 100644 --- a/tests/ui/derives/deriving-with-repr-packed-2.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -2,16 +2,10 @@ error[E0599]: the method `clone` exists for struct `Foo`, but its trait --> $DIR/deriving-with-repr-packed-2.rs:18:11 | LL | pub struct Foo(T, T, T); - | ----------------- - | | - | method `clone` not found for this struct - | doesn't satisfy `Foo: Clone` + | ----------------- method `clone` not found for this struct because it doesn't satisfy `Foo: Clone` LL | LL | struct NonCopy; - | -------------- - | | - | doesn't satisfy `NonCopy: Clone` - | doesn't satisfy `NonCopy: Copy` + | -------------- doesn't satisfy `NonCopy: Clone` or `NonCopy: Copy` ... LL | _ = x.clone(); | ^^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds diff --git a/tests/ui/derives/issue-36617.rs b/tests/ui/derives/issue-36617.rs index 08f293d2ebb06..236ec7748cbdd 100644 --- a/tests/ui/derives/issue-36617.rs +++ b/tests/ui/derives/issue-36617.rs @@ -1,16 +1,16 @@ -#![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive` +#![derive(Copy)] //~^ ERROR `derive` attribute cannot be used at crate level -#![test]//~ ERROR cannot determine resolution for the attribute macro `test` +#![test] //~^ ERROR `test` attribute cannot be used at crate level -#![test_case]//~ ERROR cannot determine resolution for the attribute macro `test_case` +#![test_case] //~^ ERROR `test_case` attribute cannot be used at crate level -#![bench]//~ ERROR cannot determine resolution for the attribute macro `bench` +#![bench] //~^ ERROR `bench` attribute cannot be used at crate level -#![global_allocator]//~ ERROR cannot determine resolution for the attribute macro `global_allocator` +#![global_allocator] //~^ ERROR `global_allocator` attribute cannot be used at crate level fn main() {} diff --git a/tests/ui/derives/issue-36617.stderr b/tests/ui/derives/issue-36617.stderr index 98be7963e5ef9..3de1d87c5046c 100644 --- a/tests/ui/derives/issue-36617.stderr +++ b/tests/ui/derives/issue-36617.stderr @@ -1,43 +1,3 @@ -error: cannot determine resolution for the attribute macro `derive` - --> $DIR/issue-36617.rs:1:4 - | -LL | #![derive(Copy)] - | ^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the attribute macro `test` - --> $DIR/issue-36617.rs:4:4 - | -LL | #![test] - | ^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the attribute macro `test_case` - --> $DIR/issue-36617.rs:7:4 - | -LL | #![test_case] - | ^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the attribute macro `bench` - --> $DIR/issue-36617.rs:10:4 - | -LL | #![bench] - | ^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the attribute macro `global_allocator` - --> $DIR/issue-36617.rs:13:4 - | -LL | #![global_allocator] - | ^^^^^^^^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: `derive` attribute cannot be used at crate level --> $DIR/issue-36617.rs:1:1 | @@ -113,5 +73,5 @@ LL - #![global_allocator] LL + #[global_allocator] | -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index 1324b80b5fcdb..9e17189671827 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -2,11 +2,7 @@ error[E0599]: the method `insert` exists for struct `HashSet`, but its tr --> $DIR/issue-91550.rs:8:8 | LL | struct Value(u32); - | ------------ - | | - | doesn't satisfy `Value: Eq` - | doesn't satisfy `Value: Hash` - | doesn't satisfy `Value: PartialEq` + | ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq` ... LL | hs.insert(Value(0)); | ^^^^^^ @@ -26,10 +22,7 @@ error[E0599]: the method `use_eq` exists for struct `Object`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | -------------------- - | | - | doesn't satisfy `NoDerives: Eq` - | doesn't satisfy `NoDerives: PartialEq` + | -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq` LL | LL | struct Object(T); | ---------------- method `use_eq` not found for this struct @@ -57,12 +50,7 @@ error[E0599]: the method `use_ord` exists for struct `Object`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | -------------------- - | | - | doesn't satisfy `NoDerives: Eq` - | doesn't satisfy `NoDerives: Ord` - | doesn't satisfy `NoDerives: PartialEq` - | doesn't satisfy `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord` not found for this struct @@ -94,12 +82,7 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object $DIR/issue-91550.rs:28:9 | LL | pub struct NoDerives; - | -------------------- - | | - | doesn't satisfy `NoDerives: Eq` - | doesn't satisfy `NoDerives: Ord` - | doesn't satisfy `NoDerives: PartialEq` - | doesn't satisfy `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord_and_partial_ord` not found for this struct diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 42154c3c3be23..9c6f4d3094b55 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -56,8 +56,6 @@ impl ::core::cmp::PartialEq for Empty { fn eq(&self, other: &Empty) -> bool { true } } #[automatically_derived] -impl ::core::marker::StructuralEq for Empty { } -#[automatically_derived] impl ::core::cmp::Eq for Empty { #[inline] #[doc(hidden)] @@ -132,8 +130,6 @@ impl ::core::cmp::PartialEq for Point { } } #[automatically_derived] -impl ::core::marker::StructuralEq for Point { } -#[automatically_derived] impl ::core::cmp::Eq for Point { #[inline] #[doc(hidden)] @@ -219,8 +215,6 @@ impl ::core::cmp::PartialEq for PackedPoint { } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedPoint { } -#[automatically_derived] impl ::core::cmp::Eq for PackedPoint { #[inline] #[doc(hidden)] @@ -333,8 +327,6 @@ impl ::core::cmp::PartialEq for Big { } } #[automatically_derived] -impl ::core::marker::StructuralEq for Big { } -#[automatically_derived] impl ::core::cmp::Eq for Big { #[inline] #[doc(hidden)] @@ -500,8 +492,6 @@ impl ::core::cmp::PartialEq for Unsized { fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 } } #[automatically_derived] -impl ::core::marker::StructuralEq for Unsized { } -#[automatically_derived] impl ::core::cmp::Eq for Unsized { #[inline] #[doc(hidden)] @@ -616,8 +606,6 @@ impl } } #[automatically_derived] -impl ::core::marker::StructuralEq for Generic { } -#[automatically_derived] impl ::core::cmp::Eq for Generic where T::A: ::core::cmp::Eq { #[inline] @@ -739,8 +727,6 @@ impl ::core::marker::StructuralEq for PackedGeneric { } -#[automatically_derived] impl ::core::cmp::Eq for PackedGeneric where T::A: ::core::cmp::Eq + ::core::marker::Copy { @@ -825,8 +811,6 @@ impl ::core::cmp::PartialEq for Enum0 { fn eq(&self, other: &Enum0) -> bool { match *self {} } } #[automatically_derived] -impl ::core::marker::StructuralEq for Enum0 { } -#[automatically_derived] impl ::core::cmp::Eq for Enum0 { #[inline] #[doc(hidden)] @@ -897,8 +881,6 @@ impl ::core::cmp::PartialEq for Enum1 { } } #[automatically_derived] -impl ::core::marker::StructuralEq for Enum1 { } -#[automatically_derived] impl ::core::cmp::Eq for Enum1 { #[inline] #[doc(hidden)] @@ -965,8 +947,6 @@ impl ::core::cmp::PartialEq for Fieldless1 { fn eq(&self, other: &Fieldless1) -> bool { true } } #[automatically_derived] -impl ::core::marker::StructuralEq for Fieldless1 { } -#[automatically_derived] impl ::core::cmp::Eq for Fieldless1 { #[inline] #[doc(hidden)] @@ -1041,8 +1021,6 @@ impl ::core::cmp::PartialEq for Fieldless { } } #[automatically_derived] -impl ::core::marker::StructuralEq for Fieldless { } -#[automatically_derived] impl ::core::cmp::Eq for Fieldless { #[inline] #[doc(hidden)] @@ -1150,8 +1128,6 @@ impl ::core::cmp::PartialEq for Mixed { } } #[automatically_derived] -impl ::core::marker::StructuralEq for Mixed { } -#[automatically_derived] impl ::core::cmp::Eq for Mixed { #[inline] #[doc(hidden)] @@ -1279,8 +1255,6 @@ impl ::core::cmp::PartialEq for Fielded { } } #[automatically_derived] -impl ::core::marker::StructuralEq for Fielded { } -#[automatically_derived] impl ::core::cmp::Eq for Fielded { #[inline] #[doc(hidden)] @@ -1402,8 +1376,6 @@ impl } } #[automatically_derived] -impl ::core::marker::StructuralEq for EnumGeneric { } -#[automatically_derived] impl ::core::cmp::Eq for EnumGeneric { #[inline] diff --git a/tests/ui/deriving/deriving-bounds.rs b/tests/ui/deriving/deriving-bounds.rs index f0b921d0e7c0e..f3e7cf99437d5 100644 --- a/tests/ui/deriving/deriving-bounds.rs +++ b/tests/ui/deriving/deriving-bounds.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #[derive(Copy, Clone)] struct Test; diff --git a/tests/ui/deriving/issue-103157.stderr b/tests/ui/deriving/issue-103157.stderr index 384899ea43334..f76701860efb5 100644 --- a/tests/ui/deriving/issue-103157.stderr +++ b/tests/ui/deriving/issue-103157.stderr @@ -5,7 +5,7 @@ LL | #[derive(PartialEq, Eq)] | -- in this derive macro expansion ... LL | Float(Option), - | ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64` + | ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64`, which is required by `Option: Eq` | = help: the following other types implement trait `Eq`: isize diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 3c474d19d1d05..eed01267224d3 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -191,7 +191,14 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as AsyncFnOnce>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19 diff --git a/tests/ui/did_you_mean/recursion_limit.stderr b/tests/ui/did_you_mean/recursion_limit.stderr index bff57a63deb16..2ecee2030b03f 100644 --- a/tests/ui/did_you_mean/recursion_limit.stderr +++ b/tests/ui/did_you_mean/recursion_limit.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow evaluating the requirement `J: Send` --> $DIR/recursion_limit.rs:34:5 | LL | is_send::(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`) note: required because it appears within the type `I` diff --git a/tests/ui/drop/drop-struct-as-object.rs b/tests/ui/drop/drop-struct-as-object.rs index 377027a4fc5f2..1aa6877704253 100644 --- a/tests/ui/drop/drop-struct-as-object.rs +++ b/tests/ui/drop/drop-struct-as-object.rs @@ -12,7 +12,7 @@ struct Cat { } trait Dummy { - fn get(&self) -> usize; + fn get(&self) -> usize; //~ WARN method `get` is never used } impl Dummy for Cat { diff --git a/tests/ui/drop/drop-struct-as-object.stderr b/tests/ui/drop/drop-struct-as-object.stderr new file mode 100644 index 0000000000000..10527c968ed70 --- /dev/null +++ b/tests/ui/drop/drop-struct-as-object.stderr @@ -0,0 +1,12 @@ +warning: method `get` is never used + --> $DIR/drop-struct-as-object.rs:15:8 + | +LL | trait Dummy { + | ----- method in this trait +LL | fn get(&self) -> usize; + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/dst/dst-bad-assign-3.stderr b/tests/ui/dst/dst-bad-assign-3.stderr index 6dd3434fd21be..007f6b898bee5 100644 --- a/tests/ui/dst/dst-bad-assign-3.stderr +++ b/tests/ui/dst/dst-bad-assign-3.stderr @@ -8,6 +8,7 @@ LL | f5.2 = Bar1 {f: 36}; | = note: expected trait object `dyn ToBar` found struct `Bar1` + = help: `Bar1` implements `ToBar` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time --> $DIR/dst-bad-assign-3.rs:33:5 diff --git a/tests/ui/dst/dst-bad-assign.stderr b/tests/ui/dst/dst-bad-assign.stderr index d8d1057876f4f..f935d27e96e2f 100644 --- a/tests/ui/dst/dst-bad-assign.stderr +++ b/tests/ui/dst/dst-bad-assign.stderr @@ -8,6 +8,7 @@ LL | f5.ptr = Bar1 {f: 36}; | = note: expected trait object `dyn ToBar` found struct `Bar1` + = help: `Bar1` implements `ToBar` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time --> $DIR/dst-bad-assign.rs:35:5 diff --git a/tests/ui/dst/dst-bad-deep-2.stderr b/tests/ui/dst/dst-bad-deep-2.stderr index c7e9854340f09..554e81bee10a5 100644 --- a/tests/ui/dst/dst-bad-deep-2.stderr +++ b/tests/ui/dst/dst-bad-deep-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &(([isize],),) = &(*g,); | ^^^^^ doesn't have a size known at compile-time | - = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]` + = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]`, which is required by `(([isize],),): Sized` = note: required because it appears within the type `([isize],)` = note: required because it appears within the type `(([isize],),)` = note: tuples must have a statically known size to be initialized diff --git a/tests/ui/dst/dst-bad-deep.stderr b/tests/ui/dst/dst-bad-deep.stderr index 1b0f9738ab09a..4f180e593f8ae 100644 --- a/tests/ui/dst/dst-bad-deep.stderr +++ b/tests/ui/dst/dst-bad-deep.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &Fat> = &Fat { ptr: *g }; | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Fat>`, the trait `Sized` is not implemented for `[isize]` + = help: within `Fat>`, the trait `Sized` is not implemented for `[isize]`, which is required by `Fat>: Sized` note: required because it appears within the type `Fat<[isize]>` --> $DIR/dst-bad-deep.rs:6:8 | diff --git a/tests/ui/dst/dst-sized-trait-param.stderr b/tests/ui/dst/dst-sized-trait-param.stderr index 60e9de90332cc..2ac666c8a2cc7 100644 --- a/tests/ui/dst/dst-sized-trait-param.stderr +++ b/tests/ui/dst/dst-sized-trait-param.stderr @@ -5,11 +5,11 @@ LL | impl Foo<[isize]> for usize { } | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[isize]` -note: required by a bound in `Foo` +note: required by an implicit `Sized` bound in `Foo` --> $DIR/dst-sized-trait-param.rs:5:11 | LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized - | ^ required by this bound in `Foo` + | ^ required by the implicit `Sized` requirement on this type parameter in `Foo` help: consider relaxing the implicit `Sized` restriction | LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized diff --git a/tests/ui/dst/issue-90528-unsizing-not-suggestion-110063.stderr b/tests/ui/dst/issue-90528-unsizing-not-suggestion-110063.stderr index 6752a484448c5..2d7956f1958c5 100644 --- a/tests/ui/dst/issue-90528-unsizing-not-suggestion-110063.stderr +++ b/tests/ui/dst/issue-90528-unsizing-not-suggestion-110063.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `[u8; 1]: Test` is not satisfied --> $DIR/issue-90528-unsizing-not-suggestion-110063.rs:11:22 | LL | let x: [u8; 1] = needs_test(); - | ^^^^^^^^^^ the trait `Test` is not implemented for `[u8; 1]` + | ^^^^^^^^^^^^ the trait `Test` is not implemented for `[u8; 1]` | = help: the trait `Test` is implemented for `&[u8]` note: required by a bound in `needs_test` diff --git a/tests/ui/dyn-star/dispatch-on-pin-mut.rs b/tests/ui/dyn-star/dispatch-on-pin-mut.rs index c4ae279e6c11e..151aa9092fbe1 100644 --- a/tests/ui/dyn-star/dispatch-on-pin-mut.rs +++ b/tests/ui/dyn-star/dispatch-on-pin-mut.rs @@ -19,15 +19,14 @@ async fn async_main() { // ------------------------------------------------------------------------- // // Implementation Details Below... -use std::task::*; use std::pin::pin; +use std::task::*; fn main() { let mut fut = pin!(async_main()); // Poll loop, just to test the future... - let waker = Waker::noop(); - let ctx = &mut Context::from_waker(&waker); + let ctx = &mut Context::from_waker(Waker::noop()); loop { match fut.as_mut().poll(ctx) { diff --git a/tests/ui/dyn-star/no-implicit-dyn-star.stderr b/tests/ui/dyn-star/no-implicit-dyn-star.stderr index 06c7bcc574825..bea334a8a69a8 100644 --- a/tests/ui/dyn-star/no-implicit-dyn-star.stderr +++ b/tests/ui/dyn-star/no-implicit-dyn-star.stderr @@ -8,6 +8,7 @@ LL | dyn_star_foreign::require_dyn_star_display(1usize); | = note: expected trait object `(dyn* std::fmt::Display + 'static)` found type `usize` + = help: `usize` implements `Display`, `#[feature(dyn_star)]` is likely not enabled; that feature it is currently incomplete note: function defined here --> $DIR/auxiliary/dyn-star-foreign.rs:6:8 | diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs index 0201c8897065c..a4eb669e32104 100644 --- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs +++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs @@ -1,4 +1,4 @@ -#![feature(dyn_star)] +#![feature(dyn_star, trait_upcasting)] //~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes trait A: B {} diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr index 7e2cf661369b9..1f7bfb1d5bdc5 100644 --- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr +++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr @@ -1,7 +1,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/no-unsize-coerce-dyn-trait.rs:1:12 | -LL | #![feature(dyn_star)] +LL | #![feature(dyn_star, trait_upcasting)] | ^^^^^^^^ | = note: see issue #102425 for more information diff --git a/tests/ui/dyn-star/upcast.rs b/tests/ui/dyn-star/upcast.rs index 7748cdda943c2..c667ac143a395 100644 --- a/tests/ui/dyn-star/upcast.rs +++ b/tests/ui/dyn-star/upcast.rs @@ -1,6 +1,6 @@ // known-bug: #104800 -#![feature(dyn_star)] +#![feature(dyn_star, trait_upcasting)] trait Foo: Bar { fn hello(&self); diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr index bdf77da713a0e..adef9525bf1fa 100644 --- a/tests/ui/dyn-star/upcast.stderr +++ b/tests/ui/dyn-star/upcast.stderr @@ -1,7 +1,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/upcast.rs:3:12 | -LL | #![feature(dyn_star)] +LL | #![feature(dyn_star, trait_upcasting)] | ^^^^^^^^ | = note: see issue #102425 for more information diff --git a/tests/ui/dynamically-sized-types/dst-coercions.rs b/tests/ui/dynamically-sized-types/dst-coercions.rs index 66688e93fb80d..1efdf1de0e61c 100644 --- a/tests/ui/dynamically-sized-types/dst-coercions.rs +++ b/tests/ui/dynamically-sized-types/dst-coercions.rs @@ -5,7 +5,7 @@ // pretty-expanded FIXME #23616 struct S; -trait T { fn dummy(&self) { } } +trait T { fn dummy(&self) { } } //~ WARN method `dummy` is never used impl T for S {} pub fn main() { diff --git a/tests/ui/dynamically-sized-types/dst-coercions.stderr b/tests/ui/dynamically-sized-types/dst-coercions.stderr new file mode 100644 index 0000000000000..e4721ce50a045 --- /dev/null +++ b/tests/ui/dynamically-sized-types/dst-coercions.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/dst-coercions.rs:8:14 + | +LL | trait T { fn dummy(&self) { } } + | - ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/empty-type-parameter-list.rs b/tests/ui/empty-type-parameter-list.rs index e168cd03b2746..23d09fbf281d0 100644 --- a/tests/ui/empty-type-parameter-list.rs +++ b/tests/ui/empty-type-parameter-list.rs @@ -3,7 +3,7 @@ // no type parameters at all struct S<>; -trait T<> {} +trait T<> {} //~ WARN trait `T` is never used enum E<> { V } impl<> T<> for S<> {} impl T for E {} diff --git a/tests/ui/empty-type-parameter-list.stderr b/tests/ui/empty-type-parameter-list.stderr new file mode 100644 index 0000000000000..31a5015e99349 --- /dev/null +++ b/tests/ui/empty-type-parameter-list.stderr @@ -0,0 +1,10 @@ +warning: trait `T` is never used + --> $DIR/empty-type-parameter-list.rs:6:7 + | +LL | trait T<> {} + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr b/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr index fac3ce07aeb92..1341b03cb56e4 100644 --- a/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr +++ b/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr @@ -6,14 +6,14 @@ LL | Some = std::mem::size_of::(), | = note: type parameters may not be used in enum discriminant values -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-70453-generics-in-discr-ice.rs:7:20 | LL | enum MyWeirdOption { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/enum-discriminant/issue-72554.rs b/tests/ui/enum-discriminant/issue-72554.rs index 54f7e9ac592eb..1fe9a5f4faa7d 100644 --- a/tests/ui/enum-discriminant/issue-72554.rs +++ b/tests/ui/enum-discriminant/issue-72554.rs @@ -3,6 +3,7 @@ use std::collections::BTreeSet; #[derive(Hash)] pub enum ElemDerived { //~^ ERROR recursive type `ElemDerived` has infinite size + //~| ERROR cycle detected A(ElemDerived) } diff --git a/tests/ui/enum-discriminant/issue-72554.stderr b/tests/ui/enum-discriminant/issue-72554.stderr index 381f24d351e9c..648680c6031da 100644 --- a/tests/ui/enum-discriminant/issue-72554.stderr +++ b/tests/ui/enum-discriminant/issue-72554.stderr @@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size | LL | pub enum ElemDerived { | ^^^^^^^^^^^^^^^^^^^^ -LL | +... LL | A(ElemDerived) | ----------- recursive without indirection | @@ -12,6 +12,21 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | A(Box) | ++++ + -error: aborting due to 1 previous error +error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived` + --> $DIR/issue-72554.rs:4:1 + | +LL | pub enum ElemDerived { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again +note: cycle used when computing drop-check constraints for `Elem` + --> $DIR/issue-72554.rs:11:1 + | +LL | pub enum Elem { + | ^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0072`. +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/enum/issue-67945-1.stderr b/tests/ui/enum/issue-67945-1.stderr index 878fa322f02d5..ce0ea77763663 100644 --- a/tests/ui/enum/issue-67945-1.stderr +++ b/tests/ui/enum/issue-67945-1.stderr @@ -6,14 +6,14 @@ LL | let x: S = 0; | = note: type parameters may not be used in enum discriminant values -error[E0392]: parameter `S` is never used +error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-1.rs:1:10 | LL | enum Bug { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead + = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/enum/issue-67945-2.stderr b/tests/ui/enum/issue-67945-2.stderr index f8ec12d470acf..96bd08f841a40 100644 --- a/tests/ui/enum/issue-67945-2.stderr +++ b/tests/ui/enum/issue-67945-2.stderr @@ -6,14 +6,14 @@ LL | Var = type_ascribe!(0, S), | = note: type parameters may not be used in enum discriminant values -error[E0392]: parameter `S` is never used +error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-2.rs:3:10 | LL | enum Bug { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead + = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/error-codes/E0091.stderr b/tests/ui/error-codes/E0091.stderr index a596b75e481de..c1427ec66863a 100644 --- a/tests/ui/error-codes/E0091.stderr +++ b/tests/ui/error-codes/E0091.stderr @@ -1,14 +1,20 @@ -error[E0091]: type parameter `T` is unused +error[E0091]: type parameter `T` is never used --> $DIR/E0091.rs:1:10 | LL | type Foo = u32; | ^ unused type parameter + | + = help: consider removing `T` or referring to it in the body of the type alias + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error[E0091]: type parameter `B` is unused +error[E0091]: type parameter `B` is never used --> $DIR/E0091.rs:2:14 | LL | type Foo2 = Box; | ^ unused type parameter + | + = help: consider removing `B` or referring to it in the body of the type alias + = help: if you intended `B` to be a const parameter, use `const B: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/error-codes/E0277-2.stderr b/tests/ui/error-codes/E0277-2.stderr index 9a262f7559075..f4e18e3bb539c 100644 --- a/tests/ui/error-codes/E0277-2.stderr +++ b/tests/ui/error-codes/E0277-2.stderr @@ -4,7 +4,7 @@ error[E0277]: `*const u8` cannot be sent between threads safely LL | is_send::(); | ^^^ `*const u8` cannot be sent between threads safely | - = help: within `Foo`, the trait `Send` is not implemented for `*const u8` + = help: within `Foo`, the trait `Send` is not implemented for `*const u8`, which is required by `Foo: Send` note: required because it appears within the type `Baz` --> $DIR/E0277-2.rs:9:8 | diff --git a/tests/ui/error-codes/E0277.stderr b/tests/ui/error-codes/E0277.stderr index 0b0d2b09720cd..aeb97290cf856 100644 --- a/tests/ui/error-codes/E0277.stderr +++ b/tests/ui/error-codes/E0277.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | - = help: within `Path`, the trait `Sized` is not implemented for `[u8]` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized` note: required because it appears within the type `Path` --> $SRC_DIR/std/src/path.rs:LL:COL = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/error-codes/E0283.stderr b/tests/ui/error-codes/E0283.stderr index 6008809f050f8..fc08395a2b0df 100644 --- a/tests/ui/error-codes/E0283.stderr +++ b/tests/ui/error-codes/E0283.stderr @@ -5,7 +5,7 @@ LL | fn create() -> u32; | ------------------- `Coroutine::create` defined here ... LL | let cont: u32 = Coroutine::create(); - | ^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation | diff --git a/tests/ui/error-codes/E0392.stderr b/tests/ui/error-codes/E0392.stderr index ecbfd5584d5a3..9971267e9270d 100644 --- a/tests/ui/error-codes/E0392.stderr +++ b/tests/ui/error-codes/E0392.stderr @@ -1,11 +1,11 @@ -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/E0392.rs:1:10 | LL | enum Foo { Bar } - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr index d27fade487fe2..754867061c7f8 100644 --- a/tests/ui/error-codes/E0401.stderr +++ b/tests/ui/error-codes/E0401.stderr @@ -20,7 +20,7 @@ LL | fn baz $DIR/E0401.rs:24:25 | LL | impl Iterator for A { @@ -29,7 +29,7 @@ LL | impl Iterator for A { LL | fn helper(sel: &Self) -> u8 { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | refer to the type directly here instead error[E0283]: type annotations needed diff --git a/tests/ui/error-codes/E0790.stderr b/tests/ui/error-codes/E0790.stderr index f559abae39780..6338a10b6af9d 100644 --- a/tests/ui/error-codes/E0790.stderr +++ b/tests/ui/error-codes/E0790.stderr @@ -5,7 +5,7 @@ LL | fn my_fn(); | ----------- `MyTrait::my_fn` defined here ... LL | MyTrait::my_fn(); - | ^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | @@ -33,7 +33,7 @@ LL | fn my_fn(); | ----------- `MyTrait::my_fn` defined here ... LL | inner::MyTrait::my_fn(); - | ^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | @@ -61,7 +61,7 @@ LL | fn my_fn(); | ----------- `MyTrait2::my_fn` defined here ... LL | MyTrait2::my_fn(); - | ^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation | diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr index 9228a047e8785..bd4e934822751 100644 --- a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr +++ b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:53:46 | LL | want(Wrapper { value: Burrito { filling: q } }); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | | | required by a bound introduced by this call | @@ -38,7 +38,7 @@ LL | want(Some(())); | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()`, which is required by `Option<()>: T1` = help: the trait `T1` is implemented for `Option` note: required for `Option<()>` to implement `T1` --> $DIR/blame-trait-error.rs:21:20 @@ -109,7 +109,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:65:45 | LL | want(&ExampleTuple::ExampleTupleVariant(q)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple: T1` | | | required by a bound introduced by this call | @@ -134,7 +134,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:68:31 | LL | want(&ExampleTupleVariant(q)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple: T1` | | | required by a bound introduced by this call | @@ -159,7 +159,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:71:50 | LL | want(&ExampleOtherTuple::ExampleTupleVariant(q)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple: T1` | | | required by a bound introduced by this call | @@ -184,7 +184,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:74:44 | LL | want(&ExampleDifferentTupleVariantName(q)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple: T1` | | | required by a bound introduced by this call | @@ -209,7 +209,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:77:45 | LL | want(&ExampleYetAnotherTupleVariantName(q)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple: T1` | | | required by a bound introduced by this call | @@ -234,7 +234,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:80:56 | LL | want(&ExampleStruct::ExampleStructVariant { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct: T1` | note: required for `ExampleStruct` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -257,7 +257,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:83:41 | LL | want(&ExampleStructVariant { field: q }); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct: T1` | | | required by a bound introduced by this call | @@ -282,7 +282,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:86:61 | LL | want(&ExampleOtherStruct::ExampleStructVariant { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct: T1` | note: required for `ExampleStruct` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -305,7 +305,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:89:54 | LL | want(&ExampleDifferentStructVariantName { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct: T1` | note: required for `ExampleStruct` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -328,7 +328,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:92:55 | LL | want(&ExampleYetAnotherStructVariantName { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct: T1` | note: required for `ExampleStruct` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -351,7 +351,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:95:38 | LL | want(&ExampleActuallyTupleStruct(q, 0)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleActuallyTupleStruct: T1` | | | required by a bound introduced by this call | @@ -376,7 +376,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:98:43 | LL | want(&ExampleActuallyTupleStructOther(q, 0)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleActuallyTupleStruct: T1` | | | required by a bound introduced by this call | diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr index b6a24e12bcc76..a2df6843f43b9 100644 --- a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr +++ b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:81:60 | LL | want(Wrapper { value: Burrito { spicy: false, filling: q } }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | note: required for `Burrito` to implement `T2` --> $DIR/blame-trait-error-spans-on-exprs.rs:22:13 @@ -32,7 +32,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:85:84 | LL | want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | note: required for `BurritoKinds` to implement `T2` --> $DIR/blame-trait-error-spans-on-exprs.rs:32:13 @@ -62,7 +62,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:89:39 | LL | want(Wrapper { value: Taco(false, q) }); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | | | required by a bound introduced by this call | @@ -94,7 +94,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:93:53 | LL | want(Wrapper { value: TacoKinds::OneTaco(false, q) }); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | | | required by a bound introduced by this call | @@ -126,7 +126,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:97:74 | LL | want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | note: required for `GenericBurrito` to implement `T2` --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16 @@ -156,7 +156,7 @@ error[E0277]: the trait bound `Q: T2` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:101:14 | LL | want((3, q)); - | ---- ^ the trait `T2` is not implemented for `Q` + | ---- ^ the trait `T2` is not implemented for `Q`, which is required by `({integer}, Q): T1` | | | required by a bound introduced by this call | @@ -181,7 +181,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:105:31 | LL | want(Wrapper { value: (3, q) }); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<({integer}, Q)>: T1` | | | required by a bound introduced by this call | @@ -213,7 +213,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:109:15 | LL | want(((3, q), 5)); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `(({integer}, Q), {integer}): T1` | | | required by a bound introduced by this call | @@ -245,7 +245,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:112:49 | LL | want(DoubleWrapper { item: Wrapper { value: q } }); - | ---- ^ the trait `T1` is not implemented for `Q` + | ---- ^ the trait `T1` is not implemented for `Q`, which is required by `DoubleWrapper: T1` | | | required by a bound introduced by this call | @@ -270,7 +270,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:115:88 | LL | want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } }); - | ---- required by a bound introduced by this call ^ the trait `T1` is not implemented for `Q` + | ---- required by a bound introduced by this call ^ the trait `T1` is not implemented for `Q`, which is required by `DoubleWrapper>: T1` | note: required for `DoubleWrapper` to implement `T1` --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13 @@ -295,7 +295,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:119:27 | LL | want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } }); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper>: T1` | | | required by a bound introduced by this call | @@ -327,7 +327,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:122:35 | LL | want(Two { a: Two { a: (), b: q }, b: () }); - | ---- ^ the trait `T1` is not implemented for `Q` + | ---- ^ the trait `T1` is not implemented for `Q`, which is required by `Two, ()>: T1` | | | required by a bound introduced by this call | @@ -354,7 +354,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied LL | want( | ---- required by a bound introduced by this call LL | Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () }, - | ^ the trait `T1` is not implemented for `Q` + | ^ the trait `T1` is not implemented for `Q`, which is required by `Two, ()>>, ()>: T1` | note: required for `Two, ()>` to implement `T1` --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19 @@ -379,7 +379,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:133:44 | LL | want(&Burrito { spicy: false, filling: q }); - | ---- ^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&Burrito: T1` | | | required by a bound introduced by this call | diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed index bb093a4af4a3e..3c71587c8e399 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![allow(dropping_references)] struct Foo { diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs index 1a9f89c054f39..075d4cbe02b31 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![allow(dropping_references)] struct Foo { diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr index d2d69ce6daf72..13b6ee9987e88 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -1,5 +1,5 @@ error[E0040]: explicit use of destructor method - --> $DIR/explicit-call-to-supertrait-dtor.rs:22:14 + --> $DIR/explicit-call-to-supertrait-dtor.rs:23:14 | LL | self.drop(); | ^^^^ explicit destructor calls not allowed diff --git a/tests/ui/extenv/issue-55897.rs b/tests/ui/extenv/issue-55897.rs index b7533f41351da..b6500e5405933 100644 --- a/tests/ui/extenv/issue-55897.rs +++ b/tests/ui/extenv/issue-55897.rs @@ -4,7 +4,6 @@ mod unresolved_env { use env; //~ ERROR unresolved import `env` include!(concat!(env!("NON_EXISTENT"), "/data.rs")); - //~^ ERROR cannot determine resolution for the macro `env` } mod nonexistent_env { diff --git a/tests/ui/extenv/issue-55897.stderr b/tests/ui/extenv/issue-55897.stderr index 401db827813a9..2e8c05cca867f 100644 --- a/tests/ui/extenv/issue-55897.stderr +++ b/tests/ui/extenv/issue-55897.stderr @@ -1,5 +1,5 @@ error: environment variable `NON_EXISTENT` not defined at compile time - --> $DIR/issue-55897.rs:11:22 + --> $DIR/issue-55897.rs:10:22 | LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: suffixes on string literals are invalid - --> $DIR/issue-55897.rs:16:22 + --> $DIR/issue-55897.rs:15:22 | LL | include!(concat!("NON_EXISTENT"suffix, "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ invalid suffix `suffix` @@ -33,14 +33,6 @@ help: consider importing this module instead LL | use std::env; | ~~~~~~~~ -error: cannot determine resolution for the macro `env` - --> $DIR/issue-55897.rs:6:22 - | -LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); - | ^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/extern/auxiliary/issue-80074-macro-2.rs b/tests/ui/extern/auxiliary/issue-80074-macro-2.rs new file mode 100644 index 0000000000000..bc87a2b543478 --- /dev/null +++ b/tests/ui/extern/auxiliary/issue-80074-macro-2.rs @@ -0,0 +1,3 @@ +// edition:2018 + +macro_rules! m { () => {}; } diff --git a/tests/ui/extern/auxiliary/issue-80074-macro.rs b/tests/ui/extern/auxiliary/issue-80074-macro.rs index 30e0f19ab8d84..3e912d977159a 100644 --- a/tests/ui/extern/auxiliary/issue-80074-macro.rs +++ b/tests/ui/extern/auxiliary/issue-80074-macro.rs @@ -2,3 +2,5 @@ macro_rules! foo_ { () => {}; } use foo_ as foo; + +macro_rules! bar { () => {}; } diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr index a79caced111bb..7428e6a60b520 100644 --- a/tests/ui/extern/extern-types-unsized.stderr +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -5,11 +5,11 @@ LL | assert_sized::(); | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `A` -note: required by a bound in `assert_sized` +note: required by an implicit `Sized` bound in `assert_sized` --> $DIR/extern-types-unsized.rs:19:17 | LL | fn assert_sized() {} - | ^ required by this bound in `assert_sized` + | ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized` help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() {} @@ -21,17 +21,17 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim LL | assert_sized::(); | ^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `Sized` is not implemented for `A` + = help: within `Foo`, the trait `Sized` is not implemented for `A`, which is required by `Foo: Sized` note: required because it appears within the type `Foo` --> $DIR/extern-types-unsized.rs:9:8 | LL | struct Foo { | ^^^ -note: required by a bound in `assert_sized` +note: required by an implicit `Sized` bound in `assert_sized` --> $DIR/extern-types-unsized.rs:19:17 | LL | fn assert_sized() {} - | ^ required by this bound in `assert_sized` + | ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized` help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() {} @@ -43,17 +43,17 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim LL | assert_sized::>(); | ^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar`, the trait `Sized` is not implemented for `A` + = help: within `Bar`, the trait `Sized` is not implemented for `A`, which is required by `Bar: Sized` note: required because it appears within the type `Bar` --> $DIR/extern-types-unsized.rs:14:8 | LL | struct Bar { | ^^^ -note: required by a bound in `assert_sized` +note: required by an implicit `Sized` bound in `assert_sized` --> $DIR/extern-types-unsized.rs:19:17 | LL | fn assert_sized() {} - | ^ required by this bound in `assert_sized` + | ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized` help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() {} @@ -65,17 +65,17 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim LL | assert_sized::>>(); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar>`, the trait `Sized` is not implemented for `A` + = help: within `Bar>`, the trait `Sized` is not implemented for `A`, which is required by `Bar>: Sized` note: required because it appears within the type `Bar` --> $DIR/extern-types-unsized.rs:14:8 | LL | struct Bar { | ^^^ -note: required by a bound in `assert_sized` +note: required by an implicit `Sized` bound in `assert_sized` --> $DIR/extern-types-unsized.rs:19:17 | LL | fn assert_sized() {} - | ^ required by this bound in `assert_sized` + | ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized` help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() {} diff --git a/tests/ui/extern/issue-80074.rs b/tests/ui/extern/issue-80074.rs index f83027d4abfd2..6e4f176de8201 100644 --- a/tests/ui/extern/issue-80074.rs +++ b/tests/ui/extern/issue-80074.rs @@ -1,10 +1,20 @@ // edition:2018 -// build-pass // aux-crate:issue_80074=issue-80074-macro.rs +// aux-crate:issue_80074_2=issue-80074-macro-2.rs #[macro_use] extern crate issue_80074; +#[macro_use(m)] +extern crate issue_80074_2; +//~^^ ERROR: imported macro not found + fn main() { foo!(); + //~^ WARN: macro `foo` is private + //~| WARN: it will become a hard error in a future release! + bar!(); + //~^ ERROR: cannot find macro `bar` in this scope + m!(); + //~^ ERROR: cannot find macro `m` in this scope } diff --git a/tests/ui/extern/issue-80074.stderr b/tests/ui/extern/issue-80074.stderr new file mode 100644 index 0000000000000..b30b761593e88 --- /dev/null +++ b/tests/ui/extern/issue-80074.stderr @@ -0,0 +1,31 @@ +error[E0469]: imported macro not found + --> $DIR/issue-80074.rs:8:13 + | +LL | #[macro_use(m)] + | ^ + +error: cannot find macro `bar` in this scope + --> $DIR/issue-80074.rs:16:5 + | +LL | bar!(); + | ^^^ + +error: cannot find macro `m` in this scope + --> $DIR/issue-80074.rs:18:5 + | +LL | m!(); + | ^ + +warning: macro `foo` is private + --> $DIR/issue-80074.rs:13:5 + | +LL | foo!(); + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120192 + = note: `#[warn(private_macro_use)]` on by default + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0469`. diff --git a/tests/ui/extern/no-mangle-associated-fn.rs b/tests/ui/extern/no-mangle-associated-fn.rs index ecd44abbf264c..56afd8b90926e 100644 --- a/tests/ui/extern/no-mangle-associated-fn.rs +++ b/tests/ui/extern/no-mangle-associated-fn.rs @@ -12,7 +12,7 @@ impl Foo { } } -trait Bar { +trait Bar { //~ WARN trait `Bar` is never used fn qux() -> u8; } diff --git a/tests/ui/extern/no-mangle-associated-fn.stderr b/tests/ui/extern/no-mangle-associated-fn.stderr new file mode 100644 index 0000000000000..772cbf6cf7dd7 --- /dev/null +++ b/tests/ui/extern/no-mangle-associated-fn.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/no-mangle-associated-fn.rs:15:7 + | +LL | trait Bar { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-abi_amdgpu_kernel.rs b/tests/ui/feature-gates/feature-gate-abi_amdgpu_kernel.rs deleted file mode 100644 index 465b81d7fe33c..0000000000000 --- a/tests/ui/feature-gates/feature-gate-abi_amdgpu_kernel.rs +++ /dev/null @@ -1,30 +0,0 @@ -// compile-flags: --crate-type=rlib -#![no_core] -#![feature(no_core, lang_items)] -#[lang="sized"] -trait Sized { } - -extern "amdgpu-kernel" fn fu() {} //~ ERROR amdgpu-kernel ABI is experimental -//~^ ERROR is not a supported ABI - -trait T { - extern "amdgpu-kernel" fn mu(); //~ ERROR amdgpu-kernel ABI is experimental - extern "amdgpu-kernel" fn dmu() {} //~ ERROR amdgpu-kernel ABI is experimental - //~^ ERROR is not a supported ABI -} - -struct S; -impl T for S { - extern "amdgpu-kernel" fn mu() {} //~ ERROR amdgpu-kernel ABI is experimental - //~^ ERROR is not a supported ABI -} - -impl S { - extern "amdgpu-kernel" fn imu() {} //~ ERROR amdgpu-kernel ABI is experimental - //~^ ERROR is not a supported ABI -} - -type TAU = extern "amdgpu-kernel" fn(); //~ ERROR amdgpu-kernel ABI is experimental - -extern "amdgpu-kernel" {} //~ ERROR amdgpu-kernel ABI is experimental -//~^ ERROR is not a supported ABI diff --git a/tests/ui/feature-gates/feature-gate-abi_amdgpu_kernel.stderr b/tests/ui/feature-gates/feature-gate-abi_amdgpu_kernel.stderr deleted file mode 100644 index c5ae52c789b67..0000000000000 --- a/tests/ui/feature-gates/feature-gate-abi_amdgpu_kernel.stderr +++ /dev/null @@ -1,104 +0,0 @@ -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:7:8 - | -LL | extern "amdgpu-kernel" fn fu() {} - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:11:12 - | -LL | extern "amdgpu-kernel" fn mu(); - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:12:12 - | -LL | extern "amdgpu-kernel" fn dmu() {} - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:18:12 - | -LL | extern "amdgpu-kernel" fn mu() {} - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:23:12 - | -LL | extern "amdgpu-kernel" fn imu() {} - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:27:19 - | -LL | type TAU = extern "amdgpu-kernel" fn(); - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:29:8 - | -LL | extern "amdgpu-kernel" {} - | ^^^^^^^^^^^^^^^ - | - = note: see issue #51575 for more information - = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:29:1 - | -LL | extern "amdgpu-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:7:1 - | -LL | extern "amdgpu-kernel" fn fu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:12:5 - | -LL | extern "amdgpu-kernel" fn dmu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:18:5 - | -LL | extern "amdgpu-kernel" fn mu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_amdgpu_kernel.rs:23:5 - | -LL | extern "amdgpu-kernel" fn imu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 12 previous errors - -Some errors have detailed explanations: E0570, E0658. -For more information about an error, try `rustc --explain E0570`. diff --git a/tests/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr b/tests/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr index d05971fb0529d..5e3d34aa9f3ed 100644 --- a/tests/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr +++ b/tests/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr @@ -7,6 +7,7 @@ LL | 0 .. 3 => {} = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-feature-gate.stderr b/tests/ui/feature-gates/feature-gate-feature-gate.stderr index 8ff99ddbe2188..6ca6c04e40181 100644 --- a/tests/ui/feature-gates/feature-gate-feature-gate.stderr +++ b/tests/ui/feature-gates/feature-gate-feature-gate.stderr @@ -1,4 +1,4 @@ -error: unstable feature +error: use of an unstable feature --> $DIR/feature-gate-feature-gate.rs:2:12 | LL | #![feature(intrinsics)] diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs deleted file mode 100644 index f354534356c21..0000000000000 --- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![crate_type = "lib"] - -extern "C" { - #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature - pub fn foo(); -} diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr deleted file mode 100644 index 8d19874c36a0c..0000000000000 --- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature - --> $DIR/feature-gate-ffi_returns_twice.rs:4:5 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #58314 for more information - = help: add `#![feature(ffi_returns_twice)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-never_type.rs b/tests/ui/feature-gates/feature-gate-never_type.rs index be8c27dbb1b02..f5d28a4877fdf 100644 --- a/tests/ui/feature-gates/feature-gate-never_type.rs +++ b/tests/ui/feature-gates/feature-gate-never_type.rs @@ -13,5 +13,14 @@ impl Foo for Meeshka { type Wub = !; //~ ERROR type is experimental } +fn look_ma_no_feature_gate !>() {} //~ ERROR type is experimental +fn tadam(f: &dyn Fn() -> !) {} //~ ERROR type is experimental +fn panic() -> ! { + panic!(); +} +fn toudoum() -> impl Fn() -> ! { //~ ERROR type is experimental + panic +} + fn main() { } diff --git a/tests/ui/feature-gates/feature-gate-never_type.stderr b/tests/ui/feature-gates/feature-gate-never_type.stderr index 0fca58519ce13..33e4e019b18d3 100644 --- a/tests/ui/feature-gates/feature-gate-never_type.stderr +++ b/tests/ui/feature-gates/feature-gate-never_type.stderr @@ -48,6 +48,36 @@ LL | type Wub = !; = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors +error[E0658]: the `!` type is experimental + --> $DIR/feature-gate-never_type.rs:16:43 + | +LL | fn look_ma_no_feature_gate !>() {} + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `!` type is experimental + --> $DIR/feature-gate-never_type.rs:17:26 + | +LL | fn tadam(f: &dyn Fn() -> !) {} + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `!` type is experimental + --> $DIR/feature-gate-never_type.rs:21:30 + | +LL | fn toudoum() -> impl Fn() -> ! { + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs index e19dcf9f6a54c..1f2f7ee1e1919 100644 --- a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs +++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr index 02ee54e8607ac..fc7dd7923f7a8 100644 --- a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr +++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr @@ -13,7 +13,7 @@ error[E0658]: using enums in offset_of is experimental LL | offset_of!(Alpha, One); | ^^^ | - = note: see issue #106655 for more information + = note: see issue #120141 for more information = help: add `#![feature(offset_of_enum)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -29,7 +29,7 @@ error[E0658]: using enums in offset_of is experimental LL | offset_of!(Alpha, Two.0); | ^^^ | - = note: see issue #106655 for more information + = note: see issue #120141 for more information = help: add `#![feature(offset_of_enum)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.rs b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs new file mode 100644 index 0000000000000..c4eb4720fde5e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs @@ -0,0 +1,28 @@ +#![feature(offset_of_enum)] + +use std::mem::offset_of; + +struct S { + a: u8, + b: (u8, u8), + c: T, +} + +struct T { + t: &'static str, +} + +enum Alpha { + One(u8), + Two(u8), +} + +fn main() { + offset_of!(Alpha, Two.0); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!(S, a); + offset_of!((u8, S), 1); + offset_of!((u32, (S, T)), 1.1); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!(S, b.0); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!((S, ()), 0.c); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!(S, c.t); //~ ERROR only a single ident or integer is stable as the field in offset_of +} diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr new file mode 100644 index 0000000000000..f367fc9fa0dd4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr @@ -0,0 +1,60 @@ +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:21:27 + | +LL | offset_of!(Alpha, Two.0); + | ^ + | + = note: see issue #120140 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:24:33 + | +LL | offset_of!((u32, (S, T)), 1.1); + | _____----------------------------^- + | | | + | | in this macro invocation +LL | | offset_of!(S, b.0); +LL | | offset_of!((S, ()), 0.c); +LL | | offset_of!(S, c.t); +... | + | + = note: see issue #120140 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:25:21 + | +LL | offset_of!(S, b.0); + | ^ + | + = note: see issue #120140 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:26:27 + | +LL | offset_of!((S, ()), 0.c); + | ^ + | + = note: see issue #120140 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:27:21 + | +LL | offset_of!(S, c.t); + | ^ + | + = note: see issue #120140 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.rs b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs new file mode 100644 index 0000000000000..e4102f1cfa75d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs @@ -0,0 +1,13 @@ +trait Foo {} + +trait Bar: Foo {} + +impl Foo for () {} + +impl Bar for () {} + +fn main() { + let bar: &dyn Bar = &(); + let foo: &dyn Foo = bar; + //~^ ERROR trait upcasting coercion is experimental [E0658] +} diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr new file mode 100644 index 0000000000000..6fd277ae8cc3e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr @@ -0,0 +1,14 @@ +error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental + --> $DIR/feature-gate-trait_upcasting.rs:11:25 + | +LL | let foo: &dyn Foo = bar; + | ^^^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required when coercing `&dyn Bar` into `&dyn Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index 1b87ebd9f20ce..7fc726409ce40 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -94,7 +94,7 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at LL | fn unsized_local() where Dst: Sized { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)` + = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)`, which is required by `Dst<(dyn A + 'static)>: Sized` note: required because it appears within the type `Dst<(dyn A + 'static)>` --> $DIR/feature-gate-trivial_bounds.rs:48:8 | diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs index 134ea25b75afb..594a2672d435d 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs @@ -7,7 +7,7 @@ use core::{marker::PhantomPinned, pin::Pin}; /// The `unsafe_pin_internals` is indeed unsound. fn non_unsafe_pin_new_unchecked(pointer: &mut T) -> Pin<&mut T> { - Pin { pointer } + Pin { __pointer: pointer } } fn main() { diff --git a/tests/ui/feature-gates/issue-43106-gating-of-bench.rs b/tests/ui/feature-gates/issue-43106-gating-of-bench.rs index 796325b79af66..841383a008f54 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-bench.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-bench.rs @@ -5,6 +5,5 @@ #![feature(custom_inner_attributes)] #![bench = "4100"] -//~^ ERROR cannot determine resolution for the attribute macro `bench` -//~^^ ERROR `bench` attribute cannot be used at crate level +//~^ ERROR `bench` attribute cannot be used at crate level fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr b/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr index 8270d46d492a9..912c2746f3835 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr @@ -1,17 +1,9 @@ -error: cannot determine resolution for the attribute macro `bench` - --> $DIR/issue-43106-gating-of-bench.rs:7:4 - | -LL | #![bench = "4100"] - | ^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: `bench` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-bench.rs:7:1 | LL | #![bench = "4100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | fn main() {} | ---- the inner attribute doesn't annotate this function | @@ -21,5 +13,5 @@ LL - #![bench = "4100"] LL + #[bench = "4100"] | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/issue-43106-gating-of-test.rs b/tests/ui/feature-gates/issue-43106-gating-of-test.rs index 39835c9268eef..38c92d933fdd8 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-test.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-test.rs @@ -2,6 +2,5 @@ #![allow(soft_unstable)] #![test = "4200"] -//~^ ERROR cannot determine resolution for the attribute macro `test` -//~^^ ERROR `test` attribute cannot be used at crate level +//~^ ERROR `test` attribute cannot be used at crate level fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-test.stderr b/tests/ui/feature-gates/issue-43106-gating-of-test.stderr index 922c9861aa3c1..2fc220dc47bd1 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-test.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-test.stderr @@ -1,17 +1,9 @@ -error: cannot determine resolution for the attribute macro `test` - --> $DIR/issue-43106-gating-of-test.rs:4:4 - | -LL | #![test = "4200"] - | ^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: `test` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-test.rs:4:1 | LL | #![test = "4200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | fn main() {} | ---- the inner attribute doesn't annotate this function | @@ -21,5 +13,5 @@ LL - #![test = "4200"] LL + #[test = "4200"] | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/ffi_returns_twice.rs b/tests/ui/ffi_returns_twice.rs deleted file mode 100644 index 8195d0e486369..0000000000000 --- a/tests/ui/ffi_returns_twice.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(ffi_returns_twice)] -#![crate_type = "lib"] - -#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions -pub fn foo() {} - -#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions -macro_rules! bar { - () => () -} - -extern "C" { - #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions - static INT: i32; -} diff --git a/tests/ui/ffi_returns_twice.stderr b/tests/ui/ffi_returns_twice.stderr deleted file mode 100644 index 0abe7613f1493..0000000000000 --- a/tests/ui/ffi_returns_twice.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:4:1 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:7:1 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:13:5 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0724`. diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index c0650ff17c5ed..58531c61bbe80 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: UpperHex` is not satisfied --> $DIR/ifmt-unimpl.rs:2:21 | LL | format!("{:X}", "3"); - | ---- ^^^ the trait `UpperHex` is not implemented for `str` + | ---- ^^^ the trait `UpperHex` is not implemented for `str`, which is required by `&str: UpperHex` | | | required by a bound introduced by this call | diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index 6c9c7941eb339..aa377553c5041 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -6,7 +6,7 @@ LL | send(format_args!("{:?}", c)); | | | required by a bound introduced by this call | - = help: within `[core::fmt::rt::Argument<'_>]`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque` + = help: within `[core::fmt::rt::Argument<'_>]`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque`, which is required by `Arguments<'_>: Send` = note: required because it appears within the type `&core::fmt::rt::Opaque` note: required because it appears within the type `core::fmt::rt::Argument<'_>` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL @@ -28,7 +28,7 @@ LL | sync(format_args!("{:?}", c)); | | | required by a bound introduced by this call | - = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque` + = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque`, which is required by `Arguments<'_>: Sync` = note: required because it appears within the type `&core::fmt::rt::Opaque` note: required because it appears within the type `core::fmt::rt::Argument<'_>` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL diff --git a/tests/ui/for-loop-while/issue-69841.rs b/tests/ui/for-loop-while/issue-69841.rs index 1aca16ca80451..942b99b742bc6 100644 --- a/tests/ui/for-loop-while/issue-69841.rs +++ b/tests/ui/for-loop-while/issue-69841.rs @@ -2,7 +2,6 @@ // LLVM bug which needed a fix to be backported. // run-pass -// no-system-llvm fn main() { let buffer = [49u8, 10]; diff --git a/tests/ui/for/for-c-in-str.stderr b/tests/ui/for/for-c-in-str.stderr index 475cf8c887491..2544df646299b 100644 --- a/tests/ui/for/for-c-in-str.stderr +++ b/tests/ui/for/for-c-in-str.stderr @@ -4,7 +4,7 @@ error[E0277]: `&str` is not an iterator LL | for c in "asdf" { | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `Iterator` is not implemented for `&str` + = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator` = note: required for `&str` to implement `IntoIterator` error: aborting due to 1 previous error diff --git a/tests/ui/for/for-loop-bogosity.stderr b/tests/ui/for/for-loop-bogosity.stderr index 194a2fa08ceab..143e4a4efd1f0 100644 --- a/tests/ui/for/for-loop-bogosity.stderr +++ b/tests/ui/for/for-loop-bogosity.stderr @@ -4,7 +4,7 @@ error[E0277]: `MyStruct` is not an iterator LL | for x in bogus { | ^^^^^ `MyStruct` is not an iterator | - = help: the trait `Iterator` is not implemented for `MyStruct` + = help: the trait `Iterator` is not implemented for `MyStruct`, which is required by `MyStruct: IntoIterator` = note: required for `MyStruct` to implement `IntoIterator` error: aborting due to 1 previous error diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr index 28dbdf4c374c0..3d753b9c8b884 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/for/issue-20605.next.stderr @@ -34,15 +34,11 @@ error: the type `&mut as IntoIterator>::IntoIte LL | for item in *things { *item = 0 } | ^^^^^^^ -error[E0277]: the size for values of type `< as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time - --> $DIR/issue-20605.rs:5:9 +error: the type `Option<< as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed + --> $DIR/issue-20605.rs:5:17 | LL | for item in *things { *item = 0 } - | ^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `< as IntoIterator>::IntoIter as Iterator>::Item` - = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature + | ^^^^^^^ error[E0277]: the size for values of type `< as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time --> $DIR/issue-20605.rs:5:5 @@ -54,11 +50,15 @@ LL | for item in *things { *item = 0 } note: required by a bound in `None` --> $SRC_DIR/core/src/option.rs:LL:COL -error: the type `Option<< as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed - --> $DIR/issue-20605.rs:5:17 +error[E0277]: the size for values of type `< as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time + --> $DIR/issue-20605.rs:5:9 | LL | for item in *things { *item = 0 } - | ^^^^^^^ + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `< as IntoIterator>::IntoIter as Iterator>::Item` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0614]: type `< as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced --> $DIR/issue-20605.rs:5:27 diff --git a/tests/ui/function-pointer/unsized-ret.stderr b/tests/ui/function-pointer/unsized-ret.stderr index 66116273ff4d6..81d603f4b20e3 100644 --- a/tests/ui/function-pointer/unsized-ret.stderr +++ b/tests/ui/function-pointer/unsized-ret.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo:: str, _>(None, ()); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> str`, the trait `Sized` is not implemented for `str` + = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`, which is required by `fn() -> str: Fn<_>` = note: required because it appears within the type `fn() -> str` note: required by a bound in `foo` --> $DIR/unsized-ret.rs:5:11 @@ -18,7 +18,7 @@ error[E0277]: the size for values of type `(dyn std::fmt::Display + 'a)` cannot LL | foo:: fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&(),)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)` + = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`, which is required by `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a): Fn<_>` = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)` note: required by a bound in `foo` --> $DIR/unsized-ret.rs:5:11 diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.stderr index 685c2794967b2..314a5509da8bc 100644 --- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.stderr +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `::Bar<()>: Eq` is not satisfied --> $DIR/assume-gat-normalization-for-nested-goals.rs:6:30 | LL | type Bar: Baz = i32; - | ^^^ the trait `Eq` is not implemented for `::Bar<()>` + | ^^^ the trait `Eq` is not implemented for `::Bar<()>`, which is required by `i32: Baz` | note: required for `i32` to implement `Baz` --> $DIR/assume-gat-normalization-for-nested-goals.rs:13:23 diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr index 261070d1db4bf..c3b119e21443d 100644 --- a/tests/ui/generic-associated-types/impl_bounds.stderr +++ b/tests/ui/generic-associated-types/impl_bounds.stderr @@ -25,7 +25,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:18:33 | LL | type C = String where Self: Copy; - | ^^^^ the trait `Copy` is not implemented for `T` + | ^^^^ the trait `Copy` is not implemented for `T`, which is required by `Fooy: Copy` | note: required for `Fooy` to implement `Copy` --> $DIR/impl_bounds.rs:10:10 @@ -50,7 +50,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:20:24 | LL | fn d() where Self: Copy {} - | ^^^^ the trait `Copy` is not implemented for `T` + | ^^^^ the trait `Copy` is not implemented for `T`, which is required by `Fooy: Copy` | note: required for `Fooy` to implement `Copy` --> $DIR/impl_bounds.rs:10:10 diff --git a/tests/ui/generic-associated-types/issue-101020.stderr b/tests/ui/generic-associated-types/issue-101020.stderr index 9c3753c2d1809..7faab4e527463 100644 --- a/tests/ui/generic-associated-types/issue-101020.stderr +++ b/tests/ui/generic-associated-types/issue-101020.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satis --> $DIR/issue-101020.rs:31:22 | LL | (&mut EmptyIter).consume(()); - | ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()` + | ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`, which is required by `for<'a> &'a mut (): FuncInput<'a, &'a mut ()>` | help: this trait has no implementations, consider adding one --> $DIR/issue-101020.rs:28:1 diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index 3a973d356dc98..7813370ae63f8 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -19,16 +19,10 @@ error[E0599]: the size for values of type `Node` cannot be known --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:31:35 | LL | enum Node { - | ------------------------------ - | | - | variant or associated item `new` not found for this enum - | doesn't satisfy `Node: Sized` + | ------------------------------ variant or associated item `new` not found for this enum because it doesn't satisfy `Node: Sized` ... LL | let mut list = RcNode::::new(); | ^^^ doesn't have a size known at compile-time - --> $SRC_DIR/core/src/ops/deref.rs:LL:COL - | - = note: doesn't satisfy `_: Sized` | note: trait bound `Node: Sized` was not satisfied --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:4:18 diff --git a/tests/ui/generic-associated-types/issue-74824.stderr b/tests/ui/generic-associated-types/issue-74824.stderr index e5638d90ee8e7..942d9583be1b1 100644 --- a/tests/ui/generic-associated-types/issue-74824.stderr +++ b/tests/ui/generic-associated-types/issue-74824.stderr @@ -14,7 +14,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/issue-74824.rs:6:26 | LL | type Copy: Copy = Box; - | ^^^^^^ the trait `Clone` is not implemented for `T` + | ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `::Copy: Copy` | = note: required for `Box` to implement `Clone` = note: required for `::Copy` to implement `Copy` diff --git a/tests/ui/generic-associated-types/issue-79422.extended.stderr b/tests/ui/generic-associated-types/issue-79422.extended.stderr index 14492266cdaf3..ae1526296a795 100644 --- a/tests/ui/generic-associated-types/issue-79422.extended.stderr +++ b/tests/ui/generic-associated-types/issue-79422.extended.stderr @@ -27,6 +27,7 @@ LL | type VRefCont<'a> = &'a V where Self: 'a; | ^^^^^ = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` found reference `&u8` + = help: `&u8` implements `RefCont` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well = note: required for the cast from `Box>` to `Box + 'static)>>` error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-88287.stderr b/tests/ui/generic-associated-types/issue-88287.stderr index 79ac6d0f10bd2..54ecc5cfcd810 100644 --- a/tests/ui/generic-associated-types/issue-88287.stderr +++ b/tests/ui/generic-associated-types/issue-88287.stderr @@ -7,11 +7,11 @@ LL | type SearchFutureTy<'f, A, B: 'f> LL | async move { todo!() } | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `>` +note: required by an implicit `Sized` bound in `>` --> $DIR/issue-88287.rs:24:6 | LL | impl SearchableResourceExt for T - | ^ required by this bound in `>` + | ^ required by the implicit `Sized` requirement on this type parameter in `>` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - A: SearchableResource + ?Sized + 'f, diff --git a/tests/ui/generic-associated-types/issue-88360.fixed b/tests/ui/generic-associated-types/issue-88360.fixed index 3dea8bf7ac81d..6fb1e2559c0ac 100644 --- a/tests/ui/generic-associated-types/issue-88360.fixed +++ b/tests/ui/generic-associated-types/issue-88360.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait GatTrait { type Gat<'a> where Self: 'a; diff --git a/tests/ui/generic-associated-types/issue-88360.rs b/tests/ui/generic-associated-types/issue-88360.rs index 4d4c7ea318078..c8f07955b6129 100644 --- a/tests/ui/generic-associated-types/issue-88360.rs +++ b/tests/ui/generic-associated-types/issue-88360.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait GatTrait { type Gat<'a> where Self: 'a; diff --git a/tests/ui/generic-associated-types/issue-88360.stderr b/tests/ui/generic-associated-types/issue-88360.stderr index 49d36acadd657..488e50d2843bf 100644 --- a/tests/ui/generic-associated-types/issue-88360.stderr +++ b/tests/ui/generic-associated-types/issue-88360.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-88360.rs:15:9 + --> $DIR/issue-88360.rs:16:9 | LL | trait SuperTrait | - found this type parameter diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs index 83655341d6a24..92ce4a0970f36 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs @@ -5,7 +5,7 @@ trait X { type Y; } -trait M { +trait M { //~ NOTE fn f(&self) {} } @@ -16,9 +16,7 @@ impl = i32>> M for T {} //~| NOTE struct S; -//~^ NOTE method `f` not found for this -//~| NOTE doesn't satisfy `::Y = i32` -//~| NOTE doesn't satisfy `S: M` +//~^ NOTE method `f` not found for this struct because it doesn't satisfy `::Y = i32` or `S: M` impl X for S { type Y = bool; diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr index 7ca0b2912a68a..61512dd46582d 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr @@ -1,12 +1,8 @@ error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied - --> $DIR/method-unsatisfied-assoc-type-predicate.rs:28:7 + --> $DIR/method-unsatisfied-assoc-type-predicate.rs:26:7 | LL | struct S; - | -------- - | | - | method `f` not found for this struct - | doesn't satisfy `::Y = i32` - | doesn't satisfy `S: M` + | -------- method `f` not found for this struct because it doesn't satisfy `::Y = i32` or `S: M` ... LL | a.f(); | ^ method cannot be called on `S` due to unsatisfied trait bounds @@ -18,6 +14,12 @@ LL | impl = i32>> M for T {} | ^^^^^^^^^^^^ - - | | | unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `M` defines an item `f`, perhaps you need to implement it + --> $DIR/method-unsatisfied-assoc-type-predicate.rs:8:1 + | +LL | trait M { + | ^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/parameter-defaults.stderr b/tests/ui/generic-const-items/parameter-defaults.stderr index 697423e8dc399..b8220af5d0e93 100644 --- a/tests/ui/generic-const-items/parameter-defaults.stderr +++ b/tests/ui/generic-const-items/parameter-defaults.stderr @@ -8,7 +8,7 @@ error[E0282]: type annotations needed for `Option` --> $DIR/parameter-defaults.rs:13:9 | LL | let _ = NONE; - | ^ + | ^ ---- type must be known at this point | help: consider giving this pattern a type, where the type for type parameter `T` is specified | diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed index aa6d6310f5fe3..f51040358c0b3 100644 --- a/tests/ui/generics/generic-no-mangle.fixed +++ b/tests/ui/generics/generic-no-mangle.fixed @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![deny(no_mangle_generic_items)] diff --git a/tests/ui/generics/generic-no-mangle.rs b/tests/ui/generics/generic-no-mangle.rs index 8a59ca75aafd2..02015331c5712 100644 --- a/tests/ui/generics/generic-no-mangle.rs +++ b/tests/ui/generics/generic-no-mangle.rs @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![deny(no_mangle_generic_items)] #[no_mangle] diff --git a/tests/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/tests/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr index 3f4f50562e252..3739829455bde 100644 --- a/tests/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr +++ b/tests/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr @@ -6,10 +6,10 @@ LL | impl Tsized for () {} | = help: the trait `Sized` is not implemented for `[()]` note: required by a bound in `Tsized` - --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:14 + --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:17 | LL | trait Tsized {} - | ^^^^^^^^^^^^^^^^^ required by this bound in `Tsized` + | ^^^^^ required by this bound in `Tsized` error: aborting due to 1 previous error diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs index a2a4c62fa0295..33b99259dfec9 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs @@ -1,7 +1,6 @@ // Test various non-exhaustive matches for `X..`, `..=X` and `..X` ranges. #![feature(exclusive_range_pattern)] -#![allow(illegal_floating_point_literal_pattern)] fn main() {} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr index 6b20a820b7302..1e68235303b2e 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:14:8 | LL | m!(0f32, f32::NEG_INFINITY..); | ^^^^ pattern `_` not covered @@ -11,7 +11,7 @@ LL | match $s { $($t)+ => {}, _ => todo!() } | ++++++++++++++ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8 | LL | m!(0f32, ..f32::INFINITY); | ^^^^ pattern `_` not covered @@ -23,7 +23,7 @@ LL | match $s { $($t)+ => {}, _ => todo!() } | ++++++++++++++ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:24:8 | LL | m!('a', ..core::char::MAX); | ^^^ pattern `'\u{10ffff}'` not covered @@ -35,7 +35,7 @@ LL | match $s { $($t)+ => {}, '\u{10ffff}' => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8 | LL | m!('a', ..ALMOST_MAX); | ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered @@ -47,7 +47,7 @@ LL | match $s { $($t)+ => {}, '\u{10fffe}'..='\u{10ffff}' => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `'\0'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8 | LL | m!('a', ALMOST_MIN..); | ^^^ pattern `'\0'` not covered @@ -59,7 +59,7 @@ LL | match $s { $($t)+ => {}, '\0' => todo!() } | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8 | LL | m!('a', ..=ALMOST_MAX); | ^^^ pattern `'\u{10ffff}'` not covered @@ -71,7 +71,7 @@ LL | match $s { $($t)+ => {}, '\u{10ffff}' => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `'b'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8 | LL | m!('a', ..=VAL | VAL_2..); | ^^^ pattern `'b'` not covered @@ -83,7 +83,7 @@ LL | match $s { $($t)+ => {}, 'b' => todo!() } | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `'b'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8 | LL | m!('a', ..VAL_1 | VAL_2..); | ^^^ pattern `'b'` not covered @@ -95,7 +95,7 @@ LL | match $s { $($t)+ => {}, 'b' => todo!() } | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:39:12 | LL | m!(0, ..u8::MAX); | ^ pattern `u8::MAX` not covered @@ -107,7 +107,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `254_u8..=u8::MAX` not covered @@ -119,7 +119,7 @@ LL | match $s { $($t)+ => {}, 254_u8..=u8::MAX => todo!() } | +++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u8` not covered @@ -131,7 +131,7 @@ LL | match $s { $($t)+ => {}, 0_u8 => todo!() } | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u8::MAX` not covered @@ -143,7 +143,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u8` not covered @@ -155,7 +155,7 @@ LL | match $s { $($t)+ => {}, 43_u8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u8` not covered @@ -167,7 +167,7 @@ LL | match $s { $($t)+ => {}, 43_u8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:52:12 | LL | m!(0, ..u16::MAX); | ^ pattern `u16::MAX` not covered @@ -179,7 +179,7 @@ LL | match $s { $($t)+ => {}, u16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `65534_u16..=u16::MAX` not covered @@ -191,7 +191,7 @@ LL | match $s { $($t)+ => {}, 65534_u16..=u16::MAX => todo!() } | +++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u16` not covered @@ -203,7 +203,7 @@ LL | match $s { $($t)+ => {}, 0_u16 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u16::MAX` not covered @@ -215,7 +215,7 @@ LL | match $s { $($t)+ => {}, u16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u16` not covered @@ -227,7 +227,7 @@ LL | match $s { $($t)+ => {}, 43_u16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u16` not covered @@ -239,7 +239,7 @@ LL | match $s { $($t)+ => {}, 43_u16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:65:12 | LL | m!(0, ..u32::MAX); | ^ pattern `u32::MAX` not covered @@ -251,7 +251,7 @@ LL | match $s { $($t)+ => {}, u32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `4294967294_u32..=u32::MAX` not covered @@ -263,7 +263,7 @@ LL | match $s { $($t)+ => {}, 4294967294_u32..=u32::MAX => todo!() } | ++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u32` not covered @@ -275,7 +275,7 @@ LL | match $s { $($t)+ => {}, 0_u32 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u32::MAX` not covered @@ -287,7 +287,7 @@ LL | match $s { $($t)+ => {}, u32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u32` not covered @@ -299,7 +299,7 @@ LL | match $s { $($t)+ => {}, 43_u32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u32` not covered @@ -311,7 +311,7 @@ LL | match $s { $($t)+ => {}, 43_u32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:78:12 | LL | m!(0, ..u64::MAX); | ^ pattern `u64::MAX` not covered @@ -323,7 +323,7 @@ LL | match $s { $($t)+ => {}, u64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `18446744073709551614_u64..=u64::MAX` not covered @@ -335,7 +335,7 @@ LL | match $s { $($t)+ => {}, 18446744073709551614_u64..=u64::MAX => tod | ++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u64` not covered @@ -347,7 +347,7 @@ LL | match $s { $($t)+ => {}, 0_u64 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u64::MAX` not covered @@ -359,7 +359,7 @@ LL | match $s { $($t)+ => {}, u64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u64` not covered @@ -371,7 +371,7 @@ LL | match $s { $($t)+ => {}, 43_u64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u64` not covered @@ -383,7 +383,7 @@ LL | match $s { $($t)+ => {}, 43_u64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:91:12 | LL | m!(0, ..u128::MAX); | ^ pattern `u128::MAX` not covered @@ -395,7 +395,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered @@ -407,7 +407,7 @@ LL | match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u1 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u128` not covered @@ -419,7 +419,7 @@ LL | match $s { $($t)+ => {}, 0_u128 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u128::MAX` not covered @@ -431,7 +431,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u128` not covered @@ -443,7 +443,7 @@ LL | match $s { $($t)+ => {}, 43_u128 => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u128` not covered @@ -455,7 +455,7 @@ LL | match $s { $($t)+ => {}, 43_u128 => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:107:12 | LL | m!(0, ..i8::MAX); | ^ pattern `i8::MAX` not covered @@ -467,7 +467,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `126_i8..=i8::MAX` not covered @@ -479,7 +479,7 @@ LL | match $s { $($t)+ => {}, 126_i8..=i8::MAX => todo!() } | +++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i8::MIN` not covered @@ -491,7 +491,7 @@ LL | match $s { $($t)+ => {}, i8::MIN => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i8::MAX` not covered @@ -503,7 +503,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i8` not covered @@ -515,7 +515,7 @@ LL | match $s { $($t)+ => {}, 43_i8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i8` not covered @@ -527,7 +527,7 @@ LL | match $s { $($t)+ => {}, 43_i8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:120:12 | LL | m!(0, ..i16::MAX); | ^ pattern `i16::MAX` not covered @@ -539,7 +539,7 @@ LL | match $s { $($t)+ => {}, i16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `32766_i16..=i16::MAX` not covered @@ -551,7 +551,7 @@ LL | match $s { $($t)+ => {}, 32766_i16..=i16::MAX => todo!() } | +++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i16::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i16::MIN` not covered @@ -563,7 +563,7 @@ LL | match $s { $($t)+ => {}, i16::MIN => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i16::MAX` not covered @@ -575,7 +575,7 @@ LL | match $s { $($t)+ => {}, i16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i16` not covered @@ -587,7 +587,7 @@ LL | match $s { $($t)+ => {}, 43_i16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i16` not covered @@ -599,7 +599,7 @@ LL | match $s { $($t)+ => {}, 43_i16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:133:12 | LL | m!(0, ..i32::MAX); | ^ pattern `i32::MAX` not covered @@ -611,7 +611,7 @@ LL | match $s { $($t)+ => {}, i32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `2147483646_i32..=i32::MAX` not covered @@ -623,7 +623,7 @@ LL | match $s { $($t)+ => {}, 2147483646_i32..=i32::MAX => todo!() } | ++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i32::MIN` not covered @@ -635,7 +635,7 @@ LL | match $s { $($t)+ => {}, i32::MIN => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i32::MAX` not covered @@ -647,7 +647,7 @@ LL | match $s { $($t)+ => {}, i32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i32` not covered @@ -659,7 +659,7 @@ LL | match $s { $($t)+ => {}, 43_i32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i32` not covered @@ -671,7 +671,7 @@ LL | match $s { $($t)+ => {}, 43_i32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:146:12 | LL | m!(0, ..i64::MAX); | ^ pattern `i64::MAX` not covered @@ -683,7 +683,7 @@ LL | match $s { $($t)+ => {}, i64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `9223372036854775806_i64..=i64::MAX` not covered @@ -695,7 +695,7 @@ LL | match $s { $($t)+ => {}, 9223372036854775806_i64..=i64::MAX => todo | +++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i64::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i64::MIN` not covered @@ -707,7 +707,7 @@ LL | match $s { $($t)+ => {}, i64::MIN => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i64::MAX` not covered @@ -719,7 +719,7 @@ LL | match $s { $($t)+ => {}, i64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i64` not covered @@ -731,7 +731,7 @@ LL | match $s { $($t)+ => {}, 43_i64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i64` not covered @@ -743,7 +743,7 @@ LL | match $s { $($t)+ => {}, 43_i64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:159:12 | LL | m!(0, ..i128::MAX); | ^ pattern `i128::MAX` not covered @@ -755,7 +755,7 @@ LL | match $s { $($t)+ => {}, i128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered @@ -767,7 +767,7 @@ LL | match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i1 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i128::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i128::MIN` not covered @@ -779,7 +779,7 @@ LL | match $s { $($t)+ => {}, i128::MIN => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i128::MAX` not covered @@ -791,7 +791,7 @@ LL | match $s { $($t)+ => {}, i128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i128` not covered @@ -803,7 +803,7 @@ LL | match $s { $($t)+ => {}, 43_i128 => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i128` not covered diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index 6c6ba93196b64..d5af7bea54388 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -4,7 +4,6 @@ // via `.contains(...)` and make sure the dynamic semantics match. #![feature(exclusive_range_pattern)] -#![allow(illegal_floating_point_literal_pattern)] #![allow(unreachable_patterns)] macro_rules! yes { diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index 4b14a314e7aea..158da6509662f 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -1,5 +1,4 @@ #![feature(exclusive_range_pattern)] -#![allow(illegal_floating_point_literal_pattern)] macro_rules! m { ($s:expr, $($t:tt)+) => { diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index e9702bb380fb3..169e776fc20fd 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -1,77 +1,77 @@ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:10:11 | LL | m!(0, ..u8::MIN); | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:12:11 | LL | m!(0, ..u16::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11 | LL | m!(0, ..u32::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:16:11 | LL | m!(0, ..u64::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:18:11 | LL | m!(0, ..u128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:21:11 | LL | m!(0, ..i8::MIN); | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11 | LL | m!(0, ..i16::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:25:11 | LL | m!(0, ..i32::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11 | LL | m!(0, ..i64::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:29:11 | LL | m!(0, ..i128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:32:14 | LL | m!(0f32, ..f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:34:14 | LL | m!(0f64, ..f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:38:13 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:37:13 | LL | m!('a', ..'\u{0}'); | ^^^^^^^^^ diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs index acb7feac132f4..e6d5e64a15b7a 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs @@ -1,5 +1,4 @@ // run-pass -#![allow(incomplete_features)] #![feature(exclusive_range_pattern)] #![feature(inline_const_pat)] diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs index 55353999b6788..0c050c550c4ce 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs @@ -17,12 +17,18 @@ fn main() { } match x as i32 { 0..5+1 => errors_only.push(x), - //~^ error: expected one of `=>`, `if`, or `|`, found `+` + //~^ error: expected a pattern range bound, found an expression + //~| error: exclusive range pattern syntax is experimental 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: exclusive range pattern syntax is experimental + //~| error: inline-const in pattern position is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index e2fab14ffc235..cc481f7a79e13 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -1,8 +1,8 @@ -error: expected one of `=>`, `if`, or `|`, found `+` - --> $DIR/range_pat_interactions1.rs:19:17 +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions1.rs:19:16 | LL | 0..5+1 => errors_only.push(x), - | ^ expected one of `=>`, `if`, or `|` + | ^^^ arbitrary expressions are not allowed in patterns error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 @@ -12,6 +12,16 @@ LL | if let n @ 2..3|4 = x { | | | variable not in all patterns +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions1.rs:26:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions1.rs:10:20 | @@ -21,6 +31,7 @@ LL | if let n @ 2..3|4 = x { = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions1.rs:14:23 @@ -31,8 +42,64 @@ LL | } else if let 2..3 | 4 = x { = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:19:13 + | +LL | 0..5+1 => errors_only.push(x), + | ^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:22:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:24:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:26:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:30:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M -error: aborting due to 4 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0408, E0658. For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs index 0e96cfe785857..068104c4b1b8c 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs @@ -8,12 +8,18 @@ fn main() { for x in -9 + 1..=(9 - 2) { match x as i32 { 0..=(5+1) => errors_only.push(x), - //~^ error: expected `)`, found `+` + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: inline-const in pattern position is experimental + //~| error: exclusive range pattern syntax is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index a54f29a3b3263..8f21a6149fb89 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -1,8 +1,75 @@ -error: expected `)`, found `+` - --> $DIR/range_pat_interactions2.rs:10:19 +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions2.rs:10:18 | LL | 0..=(5+1) => errors_only.push(x), - | ^ expected `)` + | ^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error: range pattern bounds cannot have parentheses + --> $DIR/range_pat_interactions2.rs:10:17 + | +LL | 0..=(5+1) => errors_only.push(x), + | ^ ^ + | +help: remove these parentheses + | +LL - 0..=(5+1) => errors_only.push(x), +LL + 0..=5+1 => errors_only.push(x), + | + +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions2.rs:17:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:13:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:15:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:17:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:21:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr index fe233496261c1..51cc22e7d5602 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr @@ -17,6 +17,7 @@ LL | 1 | -3..0 => first_or.push(x), = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions3.rs:12:18 @@ -27,6 +28,7 @@ LL | y @ (0..5 | 6) => or_two.push(y), = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions3.rs:14:17 @@ -37,6 +39,7 @@ LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions3.rs:18:17 @@ -47,6 +50,7 @@ LL | y @ ..-7 => assert_eq!(y, -8), = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error: aborting due to 5 previous errors diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr index 5edd877bee03e..be8f3aa5051e3 100644 --- a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr +++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr @@ -17,6 +17,7 @@ LL | let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs; = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error[E0658]: exclusive range pattern syntax is experimental --> $DIR/slice_pattern_syntax_problem1.rs:4:32 @@ -27,6 +28,7 @@ LL | let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs; = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M error: aborting due to 3 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr index 77aa37cefe363..b322ea41c436d 100644 --- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr +++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr @@ -2,7 +2,7 @@ error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())` --> $DIR/fn-ptr.rs:12:5 | LL | ice(); - | ^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())` + | ^^^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())` | = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())` note: required by a bound in `ice` diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr index 4f9ceb577c0be..699a4ecc42bb9 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `filterx` exists for struct `Map $DIR/issue-30786.rs:120:22 | LL | pub struct Map { - | -------------------- - | | - | method `filterx` not found for this struct - | doesn't satisfy `_: StreamExt` + | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds @@ -18,15 +15,18 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `filterx`, perhaps you need to implement it + --> $DIR/issue-30786.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:132:24 | LL | pub struct Filter { - | ----------------------- - | | - | method `countx` not found for this struct - | doesn't satisfy `_: StreamExt` + | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` ... LL | let count = filter.countx(); | ^^^^^^ method cannot be called due to unsatisfied trait bounds @@ -39,6 +39,12 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `countx`, perhaps you need to implement it + --> $DIR/issue-30786.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr index 3240518fbbe08..e60531a876be1 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr @@ -13,7 +13,7 @@ error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied --> $DIR/issue-85455.rs:8:5 | LL | callee:: >::Associated>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr index 7fe803550bddf..761fd9045a13a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied --> $DIR/issue-89118.rs:19:8 | LL | C: StackContext, - | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` | help: this trait has no implementations, consider adding one --> $DIR/issue-89118.rs:1:1 @@ -29,7 +29,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied --> $DIR/issue-89118.rs:29:9 | LL | impl EthernetWorker {} - | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` | help: this trait has no implementations, consider adding one --> $DIR/issue-89118.rs:1:1 @@ -56,7 +56,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied --> $DIR/issue-89118.rs:22:20 | LL | type Handler = Ctx; - | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` | help: this trait has no implementations, consider adding one --> $DIR/issue-89118.rs:1:1 diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr index a2ec96f1a2d0f..f42fc59536c43 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr @@ -2,13 +2,13 @@ error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satis --> $DIR/norm-before-method-resolution.rs:22:17 | LL | let _: () = weird_bound(); - | ^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out` + | ^^^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out` | note: this is a known limitation of the trait solver that will be lifted in the future --> $DIR/norm-before-method-resolution.rs:22:17 | LL | let _: () = weird_bound(); - | ^^^^^^^^^^^ try adding turbofish arguments to this expression to specify the types manually, even if it's redundant + | ^^^^^^^^^^^^^ try adding turbofish arguments to this expression to specify the types manually, even if it's redundant note: required by a bound in `weird_bound` --> $DIR/norm-before-method-resolution.rs:18:40 | diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leak2.stderr index 52fa28145d664..1fcde0372fc96 100644 --- a/tests/ui/impl-trait/auto-trait-leak2.stderr +++ b/tests/ui/impl-trait/auto-trait-leak2.stderr @@ -9,7 +9,7 @@ LL | send(before()); | | | required by a bound introduced by this call | - = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>` + = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>`, which is required by `impl Fn(i32): Send` note: required because it's used within this closure --> $DIR/auto-trait-leak2.rs:10:5 | @@ -37,7 +37,7 @@ LL | send(after()); LL | fn after() -> impl Fn(i32) { | ------------ within this `impl Fn(i32)` | - = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>` + = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>`, which is required by `impl Fn(i32): Send` note: required because it's used within this closure --> $DIR/auto-trait-leak2.rs:38:5 | diff --git a/tests/ui/impl-trait/cross-return-site-inference.stderr b/tests/ui/impl-trait/cross-return-site-inference.stderr index 8ee3e9abf9ccb..5512c234af985 100644 --- a/tests/ui/impl-trait/cross-return-site-inference.stderr +++ b/tests/ui/impl-trait/cross-return-site-inference.stderr @@ -13,7 +13,7 @@ error[E0790]: cannot call associated function on trait without specifying the co --> $DIR/cross-return-site-inference.rs:38:16 | LL | return Err(From::from("foo")); - | ^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation | @@ -24,7 +24,7 @@ error[E0790]: cannot call associated function on trait without specifying the co --> $DIR/cross-return-site-inference.rs:44:9 | LL | Err(From::from("foo")) - | ^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation | diff --git a/tests/ui/impl-trait/dyn-impl-type-mismatch.rs b/tests/ui/impl-trait/dyn-impl-type-mismatch.rs new file mode 100644 index 0000000000000..c6170abb58285 --- /dev/null +++ b/tests/ui/impl-trait/dyn-impl-type-mismatch.rs @@ -0,0 +1,18 @@ +trait Trait {} +struct Struct; +impl Trait for Struct {} +fn foo() -> impl Trait { + Struct +} +fn main() { + let a: Box = if true { + Box::new(Struct) + } else { + foo() //~ ERROR E0308 + }; + let a: dyn Trait = if true { + Struct //~ ERROR E0308 + } else { + foo() //~ ERROR E0308 + }; +} diff --git a/tests/ui/impl-trait/dyn-impl-type-mismatch.stderr b/tests/ui/impl-trait/dyn-impl-type-mismatch.stderr new file mode 100644 index 0000000000000..ddbdaf3eb4b03 --- /dev/null +++ b/tests/ui/impl-trait/dyn-impl-type-mismatch.stderr @@ -0,0 +1,43 @@ +error[E0308]: mismatched types + --> $DIR/dyn-impl-type-mismatch.rs:11:9 + | +LL | fn foo() -> impl Trait { + | ---------- the found opaque type +... +LL | foo() + | ^^^^^ expected `Box`, found opaque type + | + = note: expected struct `Box` + found opaque type `impl Trait` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(foo()) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-impl-type-mismatch.rs:14:9 + | +LL | Struct + | ^^^^^^ expected `dyn Trait`, found `Struct` + | + = note: expected trait object `dyn Trait` + found struct `Struct` + = help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + +error[E0308]: mismatched types + --> $DIR/dyn-impl-type-mismatch.rs:16:9 + | +LL | fn foo() -> impl Trait { + | ---------- the found opaque type +... +LL | foo() + | ^^^^^ expected `dyn Trait`, found opaque type + | + = note: expected trait object `dyn Trait` + found opaque type `impl Trait` + = help: you can box the `impl Trait` to coerce it to `Box`, but you'll have to change the expected type as well + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index 4a52f82540d83..f25269ca03207 100644 --- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -6,6 +6,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | = note: expected trait object `(dyn Trait + 'static)` found struct `Struct` + = help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13 @@ -15,7 +16,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`, which is required by `(usize, (dyn Trait + 'static)): Sized` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -27,6 +28,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | = note: expected trait object `(dyn Trait + 'static)` found struct `Struct` + = help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13 @@ -36,7 +38,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`, which is required by `(usize, (dyn Trait + 'static)): Sized` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr index 1011fc4163bca..0e3cd2ff06099 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr @@ -1,4 +1,4 @@ -note: no errors encountered even though `span_delayed_bug` issued +note: no errors encountered even though delayed bugs were created note: those delayed bugs will now be shown as internal compiler errors diff --git a/tests/ui/impl-trait/example-st.rs b/tests/ui/impl-trait/example-st.rs index 4e1aa3a085921..1e6ebc52365dc 100644 --- a/tests/ui/impl-trait/example-st.rs +++ b/tests/ui/impl-trait/example-st.rs @@ -3,7 +3,7 @@ struct State; type Error = (); -trait Bind { +trait Bind { //~ WARN trait `Bind` is never used type Output; fn bind(self, f: F) -> Self::Output; } diff --git a/tests/ui/impl-trait/example-st.stderr b/tests/ui/impl-trait/example-st.stderr new file mode 100644 index 0000000000000..f722d7f658215 --- /dev/null +++ b/tests/ui/impl-trait/example-st.stderr @@ -0,0 +1,10 @@ +warning: trait `Bind` is never used + --> $DIR/example-st.rs:6:7 + | +LL | trait Bind { + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index 700aff36aa509..421afc96eed07 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -32,7 +32,7 @@ error[E0277]: the trait bound `impl Debug: Step` is not satisfied --> $DIR/impl_trait_projections.rs:26:8 | LL | -> <::std::ops::Range as Iterator>::Item - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range: Iterator` | = help: the following other types implement trait `Step`: char @@ -53,7 +53,7 @@ LL | / { LL | | LL | | (1i32..100).next().unwrap() LL | | } - | |_^ the trait `Step` is not implemented for `impl Debug` + | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range: Iterator` | = help: the following other types implement trait `Step`: char diff --git a/tests/ui/impl-trait/in-ctfe/array-len-size-of.rs b/tests/ui/impl-trait/in-ctfe/array-len-size-of.rs new file mode 100644 index 0000000000000..01ba902ef0c0d --- /dev/null +++ b/tests/ui/impl-trait/in-ctfe/array-len-size-of.rs @@ -0,0 +1,16 @@ +//! Check that const eval can use the size of opaque types. +// check-pass +use std::mem; +fn returns_opaque() -> impl Sized { + 0u8 +} + +struct NamedOpaqueType { + data: [mem::MaybeUninit; size_of_fut(returns_opaque)], +} + +const fn size_of_fut(x: fn() -> FUT) -> usize { + mem::size_of::() +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-ctfe/array-len.rs b/tests/ui/impl-trait/in-ctfe/array-len.rs new file mode 100644 index 0000000000000..73ae20495d577 --- /dev/null +++ b/tests/ui/impl-trait/in-ctfe/array-len.rs @@ -0,0 +1,22 @@ +//! Check that array lengths can observe associated types of opaque types +// check-pass +trait MyTrait: Copy { + const ASSOC: usize; +} + +impl MyTrait for u8 { + const ASSOC: usize = 32; +} + +const fn yeet() -> impl MyTrait { + 0u8 +} + +const fn output(_: T) -> usize { + ::ASSOC +} + +fn main() { + let x = [0u8; output(yeet())]; + println!("{:?}", x); +} diff --git a/tests/ui/impl-trait/in-ctfe/enum-discr.rs b/tests/ui/impl-trait/in-ctfe/enum-discr.rs new file mode 100644 index 0000000000000..8e4384adaa4cb --- /dev/null +++ b/tests/ui/impl-trait/in-ctfe/enum-discr.rs @@ -0,0 +1,26 @@ +//! check that const eval can observe associated types of opaque types. +// check-pass +trait MyTrait: Copy { + const ASSOC: usize; +} + +impl MyTrait for u8 { + const ASSOC: usize = 32; +} + +const fn yeet() -> impl MyTrait { + 0u8 +} + +const fn output(_: T) -> usize { + ::ASSOC +} + +#[repr(usize)] +enum Foo { + Bar = output(yeet()), +} + +fn main() { + println!("{}", Foo::Bar as usize); +} diff --git a/tests/ui/impl-trait/in-ctfe/fully_monomorphic_const_eval.rs b/tests/ui/impl-trait/in-ctfe/fully_monomorphic_const_eval.rs new file mode 100644 index 0000000000000..82a9a30a62362 --- /dev/null +++ b/tests/ui/impl-trait/in-ctfe/fully_monomorphic_const_eval.rs @@ -0,0 +1,29 @@ +//! This test ensures that we do look at the hidden types of +//! opaque types during const eval in order to obtain the exact type +//! of associated types. + +// check-pass + +trait MyTrait: Copy { + const ASSOC: usize; +} + +impl MyTrait for u8 { + const ASSOC: usize = 32; +} + +const fn yeet() -> impl MyTrait { + 0u8 +} + +const fn output(_: T) -> usize { + ::ASSOC +} + +struct Foo<'a>(&'a ()); +const NEED_REVEAL_ALL: usize = output(yeet()); + +fn promote_div() -> &'static usize { + &(10 / NEED_REVEAL_ALL) +} +fn main() {} diff --git a/tests/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs b/tests/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs new file mode 100644 index 0000000000000..8e3269726fc4a --- /dev/null +++ b/tests/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs @@ -0,0 +1,24 @@ +//! Check that pattern matching can observe the hidden type of opaque types. +// check-pass +trait MyTrait: Copy { + const ASSOC: u8; +} + +impl MyTrait for () { + const ASSOC: u8 = 0; +} + +const fn yeet() -> impl MyTrait {} + +const fn output(_: T) -> u8 { + ::ASSOC +} + +const CT: u8 = output(yeet()); + +fn main() { + match 0 { + CT => (), + 1.. => (), + } +} diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs index 650cb3870d581..daf29a0005dec 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs @@ -20,7 +20,6 @@ impl dyn MyTrait { MyTrait::foo(&self) //~^ ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied - //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied //~| ERROR the trait `MyTrait` cannot be made into an object } } diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr index 01de3e531952c..90285d512ef03 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr @@ -32,14 +32,6 @@ LL | MyTrait::foo(&self) | = help: the trait `MyTrait` is implemented for `Outer` -error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:9 - | -LL | MyTrait::foo(&self) - | ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` - | - = help: the trait `MyTrait` is implemented for `Outer` - error[E0038]: the trait `MyTrait` cannot be made into an object --> $DIR/cycle-effective-visibilities-during-object-safety.rs:16:6 | @@ -72,7 +64,7 @@ LL | fn foo(&self) -> impl Marker; = help: consider moving `foo` to another trait = help: only type `Outer` implements the trait, consider using it directly instead -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0038, E0277. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs index 7960018482fce..9d703cf0df1bc 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.rs +++ b/tests/ui/impl-trait/in-trait/issue-102140.rs @@ -20,7 +20,6 @@ impl dyn MyTrait { MyTrait::foo(&self) //~^ ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied - //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied } } diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr index 9cd2cdfd1a53e..dc3dcc114aed5 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -20,14 +20,6 @@ LL | MyTrait::foo(&self) | = help: the trait `MyTrait` is implemented for `Outer` -error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:20:9 - | -LL | MyTrait::foo(&self) - | ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` - | - = help: the trait `MyTrait` is implemented for `Outer` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed index 8dc8e045d4738..ecc8488a15299 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -1,6 +1,7 @@ // edition:2021 // run-rustfix +#![allow(dead_code)] trait Trait { #[allow(async_fn_in_trait)] async fn foo(); diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs index 30b04d87b9a3e..860fea07df964 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -1,6 +1,7 @@ // edition:2021 // run-rustfix +#![allow(dead_code)] trait Trait { #[allow(async_fn_in_trait)] async fn foo(); diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr index cf68ed87030a9..45fd79badb30f 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz` - --> $DIR/suggest-missing-item.rs:19:1 + --> $DIR/suggest-missing-item.rs:20:1 | LL | async fn foo(); | --------------- `foo` from trait diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr index c20df9b40edfb..7d42659d81edb 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr @@ -5,7 +5,7 @@ LL | fn nya() -> impl Wf>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -15,11 +15,11 @@ LL | fn nya2() -> impl Wf<[u8]>; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `Wf` +note: required by an implicit `Sized` bound in `Wf` --> $DIR/wf-bounds.rs:7:10 | LL | trait Wf { - | ^ required by this bound in `Wf` + | ^ required by the implicit `Sized` requirement on this type parameter in `Wf` help: consider relaxing the implicit `Sized` restriction | LL | trait Wf { @@ -32,7 +32,7 @@ LL | fn nya3() -> impl Wf<(), Output = impl Wf>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: `T` doesn't implement `std::fmt::Display` diff --git a/tests/ui/impl-trait/issue-55872-1.stderr b/tests/ui/impl-trait/issue-55872-1.stderr index 8912cce1b4b5b..0c86824e62217 100644 --- a/tests/ui/impl-trait/issue-55872-1.stderr +++ b/tests/ui/impl-trait/issue-55872-1.stderr @@ -11,7 +11,7 @@ error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` --> $DIR/issue-55872-1.rs:12:29 | LL | fn foo() -> Self::E { - | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`, which is required by `(S, T): Copy` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound @@ -23,7 +23,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` --> $DIR/issue-55872-1.rs:12:29 | LL | fn foo() -> Self::E { - | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`, which is required by `(S, T): Copy` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index 31c3e0c901365..83d1347aff431 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -46,7 +46,7 @@ error[E0277]: the trait bound `impl Debug: From>` is not satisfie --> $DIR/nested_impl_trait.rs:6:46 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` @@ -55,7 +55,7 @@ error[E0277]: the trait bound `impl Debug: From>` is not satisfie --> $DIR/nested_impl_trait.rs:19:34 | LL | fn bad(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` diff --git a/tests/ui/impl-trait/rpit/early_bound.rs b/tests/ui/impl-trait/rpit/early_bound.rs new file mode 100644 index 0000000000000..03bd64d4d76d0 --- /dev/null +++ b/tests/ui/impl-trait/rpit/early_bound.rs @@ -0,0 +1,13 @@ +use std::convert::identity; + +fn test<'a: 'a>(n: bool) -> impl Sized + 'a { + //~^ ERROR concrete type differs from previous defining opaque type use + let true = n else { loop {} }; + let _ = || { + let _ = identity::<&'a ()>(test(false)); + //~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds + }; + loop {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/rpit/early_bound.stderr b/tests/ui/impl-trait/rpit/early_bound.stderr new file mode 100644 index 0000000000000..815368f250e35 --- /dev/null +++ b/tests/ui/impl-trait/rpit/early_bound.stderr @@ -0,0 +1,26 @@ +error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds + --> $DIR/early_bound.rs:7:17 + | +LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a { + | -- --------------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +... +LL | let _ = identity::<&'a ()>(test(false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: concrete type differs from previous defining opaque type use + --> $DIR/early_bound.rs:3:29 + | +LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a { + | ^^^^^^^^^^^^^^^ expected `&()`, got `()` + | +note: previous use here + --> $DIR/early_bound.rs:7:36 + | +LL | let _ = identity::<&'a ()>(test(false)); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/transmute/in-defining-scope.rs b/tests/ui/impl-trait/transmute/in-defining-scope.rs new file mode 100644 index 0000000000000..b0b77d60b245e --- /dev/null +++ b/tests/ui/impl-trait/transmute/in-defining-scope.rs @@ -0,0 +1,14 @@ +// This causes a query cycle due to using `Reveal::All`, +// in #119821 const eval was changed to always use `Reveal::All` +// +// See that PR for more details. +use std::mem::transmute; +fn foo() -> impl Sized { + //~^ ERROR cycle detected when computing type of + unsafe { + transmute::<_, u8>(foo()); + } + 0u8 +} + +fn main() {} diff --git a/tests/ui/impl-trait/transmute/in-defining-scope.stderr b/tests/ui/impl-trait/transmute/in-defining-scope.stderr new file mode 100644 index 0000000000000..69812f43072b0 --- /dev/null +++ b/tests/ui/impl-trait/transmute/in-defining-scope.stderr @@ -0,0 +1,29 @@ +error[E0391]: cycle detected when computing type of `foo::{opaque#0}` + --> $DIR/in-defining-scope.rs:6:13 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires computing type of opaque `foo::{opaque#0}`... + --> $DIR/in-defining-scope.rs:6:13 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires type-checking `foo`... + --> $DIR/in-defining-scope.rs:6:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `foo::{opaque#0}`... + = note: ...which requires normalizing `foo::{opaque#0}`... + = note: ...which again requires computing type of `foo::{opaque#0}`, completing the cycle +note: cycle used when checking that `foo::{opaque#0}` is well-formed + --> $DIR/in-defining-scope.rs:6:13 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/transmute/outside-of-defining-scope.rs b/tests/ui/impl-trait/transmute/outside-of-defining-scope.rs new file mode 100644 index 0000000000000..7bc22ea416f06 --- /dev/null +++ b/tests/ui/impl-trait/transmute/outside-of-defining-scope.rs @@ -0,0 +1,12 @@ +//! Check that typeck can observe the size of an opaque type. +// check-pass +use std::mem::transmute; +fn foo() -> impl Sized { + 0u8 +} + +fn main() { + unsafe { + transmute::<_, u8>(foo()); + } +} diff --git a/tests/ui/impl-trait/type-alias-generic-param.rs b/tests/ui/impl-trait/type-alias-generic-param.rs index 1211625dac9cc..e4b2e4124202f 100644 --- a/tests/ui/impl-trait/type-alias-generic-param.rs +++ b/tests/ui/impl-trait/type-alias-generic-param.rs @@ -5,7 +5,7 @@ // run-pass #![feature(impl_trait_in_assoc_type)] -trait Meow { +trait Meow { //~ WARN trait `Meow` is never used type MeowType; fn meow(self) -> Self::MeowType; } diff --git a/tests/ui/impl-trait/type-alias-generic-param.stderr b/tests/ui/impl-trait/type-alias-generic-param.stderr new file mode 100644 index 0000000000000..e4115dc1319d1 --- /dev/null +++ b/tests/ui/impl-trait/type-alias-generic-param.stderr @@ -0,0 +1,10 @@ +warning: trait `Meow` is never used + --> $DIR/type-alias-generic-param.rs:8:7 + | +LL | trait Meow { + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/imports/ambiguous-2.rs b/tests/ui/imports/ambiguous-2.rs index 7b38f3006b104..2918feb059107 100644 --- a/tests/ui/imports/ambiguous-2.rs +++ b/tests/ui/imports/ambiguous-2.rs @@ -6,4 +6,5 @@ extern crate ambiguous_1; fn main() { ambiguous_1::id(); + //^ FIXME: `id` should be identified as an ambiguous item. } diff --git a/tests/ui/imports/ambiguous-4.rs b/tests/ui/imports/ambiguous-4.rs index 24ae33784c526..1e8f5be5a882e 100644 --- a/tests/ui/imports/ambiguous-4.rs +++ b/tests/ui/imports/ambiguous-4.rs @@ -5,5 +5,5 @@ extern crate ambiguous_4_extern; fn main() { ambiguous_4_extern::id(); - // `warning_ambiguous` had been lost at metadata. + //^ FIXME: `id` should be identified as an ambiguous item. } diff --git a/tests/ui/imports/ambiguous-9.stderr b/tests/ui/imports/ambiguous-9.stderr index 2731ed2ba86d3..6c7d79174daf6 100644 --- a/tests/ui/imports/ambiguous-9.stderr +++ b/tests/ui/imports/ambiguous-9.stderr @@ -60,7 +60,6 @@ note: `date_range` could also refer to the function imported here LL | use prelude::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: 4 warnings emitted diff --git a/tests/ui/imports/auxiliary/glob-conflict-cross-crate-2-extern.rs b/tests/ui/imports/auxiliary/glob-conflict-cross-crate-2-extern.rs new file mode 100644 index 0000000000000..5dec6d4699496 --- /dev/null +++ b/tests/ui/imports/auxiliary/glob-conflict-cross-crate-2-extern.rs @@ -0,0 +1,10 @@ +mod a { + pub type C = i8; +} + +mod b { + pub type C = i16; +} + +pub use a::*; +pub use b::*; diff --git a/tests/ui/imports/auxiliary/issue-114682-2-extern.rs b/tests/ui/imports/auxiliary/issue-114682-2-extern.rs new file mode 100644 index 0000000000000..df2af78916682 --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-114682-2-extern.rs @@ -0,0 +1,17 @@ +macro_rules! m { + () => { + pub fn max() {} + pub(crate) mod max {} + }; +} + +mod d { + m! {} +} + +mod e { + pub type max = i32; +} + +pub use self::d::*; +pub use self::e::*; diff --git a/tests/ui/imports/auxiliary/issue-114682-3-extern.rs b/tests/ui/imports/auxiliary/issue-114682-3-extern.rs new file mode 100644 index 0000000000000..999b66342fe00 --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-114682-3-extern.rs @@ -0,0 +1,16 @@ +mod gio { + pub trait SettingsExt { + fn abc(&self) {} + } + impl SettingsExt for T {} +} + +mod gtk { + pub trait SettingsExt { + fn efg(&self) {} + } + impl SettingsExt for T {} +} + +pub use gtk::*; +pub use gio::*; diff --git a/tests/ui/imports/auxiliary/issue-114682-4-extern.rs b/tests/ui/imports/auxiliary/issue-114682-4-extern.rs new file mode 100644 index 0000000000000..86663f11b31eb --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-114682-4-extern.rs @@ -0,0 +1,10 @@ +mod a { + pub type Result = std::result::Result; +} + +mod b { + pub type Result = std::result::Result; +} + +pub use a::*; +pub use b::*; diff --git a/tests/ui/imports/auxiliary/issue-114682-5-extern-1.rs b/tests/ui/imports/auxiliary/issue-114682-5-extern-1.rs new file mode 100644 index 0000000000000..ebf6493f9f718 --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-114682-5-extern-1.rs @@ -0,0 +1 @@ +pub struct Url; diff --git a/tests/ui/imports/auxiliary/issue-114682-5-extern-2.rs b/tests/ui/imports/auxiliary/issue-114682-5-extern-2.rs new file mode 100644 index 0000000000000..9dbefdd531be3 --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-114682-5-extern-2.rs @@ -0,0 +1,13 @@ +// edition: 2018 +// aux-build: issue-114682-5-extern-1.rs +// compile-flags: --extern issue_114682_5_extern_1 + +pub mod p { + pub use crate::types::*; + pub use crate::*; +} +mod types { + pub mod issue_114682_5_extern_1 {} +} + +pub use issue_114682_5_extern_1; diff --git a/tests/ui/imports/auxiliary/issue-114682-6-extern.rs b/tests/ui/imports/auxiliary/issue-114682-6-extern.rs new file mode 100644 index 0000000000000..caf3c4e35a0e9 --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-114682-6-extern.rs @@ -0,0 +1,9 @@ +mod a { + pub fn log() {} +} +mod b { + pub fn log() {} +} + +pub use self::a::*; +pub use self::b::*; diff --git a/tests/ui/imports/auxiliary/issue-119369-extern.rs b/tests/ui/imports/auxiliary/issue-119369-extern.rs new file mode 100644 index 0000000000000..278cbfa1e3e54 --- /dev/null +++ b/tests/ui/imports/auxiliary/issue-119369-extern.rs @@ -0,0 +1,2 @@ +use std::vec; +use std::hash::Hash; diff --git a/tests/ui/imports/extern-with-ambiguous-2.rs b/tests/ui/imports/extern-with-ambiguous-2.rs index 68c623c1c4a65..b7c9cccdb6402 100644 --- a/tests/ui/imports/extern-with-ambiguous-2.rs +++ b/tests/ui/imports/extern-with-ambiguous-2.rs @@ -12,5 +12,7 @@ mod s { use s::*; use extern_with_ambiguous_2_extern::*; use error::*; +//^ FIXME: An ambiguity error should be thrown for `error`, +// as there is ambiguity present within `extern-with-ambiguous-2-extern.rs`. fn main() {} diff --git a/tests/ui/imports/extern-with-ambiguous-3.rs b/tests/ui/imports/extern-with-ambiguous-3.rs index 282c1d569b0cc..44a9a2a00a453 100644 --- a/tests/ui/imports/extern-with-ambiguous-3.rs +++ b/tests/ui/imports/extern-with-ambiguous-3.rs @@ -13,5 +13,7 @@ mod s { use s::*; use extern_with_ambiguous_3_extern::*; use error::*; +//^ FIXME: An ambiguity error should be thrown for `error`, +// as there is ambiguity present within `extern-with-ambiguous-3-extern.rs`. fn main() {} diff --git a/tests/ui/imports/glob-conflict-cross-crate.rs b/tests/ui/imports/glob-conflict-cross-crate-1.rs similarity index 54% rename from tests/ui/imports/glob-conflict-cross-crate.rs rename to tests/ui/imports/glob-conflict-cross-crate-1.rs index d84c243f2139c..832e6c888a646 100644 --- a/tests/ui/imports/glob-conflict-cross-crate.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-1.rs @@ -4,5 +4,9 @@ extern crate glob_conflict; fn main() { glob_conflict::f(); //~ ERROR cannot find function `f` in crate `glob_conflict` + //^ FIXME: `glob_conflict::f` should raise an + // ambiguity error instead of a not found error. glob_conflict::glob::f(); //~ ERROR cannot find function `f` in module `glob_conflict::glob` + //^ FIXME: `glob_conflict::glob::f` should raise an + // ambiguity error instead of a not found error. } diff --git a/tests/ui/imports/glob-conflict-cross-crate.stderr b/tests/ui/imports/glob-conflict-cross-crate-1.stderr similarity index 82% rename from tests/ui/imports/glob-conflict-cross-crate.stderr rename to tests/ui/imports/glob-conflict-cross-crate-1.stderr index 0e3b4222fe44f..758087107f397 100644 --- a/tests/ui/imports/glob-conflict-cross-crate.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-1.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find function `f` in crate `glob_conflict` - --> $DIR/glob-conflict-cross-crate.rs:6:20 + --> $DIR/glob-conflict-cross-crate-1.rs:6:20 | LL | glob_conflict::f(); | ^ not found in `glob_conflict` error[E0425]: cannot find function `f` in module `glob_conflict::glob` - --> $DIR/glob-conflict-cross-crate.rs:7:26 + --> $DIR/glob-conflict-cross-crate-1.rs:9:26 | LL | glob_conflict::glob::f(); | ^ not found in `glob_conflict::glob` diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.rs b/tests/ui/imports/glob-conflict-cross-crate-2.rs new file mode 100644 index 0000000000000..6ba71ad30ac54 --- /dev/null +++ b/tests/ui/imports/glob-conflict-cross-crate-2.rs @@ -0,0 +1,10 @@ +// aux-build:glob-conflict-cross-crate-2-extern.rs + +extern crate glob_conflict_cross_crate_2_extern; + +use glob_conflict_cross_crate_2_extern::*; + +fn main() { + let _a: C = 1; //~ ERROR cannot find type `C` in this scope + //^ FIXME: `C` should be identified as an ambiguous item. +} diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.stderr b/tests/ui/imports/glob-conflict-cross-crate-2.stderr new file mode 100644 index 0000000000000..aebb2d59d063a --- /dev/null +++ b/tests/ui/imports/glob-conflict-cross-crate-2.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `C` in this scope + --> $DIR/glob-conflict-cross-crate-2.rs:8:13 + | +LL | let _a: C = 1; + | ^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/imports/glob-conflict-cross-crate-3.rs b/tests/ui/imports/glob-conflict-cross-crate-3.rs new file mode 100644 index 0000000000000..535d87d8ea284 --- /dev/null +++ b/tests/ui/imports/glob-conflict-cross-crate-3.rs @@ -0,0 +1,16 @@ +// check-pass +// aux-build:glob-conflict-cross-crate-2-extern.rs + +extern crate glob_conflict_cross_crate_2_extern; + +mod a { + pub type C = i32; +} + +use glob_conflict_cross_crate_2_extern::*; +use a::*; + +fn main() { + let _a: C = 1; + //^ FIXME: `C` should be identified as an ambiguous item. +} diff --git a/tests/ui/imports/issue-114682-1.rs b/tests/ui/imports/issue-114682-1.rs new file mode 100644 index 0000000000000..88fe05e51444d --- /dev/null +++ b/tests/ui/imports/issue-114682-1.rs @@ -0,0 +1,25 @@ +// https://github.com/rust-lang/rust/pull/114682#discussion_r1420534109 + +#![feature(decl_macro)] + +macro_rules! mac { + () => { + pub macro A() { + println!("non import") + } + } +} + +mod m { + pub macro A() { + println!("import") + } +} + +pub use m::*; +mac!(); + +fn main() { + A!(); + //~^ ERROR `A` is ambiguous +} diff --git a/tests/ui/imports/issue-114682-1.stderr b/tests/ui/imports/issue-114682-1.stderr new file mode 100644 index 0000000000000..85fb7f7919e4e --- /dev/null +++ b/tests/ui/imports/issue-114682-1.stderr @@ -0,0 +1,28 @@ +error[E0659]: `A` is ambiguous + --> $DIR/issue-114682-1.rs:23:5 + | +LL | A!(); + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution +note: `A` could refer to the macro defined here + --> $DIR/issue-114682-1.rs:7:9 + | +LL | / pub macro A() { +LL | | println!("non import") +LL | | } + | |_________^ +... +LL | mac!(); + | ------ in this macro invocation +note: `A` could also refer to the macro imported here + --> $DIR/issue-114682-1.rs:19:9 + | +LL | pub use m::*; + | ^^^^ + = help: consider adding an explicit import of `A` to disambiguate + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/issue-114682-2.rs b/tests/ui/imports/issue-114682-2.rs new file mode 100644 index 0000000000000..491105e62efea --- /dev/null +++ b/tests/ui/imports/issue-114682-2.rs @@ -0,0 +1,19 @@ +// aux-build: issue-114682-2-extern.rs +// https://github.com/rust-lang/rust/pull/114682#issuecomment-1879998900 + +extern crate issue_114682_2_extern; + +use issue_114682_2_extern::max; + +type A = issue_114682_2_extern::max; +//~^ ERROR: expected type, found function `issue_114682_2_extern::max` +// FIXME: +// The above error was emitted due to `(Mod(issue_114682_2_extern), Namespace(Type), Ident(max))` +// being identified as an ambiguous item. +// However, there are two points worth discussing: +// First, should this ambiguous item be omitted considering the maximum visibility +// of `issue_114682_2_extern::m::max` in the type namespace is only within the extern crate. +// Second, if we retain the ambiguous item of the extern crate, should it be treated +// as an ambiguous item within the local crate for the same reasoning? + +fn main() {} diff --git a/tests/ui/imports/issue-114682-2.stderr b/tests/ui/imports/issue-114682-2.stderr new file mode 100644 index 0000000000000..972bcecb56bc2 --- /dev/null +++ b/tests/ui/imports/issue-114682-2.stderr @@ -0,0 +1,9 @@ +error[E0573]: expected type, found function `issue_114682_2_extern::max` + --> $DIR/issue-114682-2.rs:8:10 + | +LL | type A = issue_114682_2_extern::max; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/imports/issue-114682-3.rs b/tests/ui/imports/issue-114682-3.rs new file mode 100644 index 0000000000000..0f658bfe1597a --- /dev/null +++ b/tests/ui/imports/issue-114682-3.rs @@ -0,0 +1,24 @@ +// check-pass +// aux-build: issue-114682-3-extern.rs +// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880625909 + +extern crate issue_114682_3_extern; + +use issue_114682_3_extern::*; + +mod auto { + pub trait SettingsExt { + fn ext(&self) {} + } + + impl SettingsExt for T {} +} + +pub use self::auto::*; + +fn main() { + let a: u8 = 1; + a.ext(); + //^ FIXME: it should report `ext` not found because `SettingsExt` + // is an ambiguous item in `issue-114682-3-extern.rs`. +} diff --git a/tests/ui/imports/issue-114682-4.rs b/tests/ui/imports/issue-114682-4.rs new file mode 100644 index 0000000000000..97615c1041049 --- /dev/null +++ b/tests/ui/imports/issue-114682-4.rs @@ -0,0 +1,13 @@ +// check-pass +// aux-build: issue-114682-4-extern.rs +// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441 + +extern crate issue_114682_4_extern; + +use issue_114682_4_extern::*; + +fn a() -> Result { // FIXME: `Result` should be identified as an ambiguous item. + Ok(1) +} + +fn main() {} diff --git a/tests/ui/imports/issue-114682-5.rs b/tests/ui/imports/issue-114682-5.rs new file mode 100644 index 0000000000000..eb5ac10495bee --- /dev/null +++ b/tests/ui/imports/issue-114682-5.rs @@ -0,0 +1,15 @@ +// check-pass +// edition: 2018 +// aux-build: issue-114682-5-extern-1.rs +// aux-build: issue-114682-5-extern-2.rs +// compile-flags: --extern issue_114682_5_extern_1 +// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441 + +extern crate issue_114682_5_extern_2; + +use issue_114682_5_extern_2::p::*; +use issue_114682_5_extern_1::Url; +// FIXME: The `issue_114682_5_extern_1` should be considered an ambiguous item, +// as it has already been recognized as ambiguous in `issue_114682_5_extern_2`. + +fn main() {} diff --git a/tests/ui/imports/issue-114682-6.rs b/tests/ui/imports/issue-114682-6.rs new file mode 100644 index 0000000000000..29a7d9e942643 --- /dev/null +++ b/tests/ui/imports/issue-114682-6.rs @@ -0,0 +1,13 @@ +// check-pass +// aux-build: issue-114682-6-extern.rs +// https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441 + +extern crate issue_114682_6_extern; + +use issue_114682_6_extern::*; + +fn main() { + let log = 2; + //^ `log` should be identified as an ambiguous item. + let _ = log; +} diff --git a/tests/ui/imports/issue-119369.rs b/tests/ui/imports/issue-119369.rs new file mode 100644 index 0000000000000..0b4dc3f4654bd --- /dev/null +++ b/tests/ui/imports/issue-119369.rs @@ -0,0 +1,14 @@ +// check-pass +// aux-build: issue-119369-extern.rs + +// https://github.com/rust-lang/rust/pull/119369#issuecomment-1874905662 + +#[macro_use] +extern crate issue_119369_extern; + +#[derive(Hash)] +struct A; + +fn main() { + let _: Vec = vec![]; +} diff --git a/tests/ui/imports/issue-28134.rs b/tests/ui/imports/issue-28134.rs index ef2a5d634a678..0cecdf7a0ec73 100644 --- a/tests/ui/imports/issue-28134.rs +++ b/tests/ui/imports/issue-28134.rs @@ -1,5 +1,5 @@ // compile-flags: --test #![allow(soft_unstable)] -#![test] //~ ERROR cannot determine resolution for the attribute macro `test` +#![test] //~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level diff --git a/tests/ui/imports/issue-28134.stderr b/tests/ui/imports/issue-28134.stderr index 5315c2e9fee9c..e47aa15e87a94 100644 --- a/tests/ui/imports/issue-28134.stderr +++ b/tests/ui/imports/issue-28134.stderr @@ -1,11 +1,3 @@ -error: cannot determine resolution for the attribute macro `test` - --> $DIR/issue-28134.rs:4:4 - | -LL | #![test] - | ^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: `test` attribute cannot be used at crate level --> $DIR/issue-28134.rs:4:1 | @@ -18,5 +10,5 @@ LL - #![test] LL + #[test] | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-55457.rs b/tests/ui/imports/issue-55457.rs index c1f048897d9ea..fd08294025587 100644 --- a/tests/ui/imports/issue-55457.rs +++ b/tests/ui/imports/issue-55457.rs @@ -1,10 +1,9 @@ use NonExistent; //~ ERROR unresolved import `NonExistent` use non_existent::non_existent; //~ ERROR unresolved import `non_existent` -#[non_existent] //~ ERROR cannot determine resolution for the attribute macro `non_existent` -#[derive(NonExistent)] //~ ERROR cannot determine resolution for the derive macro `NonExistent` - //~| ERROR cannot determine resolution for the derive macro `NonExistent` - //~| ERROR cannot determine resolution for the derive macro `NonExistent` +#[non_existent] +#[derive(NonExistent)] + struct S; fn main() {} diff --git a/tests/ui/imports/issue-55457.stderr b/tests/ui/imports/issue-55457.stderr index 30d2373652b4c..09bb13a060478 100644 --- a/tests/ui/imports/issue-55457.stderr +++ b/tests/ui/imports/issue-55457.stderr @@ -15,40 +15,6 @@ LL | use non_existent::non_existent; | = help: consider adding `extern crate non_existent` to use the `non_existent` crate -error: cannot determine resolution for the derive macro `NonExistent` - --> $DIR/issue-55457.rs:5:10 - | -LL | #[derive(NonExistent)] - | ^^^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the attribute macro `non_existent` - --> $DIR/issue-55457.rs:4:3 - | -LL | #[non_existent] - | ^^^^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the derive macro `NonExistent` - --> $DIR/issue-55457.rs:5:10 - | -LL | #[derive(NonExistent)] - | ^^^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: cannot determine resolution for the derive macro `NonExistent` - --> $DIR/issue-55457.rs:5:10 - | -LL | #[derive(NonExistent)] - | ^^^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/issue-59764.rs b/tests/ui/imports/issue-59764.rs index 09dee8c273268..91b3ddcd84d57 100644 --- a/tests/ui/imports/issue-59764.rs +++ b/tests/ui/imports/issue-59764.rs @@ -128,7 +128,6 @@ use issue_59764::foo::makro; //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] makro!(bar); -//~^ ERROR cannot determine resolution for the macro `makro` fn main() { bar(); diff --git a/tests/ui/imports/issue-59764.stderr b/tests/ui/imports/issue-59764.stderr index b969515e2f0e6..fe58eb97b8dbf 100644 --- a/tests/ui/imports/issue-59764.stderr +++ b/tests/ui/imports/issue-59764.stderr @@ -226,21 +226,13 @@ help: a macro with this name exists at the root of the crate LL | use issue_59764::makro; | ~~~~~~~~~~~~~~~~~~ -error: cannot determine resolution for the macro `makro` - --> $DIR/issue-59764.rs:130:1 - | -LL | makro!(bar); - | ^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error[E0425]: cannot find function `bar` in this scope - --> $DIR/issue-59764.rs:134:5 + --> $DIR/issue-59764.rs:133:5 | LL | bar(); | ^^^ not found in this scope -error: aborting due to 18 previous errors +error: aborting due to 17 previous errors Some errors have detailed explanations: E0425, E0432. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/indexing/index-help.stderr b/tests/ui/indexing/index-help.stderr index 4ec28ddf87171..1291bf2a4611e 100644 --- a/tests/ui/indexing/index-help.stderr +++ b/tests/ui/indexing/index-help.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32` LL | x[0i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32`, which is required by `Vec<{integer}>: Index<_>` = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `Vec<{integer}>` to implement `Index` diff --git a/tests/ui/indexing/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr index 3041c2c99a108..38e7881dcc675 100644 --- a/tests/ui/indexing/indexing-requires-a-uint.stderr +++ b/tests/ui/indexing/indexing-requires-a-uint.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8` LL | [0][0u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8`, which is required by `[{integer}; 1]: Index<_>` = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `[{integer}]` to implement `Index` diff --git a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr index 4cced22789f74..df4d7cc0683d5 100644 --- a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr +++ b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: Borrow<&str>` is not satisfied --> $DIR/point-at-index-for-obligation-failure.rs:5:9 | LL | &s - | ^^ the trait `Borrow<&str>` is not implemented for `String` + | ^^ the trait `Borrow<&str>` is not implemented for `String`, which is required by `HashMap: Index<&_>` | = help: the trait `Borrow` is implemented for `String` = help: for that trait implementation, expected `str`, found `&str` diff --git a/tests/ui/inference/erase-type-params-in-label.stderr b/tests/ui/inference/erase-type-params-in-label.stderr index 9be1828648011..546e679f2d0bc 100644 --- a/tests/ui/inference/erase-type-params-in-label.stderr +++ b/tests/ui/inference/erase-type-params-in-label.stderr @@ -2,7 +2,7 @@ error[E0283]: type annotations needed for `Foo` --> $DIR/erase-type-params-in-label.rs:2:9 | LL | let foo = foo(1, ""); - | ^^^ --- type must be known at this point + | ^^^ ---------- type must be known at this point | = note: cannot satisfy `_: Default` note: required by a bound in `foo` @@ -19,7 +19,7 @@ error[E0283]: type annotations needed for `Bar` --> $DIR/erase-type-params-in-label.rs:5:9 | LL | let bar = bar(1, ""); - | ^^^ --- type must be known at this point + | ^^^ ---------- type must be known at this point | = note: cannot satisfy `_: Default` note: required by a bound in `bar` diff --git a/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr b/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr index aeebf68e67576..5576e17546873 100644 --- a/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr +++ b/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr @@ -2,7 +2,7 @@ error[E0790]: cannot call associated function on trait without specifying the co --> $DIR/infer-var-for-self-param.rs:5:14 | LL | let _ = (Default::default(),); - | ^^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation | diff --git a/tests/ui/inference/need_type_info/type-alias.rs b/tests/ui/inference/need_type_info/type-alias.rs index f921b046b6cac..b24af2d484954 100644 --- a/tests/ui/inference/need_type_info/type-alias.rs +++ b/tests/ui/inference/need_type_info/type-alias.rs @@ -15,7 +15,7 @@ fn direct_alias() { type IndirectAlias = Ty>; fn indirect_alias() { - IndirectAlias::new(); + IndirectAlias::new(); //~ ERROR: type annotations needed // FIXME: This should also emit an error. // // Added it separately as `type-alias-indirect.rs` diff --git a/tests/ui/inference/need_type_info/type-alias.stderr b/tests/ui/inference/need_type_info/type-alias.stderr index a33f49baf549f..2c39a3f56466f 100644 --- a/tests/ui/inference/need_type_info/type-alias.stderr +++ b/tests/ui/inference/need_type_info/type-alias.stderr @@ -2,14 +2,20 @@ error[E0282]: type annotations needed --> $DIR/type-alias.rs:12:5 | LL | DirectAlias::new() - | ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + +error[E0282]: type annotations needed + --> $DIR/type-alias.rs:18:5 + | +LL | IndirectAlias::new(); + | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error[E0282]: type annotations needed --> $DIR/type-alias.rs:32:5 | LL | DirectButWithDefaultAlias::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/inline-const/const-match-pat-generic.rs b/tests/ui/inline-const/const-match-pat-generic.rs index 46e501abf6c2e..9d76fc2ad65bc 100644 --- a/tests/ui/inline-const/const-match-pat-generic.rs +++ b/tests/ui/inline-const/const-match-pat-generic.rs @@ -1,4 +1,3 @@ -#![allow(incomplete_features)] #![feature(inline_const_pat)] // rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr index 4ffbde4101d72..15c3a876afcf7 100644 --- a/tests/ui/inline-const/const-match-pat-generic.stderr +++ b/tests/ui/inline-const/const-match-pat-generic.stderr @@ -1,11 +1,11 @@ error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:8:9 + --> $DIR/const-match-pat-generic.rs:7:9 | LL | const { V } => {}, | ^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:20:9 + --> $DIR/const-match-pat-generic.rs:19:9 | LL | const { f(V) } => {}, | ^^^^^^^^^^^^^^ diff --git a/tests/ui/inline-const/const-match-pat-inference.rs b/tests/ui/inline-const/const-match-pat-inference.rs index d83ae6e983486..c595824833f5f 100644 --- a/tests/ui/inline-const/const-match-pat-inference.rs +++ b/tests/ui/inline-const/const-match-pat-inference.rs @@ -1,7 +1,6 @@ // check-pass #![feature(inline_const_pat)] -#![allow(incomplete_features)] fn main() { match 1u64 { diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs index 366ad26bb2716..ff0a9dbf110c4 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.rs @@ -1,6 +1,3 @@ -// ignore-test (This is currently broken) - -#![allow(incomplete_features)] #![feature(const_mut_refs)] #![feature(inline_const_pat)] @@ -9,6 +6,9 @@ use std::marker::PhantomData; #[derive(PartialEq, Eq)] pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); +#[derive(PartialEq, Eq)] +pub struct CovariantRef<'a, T: ?Sized>(&'a T); + impl<'a, T: ?Sized> InvariantRef<'a, T> { pub const fn new(r: &'a T) -> Self { InvariantRef(r, PhantomData) @@ -19,16 +19,30 @@ impl<'a> InvariantRef<'a, ()> { pub const NEW: Self = InvariantRef::new(&()); } +impl<'a> CovariantRef<'a, ()> { + pub const NEW: Self = CovariantRef(&()); +} + fn match_invariant_ref<'a>() { let y = (); match InvariantRef::new(&y) { - //~^ ERROR `y` does not live long enough [E0597] - // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without - // const block) + //~^ ERROR `y` does not live long enough [E0597] const { InvariantRef::<'a>::NEW } => (), } } +fn match_covariant_ref<'a>() { + // Unclear if we should error here (should we be able to subtype the type of + // `y.0`), but using the associated const directly in the pattern also + // errors. + let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); + //~^ ERROR lifetime may not live long enough + match y.0 { + const { CovariantRef::<'a>::NEW } => (), + } +} + fn main() { match_invariant_ref(); + match_covariant_ref(); } diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr new file mode 100644 index 0000000000000..98ce6cfae7b38 --- /dev/null +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr @@ -0,0 +1,28 @@ +error[E0597]: `y` does not live long enough + --> $DIR/const-match-pat-lifetime-err.rs:28:29 + | +LL | fn match_invariant_ref<'a>() { + | -- lifetime `'a` defined here +LL | let y = (); + | - binding `y` declared here +LL | match InvariantRef::new(&y) { + | ^^ borrowed value does not live long enough +LL | +LL | const { InvariantRef::<'a>::NEW } => (), + | --------------------------------- type annotation requires that `y` is borrowed for `'a` +LL | } +LL | } + | - `y` dropped here while still borrowed + +error: lifetime may not live long enough + --> $DIR/const-match-pat-lifetime-err.rs:38:12 + | +LL | fn match_covariant_ref<'a>() { + | -- lifetime `'a` defined here +... +LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/inline-const/const-match-pat-lifetime.rs b/tests/ui/inline-const/const-match-pat-lifetime.rs index 6d943bbcc0160..595741b101e93 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime.rs @@ -1,6 +1,5 @@ // run-pass -#![allow(incomplete_features)] #![feature(const_mut_refs)] #![feature(inline_const)] #![feature(inline_const_pat)] diff --git a/tests/ui/inline-const/const-match-pat-range.rs b/tests/ui/inline-const/const-match-pat-range.rs index 73d6334c36f8e..0f9372c537f89 100644 --- a/tests/ui/inline-const/const-match-pat-range.rs +++ b/tests/ui/inline-const/const-match-pat-range.rs @@ -1,6 +1,5 @@ // build-pass -#![allow(incomplete_features)] #![feature(inline_const_pat, exclusive_range_pattern)] fn main() { diff --git a/tests/ui/inline-const/const-match-pat.rs b/tests/ui/inline-const/const-match-pat.rs index 2f55e16b35cd9..fc4d37714585e 100644 --- a/tests/ui/inline-const/const-match-pat.rs +++ b/tests/ui/inline-const/const-match-pat.rs @@ -1,6 +1,5 @@ // run-pass -#![allow(incomplete_features)] #![feature(inline_const_pat)] const MMIO_BIT1: u8 = 4; const MMIO_BIT2: u8 = 5; diff --git a/tests/ui/inline-const/pat-match-fndef.rs b/tests/ui/inline-const/pat-match-fndef.rs index fbd4dc66c3a05..013a4a6756102 100644 --- a/tests/ui/inline-const/pat-match-fndef.rs +++ b/tests/ui/inline-const/pat-match-fndef.rs @@ -1,5 +1,4 @@ #![feature(inline_const_pat)] -//~^ WARN the feature `inline_const_pat` is incomplete fn uwu() {} diff --git a/tests/ui/inline-const/pat-match-fndef.stderr b/tests/ui/inline-const/pat-match-fndef.stderr index 02c4a60b68f20..b189ec51ade38 100644 --- a/tests/ui/inline-const/pat-match-fndef.stderr +++ b/tests/ui/inline-const/pat-match-fndef.stderr @@ -1,17 +1,8 @@ -warning: the feature `inline_const_pat` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/pat-match-fndef.rs:1:12 - | -LL | #![feature(inline_const_pat)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #76001 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `fn() {uwu}` cannot be used in patterns - --> $DIR/pat-match-fndef.rs:9:9 + --> $DIR/pat-match-fndef.rs:8:9 | LL | const { uwu } => {} | ^^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs index 0db18dd3260d0..b906def702950 100644 --- a/tests/ui/inline-const/pat-unsafe-err.rs +++ b/tests/ui/inline-const/pat-unsafe-err.rs @@ -1,6 +1,3 @@ -// ignore-test This is currently broken - -#![allow(incomplete_features)] #![feature(inline_const_pat)] const unsafe fn require_unsafe() -> usize { diff --git a/tests/ui/inline-const/pat-unsafe-err.stderr b/tests/ui/inline-const/pat-unsafe-err.stderr new file mode 100644 index 0000000000000..786c7f31ccce1 --- /dev/null +++ b/tests/ui/inline-const/pat-unsafe-err.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block + --> $DIR/pat-unsafe-err.rs:10:13 + | +LL | require_unsafe(); + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block + --> $DIR/pat-unsafe-err.rs:17:13 + | +LL | require_unsafe() + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs index cfef9ad6a563e..5a90920ef3cff 100644 --- a/tests/ui/inline-const/pat-unsafe.rs +++ b/tests/ui/inline-const/pat-unsafe.rs @@ -1,7 +1,5 @@ // check-pass -// ignore-test This is currently broken -#![allow(incomplete_features)] #![warn(unused_unsafe)] #![feature(inline_const_pat)] diff --git a/tests/ui/inline-const/pat-unsafe.stderr b/tests/ui/inline-const/pat-unsafe.stderr new file mode 100644 index 0000000000000..59460271ac010 --- /dev/null +++ b/tests/ui/inline-const/pat-unsafe.stderr @@ -0,0 +1,20 @@ +warning: unnecessary `unsafe` block + --> $DIR/pat-unsafe.rs:15:17 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/pat-unsafe.rs:3:9 + | +LL | #![warn(unused_unsafe)] + | ^^^^^^^^^^^^^ + +warning: unnecessary `unsafe` block + --> $DIR/pat-unsafe.rs:22:17 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +warning: 2 warnings emitted + diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr index ff6558e494b11..88d33b44c5931 100644 --- a/tests/ui/inner-static-type-parameter.stderr +++ b/tests/ui/inner-static-type-parameter.stderr @@ -5,15 +5,17 @@ LL | fn foo() { | - type parameter from outer item LL | static a: Bar = Bar::What; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/inner-static-type-parameter.rs:3:10 | LL | enum Bar { What } - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/integral-indexing.stderr b/tests/ui/integral-indexing.stderr index 97e658617cf03..ad2c3af424be8 100644 --- a/tests/ui/integral-indexing.stderr +++ b/tests/ui/integral-indexing.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` LL | v[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `u8` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u8`, which is required by `Vec: Index<_>` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `Vec` to implement `Index` @@ -15,7 +15,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `i8` LL | v[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `i8` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i8`, which is required by `Vec: Index<_>` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i8` = note: required for `Vec` to implement `Index` @@ -26,7 +26,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u32` LL | v[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `u32` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u32`, which is required by `Vec: Index<_>` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u32` = note: required for `Vec` to implement `Index` @@ -37,7 +37,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `i32` LL | v[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `i32` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i32`, which is required by `Vec: Index<_>` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `Vec` to implement `Index` @@ -48,7 +48,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `u8` LL | s.as_bytes()[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `u8` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u8`, which is required by `[u8]: Index<_>` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `[u8]` to implement `Index` @@ -59,7 +59,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `i8` LL | s.as_bytes()[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `i8` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i8`, which is required by `[u8]: Index<_>` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i8` = note: required for `[u8]` to implement `Index` @@ -70,7 +70,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `u32` LL | s.as_bytes()[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `u32` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u32`, which is required by `[u8]: Index<_>` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u32` = note: required for `[u8]` to implement `Index` @@ -81,7 +81,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `i32` LL | s.as_bytes()[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `i32` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i32`, which is required by `[u8]: Index<_>` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `[u8]` to implement `Index` diff --git a/tests/ui/interior-mutability/interior-mutability.stderr b/tests/ui/interior-mutability/interior-mutability.stderr index 36686565e2e3a..7b08a6454052d 100644 --- a/tests/ui/interior-mutability/interior-mutability.stderr +++ b/tests/ui/interior-mutability/interior-mutability.stderr @@ -6,7 +6,7 @@ LL | catch_unwind(|| { x.set(23); }); | | | required by a bound introduced by this call | - = help: within `Cell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `Cell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `{closure@$DIR/interior-mutability.rs:5:18: 5:20}: UnwindSafe` note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `&Cell` to implement `UnwindSafe` diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs index 1eb27fbdc3a63..a4445fefef57d 100644 --- a/tests/ui/internal/internal-unstable.rs +++ b/tests/ui/internal/internal-unstable.rs @@ -28,6 +28,14 @@ macro_rules! bar { }} } +#[allow_internal_unstable(stmt_expr_attributes)] +macro_rules! internal_attr { + ($e: expr) => { + #[allow(overflowing_literals)] + $e + } +} + fn main() { // ok, the instability is contained. call_unstable_allow!(); @@ -51,4 +59,6 @@ fn main() { #[allow_internal_unstable] _ => {} } + + assert_eq!(internal_attr!(1e100_f32), f32::INFINITY); } diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr index af5ac21e69640..78b9109d1c287 100644 --- a/tests/ui/internal/internal-unstable.stderr +++ b/tests/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:40:25 + --> $DIR/internal-unstable.rs:48:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:42:27 + --> $DIR/internal-unstable.rs:50:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:46:22 + --> $DIR/internal-unstable.rs:54:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:48:10 + --> $DIR/internal-unstable.rs:56:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issue-76387-llvm-miscompile.rs b/tests/ui/issue-76387-llvm-miscompile.rs index a9b4686c97021..a7fc9da633963 100644 --- a/tests/ui/issue-76387-llvm-miscompile.rs +++ b/tests/ui/issue-76387-llvm-miscompile.rs @@ -1,4 +1,3 @@ -// no-system-llvm // compile-flags: -C opt-level=3 // aux-build: issue-76387.rs // run-pass diff --git a/tests/ui/issues/issue-10412.stderr b/tests/ui/issues/issue-10412.stderr index 26666782d2abc..02a26034f9aa7 100644 --- a/tests/ui/issues/issue-10412.stderr +++ b/tests/ui/issues/issue-10412.stderr @@ -58,11 +58,11 @@ LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` -note: required by a bound in `Serializable` +note: required by an implicit `Sized` bound in `Serializable` --> $DIR/issue-10412.rs:1:27 | LL | trait Serializable<'self, T> { - | ^ required by this bound in `Serializable` + | ^ required by the implicit `Sized` requirement on this type parameter in `Serializable` help: consider relaxing the implicit `Sized` restriction | LL | trait Serializable<'self, T: ?Sized> { diff --git a/tests/ui/issues/issue-14399.rs b/tests/ui/issues/issue-14399.rs index 7b32bf8e4cbb7..0c6c4d8dc6bd3 100644 --- a/tests/ui/issues/issue-14399.rs +++ b/tests/ui/issues/issue-14399.rs @@ -9,7 +9,7 @@ #[derive(Clone)] struct B1; -trait A { fn foo(&self) {} } +trait A { fn foo(&self) {} } //~ WARN method `foo` is never used impl A for B1 {} fn main() { diff --git a/tests/ui/issues/issue-14399.stderr b/tests/ui/issues/issue-14399.stderr new file mode 100644 index 0000000000000..d226ece6fb0b6 --- /dev/null +++ b/tests/ui/issues/issue-14399.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/issue-14399.rs:12:14 + | +LL | trait A { fn foo(&self) {} } + | - ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-15858.rs b/tests/ui/issues/issue-15858.rs index 77941c07671d6..e3e3c293d7a74 100644 --- a/tests/ui/issues/issue-15858.rs +++ b/tests/ui/issues/issue-15858.rs @@ -2,7 +2,7 @@ static mut DROP_RAN: bool = false; trait Bar { - fn do_something(&mut self); + fn do_something(&mut self); //~ WARN method `do_something` is never used } struct BarImpl; diff --git a/tests/ui/issues/issue-15858.stderr b/tests/ui/issues/issue-15858.stderr new file mode 100644 index 0000000000000..f36bcc21bd7fb --- /dev/null +++ b/tests/ui/issues/issue-15858.stderr @@ -0,0 +1,12 @@ +warning: method `do_something` is never used + --> $DIR/issue-15858.rs:5:8 + | +LL | trait Bar { + | --- method in this trait +LL | fn do_something(&mut self); + | ^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-17351.rs b/tests/ui/issues/issue-17351.rs index 62f6bcf15e3e7..12bb8a73b7bd4 100644 --- a/tests/ui/issues/issue-17351.rs +++ b/tests/ui/issues/issue-17351.rs @@ -1,7 +1,7 @@ // run-pass // pretty-expanded FIXME #23616 -trait Str { fn foo(&self) {} } +trait Str { fn foo(&self) {} } //~ WARN method `foo` is never used impl Str for str {} impl<'a, S: ?Sized> Str for &'a S where S: Str {} diff --git a/tests/ui/issues/issue-17351.stderr b/tests/ui/issues/issue-17351.stderr new file mode 100644 index 0000000000000..3242d578dabce --- /dev/null +++ b/tests/ui/issues/issue-17351.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/issue-17351.rs:4:16 + | +LL | trait Str { fn foo(&self) {} } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-17904-2.stderr b/tests/ui/issues/issue-17904-2.stderr index 102c8537f8e04..9965106d1401a 100644 --- a/tests/ui/issues/issue-17904-2.stderr +++ b/tests/ui/issues/issue-17904-2.stderr @@ -1,8 +1,8 @@ -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-17904-2.rs:4:12 | LL | struct Foo where T: Copy; - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/issues/issue-17994.rs b/tests/ui/issues/issue-17994.rs index 39b0a7ebe74d8..ab37a172eaa74 100644 --- a/tests/ui/issues/issue-17994.rs +++ b/tests/ui/issues/issue-17994.rs @@ -1,3 +1,3 @@ trait Tr {} -type Huh where T: Tr = isize; //~ ERROR type parameter `T` is unused +type Huh where T: Tr = isize; //~ ERROR type parameter `T` is never used fn main() {} diff --git a/tests/ui/issues/issue-17994.stderr b/tests/ui/issues/issue-17994.stderr index ba3def64dfb5d..f149e5d08faac 100644 --- a/tests/ui/issues/issue-17994.stderr +++ b/tests/ui/issues/issue-17994.stderr @@ -1,8 +1,10 @@ -error[E0091]: type parameter `T` is unused +error[E0091]: type parameter `T` is never used --> $DIR/issue-17994.rs:2:10 | LL | type Huh where T: Tr = isize; | ^ unused type parameter + | + = help: consider removing `T` or referring to it in the body of the type alias error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-18173.rs b/tests/ui/issues/issue-18173.rs index 11468040ee530..010efee9f8ab6 100644 --- a/tests/ui/issues/issue-18173.rs +++ b/tests/ui/issues/issue-18173.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass trait Foo { type T; } diff --git a/tests/ui/issues/issue-18919.stderr b/tests/ui/issues/issue-18919.stderr index 6dcd891cedac9..714b6d7d86be3 100644 --- a/tests/ui/issues/issue-18919.stderr +++ b/tests/ui/issues/issue-18919.stderr @@ -5,11 +5,11 @@ LL | fn ho_func(f: Option) { | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn for<'a> Fn(&'a isize) -> isize` -note: required by a bound in `Option` +note: required by an implicit `Sized` bound in `Option` --> $DIR/issue-18919.rs:7:13 | LL | enum Option { - | ^ required by this bound in `Option` + | ^ required by the implicit `Sized` requirement on this type parameter in `Option` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-18919.rs:7:13 | diff --git a/tests/ui/issues/auxiliary/issue-1920.rs b/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-1920.rs rename to tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs diff --git a/tests/ui/issues/issue-1920-1.rs b/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs similarity index 100% rename from tests/ui/issues/issue-1920-1.rs rename to tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs diff --git a/tests/ui/issues/issue-1920-1.stderr b/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr similarity index 100% rename from tests/ui/issues/issue-1920-1.stderr rename to tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr diff --git a/tests/ui/issues/issue-1920-2.rs b/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs similarity index 100% rename from tests/ui/issues/issue-1920-2.rs rename to tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs diff --git a/tests/ui/issues/issue-1920-2.stderr b/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr similarity index 100% rename from tests/ui/issues/issue-1920-2.stderr rename to tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr diff --git a/tests/ui/issues/issue-1920-3.rs b/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs similarity index 100% rename from tests/ui/issues/issue-1920-3.rs rename to tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs diff --git a/tests/ui/issues/issue-1920-3.stderr b/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr similarity index 100% rename from tests/ui/issues/issue-1920-3.stderr rename to tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr diff --git a/tests/ui/issues/issue-20055-box-trait.rs b/tests/ui/issues/issue-20055-box-trait.rs index 772cd9d7eda82..36f597450adb8 100644 --- a/tests/ui/issues/issue-20055-box-trait.rs +++ b/tests/ui/issues/issue-20055-box-trait.rs @@ -8,7 +8,7 @@ // statement surrounding the `match`. trait Boo { - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } impl Boo for [i8; 1] { } diff --git a/tests/ui/issues/issue-20055-box-trait.stderr b/tests/ui/issues/issue-20055-box-trait.stderr new file mode 100644 index 0000000000000..db9d359e2252c --- /dev/null +++ b/tests/ui/issues/issue-20055-box-trait.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-20055-box-trait.rs:11:8 + | +LL | trait Boo { + | --- method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-20413.stderr b/tests/ui/issues/issue-20413.stderr index 8793029dd224a..5d442eb989851 100644 --- a/tests/ui/issues/issue-20413.stderr +++ b/tests/ui/issues/issue-20413.stderr @@ -1,11 +1,11 @@ -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-20413.rs:6:15 | LL | struct NoData; - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error[E0275]: overflow evaluating the requirement `NoData>>>>>>: Foo` --> $DIR/issue-20413.rs:9:36 diff --git a/tests/ui/issues/issue-20433.stderr b/tests/ui/issues/issue-20433.stderr index 2dd0b3c2f8439..3730a67cc7959 100644 --- a/tests/ui/issues/issue-20433.stderr +++ b/tests/ui/issues/issue-20433.stderr @@ -5,7 +5,7 @@ LL | fn iceman(c: Vec<[i32]>) {} | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[i32]` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-21763.stderr b/tests/ui/issues/issue-21763.stderr index 135b705eeeff2..aa4938a0c0b3a 100644 --- a/tests/ui/issues/issue-21763.stderr +++ b/tests/ui/issues/issue-21763.stderr @@ -4,7 +4,7 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely LL | foo::, Rc<()>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely | - = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>` + = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`, which is required by `HashMap, Rc<()>>: Send` = note: required because it appears within the type `(Rc<()>, Rc<()>)` = note: required for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` to implement `Send` note: required because it appears within the type `hashbrown::map::HashMap, Rc<()>, RandomState>` diff --git a/tests/ui/issues/issue-21909.rs b/tests/ui/issues/issue-21909.rs index 7cb558d9a4fa6..6a6cdcfee159d 100644 --- a/tests/ui/issues/issue-21909.rs +++ b/tests/ui/issues/issue-21909.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait A { diff --git a/tests/ui/issues/issue-22872.stderr b/tests/ui/issues/issue-22872.stderr index 6ff710b113325..03e5393da4882 100644 --- a/tests/ui/issues/issue-22872.stderr +++ b/tests/ui/issues/issue-22872.stderr @@ -4,7 +4,7 @@ error[E0277]: `

>::Item` is not an iterator LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

>::Item` is not an iterator | - = help: the trait `Iterator` is not implemented for `

>::Item` + = help: the trait `Iterator` is not implemented for `

>::Item`, which is required by `for<'b> Wrapper

: Wrap<'b>` note: required for `Wrapper

` to implement `for<'b> Wrap<'b>` --> $DIR/issue-22872.rs:7:13 | diff --git a/tests/ui/issues/issue-23281.stderr b/tests/ui/issues/issue-23281.stderr index e1f4e8a96c825..ee079f2deeca3 100644 --- a/tests/ui/issues/issue-23281.stderr +++ b/tests/ui/issues/issue-23281.stderr @@ -5,11 +5,11 @@ LL | pub fn function(funs: Vec ()>) {} | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $DIR/issue-23281.rs:8:12 | LL | struct Vec { - | ^ required by this bound in `Vec` + | ^ required by the implicit `Sized` requirement on this type parameter in `Vec` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-23281.rs:8:12 | diff --git a/tests/ui/issues/issue-23302-1.rs b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs similarity index 100% rename from tests/ui/issues/issue-23302-1.rs rename to tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs diff --git a/tests/ui/issues/issue-23302-1.stderr b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr similarity index 78% rename from tests/ui/issues/issue-23302-1.stderr rename to tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr index 5c2758dc60900..53131f9130d9c 100644 --- a/tests/ui/issues/issue-23302-1.stderr +++ b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr @@ -10,11 +10,15 @@ note: ...which requires const-evaluating + checking `X::A::{constant#0}`... LL | A = X::A as isize, | ^^^^^^^^^^^^^ = note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle -note: cycle used when simplifying constant for the type system `X::A::{constant#0}` - --> $DIR/issue-23302-1.rs:4:9 +note: cycle used when collecting item types in top-level module + --> $DIR/issue-23302-1.rs:3:1 | -LL | A = X::A as isize, - | ^^^^^^^^^^^^^ +LL | / enum X { +LL | | A = X::A as isize, +LL | | } +LL | | +LL | | fn main() { } + | |_____________^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-23302-2.rs b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs similarity index 100% rename from tests/ui/issues/issue-23302-2.rs rename to tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs diff --git a/tests/ui/issues/issue-23302-2.stderr b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr similarity index 77% rename from tests/ui/issues/issue-23302-2.stderr rename to tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr index 93665af69dd8d..d55d88762be43 100644 --- a/tests/ui/issues/issue-23302-2.stderr +++ b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr @@ -10,11 +10,16 @@ note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... LL | A = Y::B as isize, | ^^^^^^^^^^^^^ = note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle -note: cycle used when simplifying constant for the type system `Y::A::{constant#0}` - --> $DIR/issue-23302-2.rs:4:9 +note: cycle used when collecting item types in top-level module + --> $DIR/issue-23302-2.rs:3:1 | -LL | A = Y::B as isize, - | ^^^^^^^^^^^^^ +LL | / enum Y { +LL | | A = Y::B as isize, +LL | | B, +LL | | } +LL | | +LL | | fn main() { } + | |_____________^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-23302-3.rs b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs similarity index 100% rename from tests/ui/issues/issue-23302-3.rs rename to tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs diff --git a/tests/ui/issues/issue-23302-3.stderr b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr similarity index 86% rename from tests/ui/issues/issue-23302-3.stderr rename to tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr index b3e933a21718e..e23957c6de754 100644 --- a/tests/ui/issues/issue-23302-3.stderr +++ b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr @@ -20,11 +20,15 @@ note: ...which requires const-evaluating + checking `B`... LL | const B: i32 = A; | ^ = note: ...which again requires simplifying constant for the type system `A`, completing the cycle -note: cycle used when simplifying constant for the type system `A` +note: cycle used when linting top-level module --> $DIR/issue-23302-3.rs:1:1 | -LL | const A: i32 = B; - | ^^^^^^^^^^^^ +LL | / const A: i32 = B; +LL | | +LL | | const B: i32 = A; +LL | | +LL | | fn main() { } + | |_____________^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-23485.rs b/tests/ui/issues/issue-23485.rs index 1dd3d9293bcc6..07ed0f1b00df8 100644 --- a/tests/ui/issues/issue-23485.rs +++ b/tests/ui/issues/issue-23485.rs @@ -17,7 +17,7 @@ trait Iterator { fn next(&mut self) -> Option; - fn clone_first(mut self) -> Option<::Target> where + fn clone_first(mut self) -> Option<::Target> where //~ WARN method `clone_first` is never used Self: Sized, Self::Item: Deref, ::Target: Clone, diff --git a/tests/ui/issues/issue-23485.stderr b/tests/ui/issues/issue-23485.stderr new file mode 100644 index 0000000000000..ed2d2400d0d93 --- /dev/null +++ b/tests/ui/issues/issue-23485.stderr @@ -0,0 +1,13 @@ +warning: method `clone_first` is never used + --> $DIR/issue-23485.rs:20:8 + | +LL | trait Iterator { + | -------- method in this trait +... +LL | fn clone_first(mut self) -> Option<::Target> where + | ^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-2989.rs b/tests/ui/issues/issue-2989.rs index c0b67374370e7..a95867514073c 100644 --- a/tests/ui/issues/issue-2989.rs +++ b/tests/ui/issues/issue-2989.rs @@ -1,8 +1,8 @@ // run-pass #![allow(non_camel_case_types)] -trait methods { - fn to_bytes(&self) -> Vec ; +trait methods { //~ WARN trait `methods` is never used + fn to_bytes(&self) -> Vec; } impl methods for () { diff --git a/tests/ui/issues/issue-2989.stderr b/tests/ui/issues/issue-2989.stderr new file mode 100644 index 0000000000000..57181607cecd3 --- /dev/null +++ b/tests/ui/issues/issue-2989.stderr @@ -0,0 +1,10 @@ +warning: trait `methods` is never used + --> $DIR/issue-2989.rs:4:7 + | +LL | trait methods { + | ^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-30236.rs b/tests/ui/issues/issue-30236.rs index 9c2d855076d79..08d08a544021e 100644 --- a/tests/ui/issues/issue-30236.rs +++ b/tests/ui/issues/issue-30236.rs @@ -1,5 +1,5 @@ type Foo< - Unused //~ ERROR type parameter `Unused` is unused + Unused //~ ERROR type parameter `Unused` is never used > = u8; fn main() { diff --git a/tests/ui/issues/issue-30236.stderr b/tests/ui/issues/issue-30236.stderr index 0f69f49f505a0..bfe374a653f5f 100644 --- a/tests/ui/issues/issue-30236.stderr +++ b/tests/ui/issues/issue-30236.stderr @@ -1,8 +1,11 @@ -error[E0091]: type parameter `Unused` is unused +error[E0091]: type parameter `Unused` is never used --> $DIR/issue-30236.rs:2:5 | LL | Unused | ^^^^^^ unused type parameter + | + = help: consider removing `Unused` or referring to it in the body of the type alias + = help: if you intended `Unused` to be a const parameter, use `const Unused: /* Type */` instead error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-31910.stderr b/tests/ui/issues/issue-31910.stderr index 89a6d5574a1e5..ca2d2f619e62e 100644 --- a/tests/ui/issues/issue-31910.stderr +++ b/tests/ui/issues/issue-31910.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | X = Trait::Number, | ^^^^^^^^^^^^^ expected `isize`, found `i32` -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-31910.rs:1:11 | LL | enum Enum { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/issues/issue-32122-1.fixed b/tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.fixed similarity index 100% rename from tests/ui/issues/issue-32122-1.fixed rename to tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.fixed diff --git a/tests/ui/issues/issue-32122-1.rs b/tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.rs similarity index 100% rename from tests/ui/issues/issue-32122-1.rs rename to tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.rs diff --git a/tests/ui/issues/issue-32122-1.stderr b/tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.stderr similarity index 100% rename from tests/ui/issues/issue-32122-1.stderr rename to tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.stderr diff --git a/tests/ui/issues/issue-32122-2.fixed b/tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.fixed similarity index 100% rename from tests/ui/issues/issue-32122-2.fixed rename to tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.fixed diff --git a/tests/ui/issues/issue-32122-2.rs b/tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.rs similarity index 100% rename from tests/ui/issues/issue-32122-2.rs rename to tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.rs diff --git a/tests/ui/issues/issue-32122-2.stderr b/tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.stderr similarity index 100% rename from tests/ui/issues/issue-32122-2.stderr rename to tests/ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.stderr diff --git a/tests/ui/issues/issue-34074.rs b/tests/ui/issues/issue-34074.rs index 0600d3937c16e..ca7d7b49a042f 100644 --- a/tests/ui/issues/issue-34074.rs +++ b/tests/ui/issues/issue-34074.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Make sure several unnamed function parameters don't conflict with each other trait Tr { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 1a1cfc925b779..13667cd920e9b 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -45,14 +45,14 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo(_: T) where Self: Sized {} | +++++++++++++++++ -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-34373.rs:7:16 | LL | pub struct Foo>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unused parameter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-34503.rs b/tests/ui/issues/issue-34503.rs index 26e7358408f48..d2c95d990ecde 100644 --- a/tests/ui/issues/issue-34503.rs +++ b/tests/ui/issues/issue-34503.rs @@ -2,7 +2,7 @@ fn main() { struct X; trait Foo { - fn foo(&self) where (T, Option): Ord {} + fn foo(&self) where (T, Option): Ord {} //~ WARN methods `foo` and `bar` are never used fn bar(&self, x: &Option) -> bool where Option: Ord { *x < *x } } diff --git a/tests/ui/issues/issue-34503.stderr b/tests/ui/issues/issue-34503.stderr new file mode 100644 index 0000000000000..60d8d76a61965 --- /dev/null +++ b/tests/ui/issues/issue-34503.stderr @@ -0,0 +1,14 @@ +warning: methods `foo` and `bar` are never used + --> $DIR/issue-34503.rs:5:12 + | +LL | trait Foo { + | --- methods in this trait +LL | fn foo(&self) where (T, Option): Ord {} + | ^^^ +LL | fn bar(&self, x: &Option) -> bool + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-3563-3.rs b/tests/ui/issues/issue-3563-3.rs index bedfdab97d58b..6346b82167cb8 100644 --- a/tests/ui/issues/issue-3563-3.rs +++ b/tests/ui/issues/issue-3563-3.rs @@ -112,7 +112,7 @@ trait Canvas { // Unlike interfaces traits support default implementations. // Got an ICE as soon as I added this method. - fn add_points(&mut self, shapes: &[Point]) { + fn add_points(&mut self, shapes: &[Point]) { //~ WARN method `add_points` is never used for pt in shapes {self.add_point(*pt)}; } } diff --git a/tests/ui/issues/issue-3563-3.stderr b/tests/ui/issues/issue-3563-3.stderr new file mode 100644 index 0000000000000..bd65c1e3fd5b4 --- /dev/null +++ b/tests/ui/issues/issue-3563-3.stderr @@ -0,0 +1,13 @@ +warning: method `add_points` is never used + --> $DIR/issue-3563-3.rs:115:8 + | +LL | trait Canvas { + | ------ method in this trait +... +LL | fn add_points(&mut self, shapes: &[Point]) { + | ^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-36299.stderr b/tests/ui/issues/issue-36299.stderr index dc24fb353f408..29e8d7ca59a24 100644 --- a/tests/ui/issues/issue-36299.stderr +++ b/tests/ui/issues/issue-36299.stderr @@ -1,19 +1,19 @@ -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/issue-36299.rs:1:12 | LL | struct Foo<'a, A> {} - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `A` is never used +error[E0392]: type parameter `A` is never used --> $DIR/issue-36299.rs:1:16 | LL | struct Foo<'a, A> {} - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `A` to be a const parameter, use `const A: usize` instead + = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-3668-2.fixed b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed similarity index 100% rename from tests/ui/issues/issue-3668-2.fixed rename to tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed diff --git a/tests/ui/issues/issue-3668-2.rs b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs similarity index 100% rename from tests/ui/issues/issue-3668-2.rs rename to tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs diff --git a/tests/ui/issues/issue-3668-2.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr similarity index 100% rename from tests/ui/issues/issue-3668-2.stderr rename to tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr diff --git a/tests/ui/issues/issue-3668.rs b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs similarity index 100% rename from tests/ui/issues/issue-3668.rs rename to tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs diff --git a/tests/ui/issues/issue-3668.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr similarity index 100% rename from tests/ui/issues/issue-3668.stderr rename to tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 03fea2c16486d..a687e733d3dae 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -15,11 +15,11 @@ warning: relaxing a default bound only does something for `?Sized`; all other tr LL | struct Foo {} | ^^^^^ -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/issue-37534.rs:1:12 | LL | struct Foo {} - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/issues/issue-40510-1.migrate.stderr b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.migrate.stderr similarity index 100% rename from tests/ui/issues/issue-40510-1.migrate.stderr rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.migrate.stderr diff --git a/tests/ui/issues/issue-40510-1.rs b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs similarity index 100% rename from tests/ui/issues/issue-40510-1.rs rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs diff --git a/tests/ui/issues/issue-40510-1.stderr b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr similarity index 100% rename from tests/ui/issues/issue-40510-1.stderr rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr diff --git a/tests/ui/issues/issue-40510-2.rs b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs similarity index 100% rename from tests/ui/issues/issue-40510-2.rs rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs diff --git a/tests/ui/issues/issue-40510-3.migrate.stderr b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.migrate.stderr similarity index 100% rename from tests/ui/issues/issue-40510-3.migrate.stderr rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.migrate.stderr diff --git a/tests/ui/issues/issue-40510-3.rs b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs similarity index 100% rename from tests/ui/issues/issue-40510-3.rs rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs diff --git a/tests/ui/issues/issue-40510-3.stderr b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr similarity index 100% rename from tests/ui/issues/issue-40510-3.stderr rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr diff --git a/tests/ui/issues/issue-40510-4.rs b/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs similarity index 100% rename from tests/ui/issues/issue-40510-4.rs rename to tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs diff --git a/tests/ui/issues/issue-40827.stderr b/tests/ui/issues/issue-40827.stderr index 7f5c578ae4fff..44ae90cbc0ff8 100644 --- a/tests/ui/issues/issue-40827.stderr +++ b/tests/ui/issues/issue-40827.stderr @@ -6,7 +6,7 @@ LL | f(Foo(Arc::new(Bar::B(None)))); | | | required by a bound introduced by this call | - = help: within `Bar`, the trait `Sync` is not implemented for `Rc` + = help: within `Bar`, the trait `Sync` is not implemented for `Rc`, which is required by `Foo: Send` note: required because it appears within the type `Bar` --> $DIR/issue-40827.rs:6:6 | @@ -32,7 +32,7 @@ LL | f(Foo(Arc::new(Bar::B(None)))); | | | required by a bound introduced by this call | - = help: within `Bar`, the trait `Send` is not implemented for `Rc` + = help: within `Bar`, the trait `Send` is not implemented for `Rc`, which is required by `Foo: Send` note: required because it appears within the type `Bar` --> $DIR/issue-40827.rs:6:6 | diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed index 2f8c925b85328..13c830cd0d4b1 100644 --- a/tests/ui/issues/issue-50571.fixed +++ b/tests/ui/issues/issue-50571.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn foo(_: [i32; 2]) {} //~^ ERROR: patterns aren't allowed in methods without bodies diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs index 56f422e7d5838..6fe13e3f707db 100644 --- a/tests/ui/issues/issue-50571.rs +++ b/tests/ui/issues/issue-50571.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn foo([a, b]: [i32; 2]) {} //~^ ERROR: patterns aren't allowed in methods without bodies diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr index fe47790f1ddfb..12256ded1c0a8 100644 --- a/tests/ui/issues/issue-50571.stderr +++ b/tests/ui/issues/issue-50571.stderr @@ -1,5 +1,5 @@ error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:4:12 + --> $DIR/issue-50571.rs:5:12 | LL | fn foo([a, b]: [i32; 2]) {} | ^^^^^^ diff --git a/tests/ui/issues/issue-56199.stderr b/tests/ui/issues/issue-56199.stderr index 7aaf8e4ac2f14..eb6d7005979f6 100644 --- a/tests/ui/issues/issue-56199.stderr +++ b/tests/ui/issues/issue-56199.stderr @@ -10,7 +10,7 @@ error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56199.rs:8:17 | LL | let _ = Self(); - | ^^^^ + | ^^^^^^ | = help: did you mean to use one of the enum's variants? @@ -24,7 +24,7 @@ error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/issue-56199.rs:17:17 | LL | let _ = Self(); - | ^^^^ help: use curly brackets: `Self { /* fields */ }` + | ^^^^^^ help: use curly brackets: `Self { /* fields */ }` error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-57741-1.rs b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs similarity index 100% rename from tests/ui/issues/issue-57741-1.rs rename to tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs diff --git a/tests/ui/issues/issue-57741-1.stderr b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.stderr similarity index 100% rename from tests/ui/issues/issue-57741-1.stderr rename to tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.stderr diff --git a/tests/ui/issues/issue-57741.fixed b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.fixed similarity index 100% rename from tests/ui/issues/issue-57741.fixed rename to tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.fixed diff --git a/tests/ui/issues/issue-57741.rs b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs similarity index 100% rename from tests/ui/issues/issue-57741.rs rename to tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs diff --git a/tests/ui/issues/issue-57741.stderr b/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr similarity index 100% rename from tests/ui/issues/issue-57741.stderr rename to tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr diff --git a/tests/ui/issues/issue-5997-enum.rs b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs similarity index 100% rename from tests/ui/issues/issue-5997-enum.rs rename to tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs diff --git a/tests/ui/issues/issue-5997-enum.stderr b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.stderr similarity index 100% rename from tests/ui/issues/issue-5997-enum.stderr rename to tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.stderr diff --git a/tests/ui/issues/issue-5997-struct.rs b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs similarity index 100% rename from tests/ui/issues/issue-5997-struct.rs rename to tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs diff --git a/tests/ui/issues/issue-5997-struct.stderr b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.stderr similarity index 100% rename from tests/ui/issues/issue-5997-struct.stderr rename to tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.stderr diff --git a/tests/ui/issues/issue-5997.rs b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs similarity index 100% rename from tests/ui/issues/issue-5997.rs rename to tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs diff --git a/tests/ui/issues/issue-71676-1.fixed b/tests/ui/issues/issue-71676-suggest-deref/issue-71676-1.fixed similarity index 100% rename from tests/ui/issues/issue-71676-1.fixed rename to tests/ui/issues/issue-71676-suggest-deref/issue-71676-1.fixed diff --git a/tests/ui/issues/issue-71676-1.rs b/tests/ui/issues/issue-71676-suggest-deref/issue-71676-1.rs similarity index 100% rename from tests/ui/issues/issue-71676-1.rs rename to tests/ui/issues/issue-71676-suggest-deref/issue-71676-1.rs diff --git a/tests/ui/issues/issue-71676-1.stderr b/tests/ui/issues/issue-71676-suggest-deref/issue-71676-1.stderr similarity index 100% rename from tests/ui/issues/issue-71676-1.stderr rename to tests/ui/issues/issue-71676-suggest-deref/issue-71676-1.stderr diff --git a/tests/ui/issues/issue-71676-2.rs b/tests/ui/issues/issue-71676-suggest-deref/issue-71676-2.rs similarity index 100% rename from tests/ui/issues/issue-71676-2.rs rename to tests/ui/issues/issue-71676-suggest-deref/issue-71676-2.rs diff --git a/tests/ui/issues/issue-71676-2.stderr b/tests/ui/issues/issue-71676-suggest-deref/issue-71676-2.stderr similarity index 100% rename from tests/ui/issues/issue-71676-2.stderr rename to tests/ui/issues/issue-71676-suggest-deref/issue-71676-2.stderr diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr index 7371e2105de8d..15cb2d875c13c 100644 --- a/tests/ui/issues/issue-7364.stderr +++ b/tests/ui/issues/issue-7364.stderr @@ -4,7 +4,7 @@ error[E0277]: `RefCell` cannot be shared between threads safely LL | static boxed: Box> = Box::new(RefCell::new(0)); | ^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `Box>: Sync` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Unique>` to implement `Sync` note: required because it appears within the type `Box>` diff --git a/tests/ui/issues/issue-7575.rs b/tests/ui/issues/issue-7575.rs index ac69f2b1c80b6..0074f660c4ef0 100644 --- a/tests/ui/issues/issue-7575.rs +++ b/tests/ui/issues/issue-7575.rs @@ -1,6 +1,6 @@ // run-pass -trait Foo { +trait Foo { //~ WARN trait `Foo` is never used fn new() -> bool { false } fn dummy(&self) { } } diff --git a/tests/ui/issues/issue-7575.stderr b/tests/ui/issues/issue-7575.stderr new file mode 100644 index 0000000000000..2f987d19c80ce --- /dev/null +++ b/tests/ui/issues/issue-7575.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/issue-7575.rs:3:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-76077-1.fixed b/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.fixed similarity index 100% rename from tests/ui/issues/issue-76077-1.fixed rename to tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.fixed diff --git a/tests/ui/issues/issue-76077-1.rs b/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs similarity index 100% rename from tests/ui/issues/issue-76077-1.rs rename to tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs diff --git a/tests/ui/issues/issue-76077-1.stderr b/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.stderr similarity index 100% rename from tests/ui/issues/issue-76077-1.stderr rename to tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.stderr diff --git a/tests/ui/issues/issue-76077.rs b/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs similarity index 100% rename from tests/ui/issues/issue-76077.rs rename to tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs diff --git a/tests/ui/issues/issue-76077.stderr b/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.stderr similarity index 100% rename from tests/ui/issues/issue-76077.stderr rename to tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.stderr diff --git a/tests/ui/issues/issue-7911.rs b/tests/ui/issues/issue-7911.rs index d4db3b0776bca..114574b9009d8 100644 --- a/tests/ui/issues/issue-7911.rs +++ b/tests/ui/issues/issue-7911.rs @@ -4,7 +4,7 @@ #![allow(unused_variables)] // unused foobar_immut + foobar_mut trait FooBar { - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } struct Bar(#[allow(dead_code)] i32); struct Foo { bar: Bar } diff --git a/tests/ui/issues/issue-7911.stderr b/tests/ui/issues/issue-7911.stderr new file mode 100644 index 0000000000000..ead7ee191ac9b --- /dev/null +++ b/tests/ui/issues/issue-7911.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-7911.rs:7:8 + | +LL | trait FooBar { + | ------ method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-8248.rs b/tests/ui/issues/issue-8248.rs index 31a305c31bee2..94b1a5203b47e 100644 --- a/tests/ui/issues/issue-8248.rs +++ b/tests/ui/issues/issue-8248.rs @@ -2,7 +2,7 @@ // pretty-expanded FIXME #23616 trait A { - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } struct B; impl A for B {} diff --git a/tests/ui/issues/issue-8248.stderr b/tests/ui/issues/issue-8248.stderr new file mode 100644 index 0000000000000..a0098bcb771ae --- /dev/null +++ b/tests/ui/issues/issue-8248.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-8248.rs:5:8 + | +LL | trait A { + | - method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr index d81bc3615575e..34433eef5c70b 100644 --- a/tests/ui/issues/issue-87199.stderr +++ b/tests/ui/issues/issue-87199.stderr @@ -23,11 +23,11 @@ LL | ref_arg::<[i32]>(&[5]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[i32]` -note: required by a bound in `ref_arg` +note: required by an implicit `Sized` bound in `ref_arg` --> $DIR/issue-87199.rs:10:12 | LL | fn ref_arg(_: &T) {} - | ^ required by this bound in `ref_arg` + | ^ required by the implicit `Sized` requirement on this type parameter in `ref_arg` help: consider relaxing the implicit `Sized` restriction | LL | fn ref_arg(_: &T) {} diff --git a/tests/ui/issues/issue-9951.rs b/tests/ui/issues/issue-9951.rs index 2698a3b17c6c2..5db3f74efaa3e 100644 --- a/tests/ui/issues/issue-9951.rs +++ b/tests/ui/issues/issue-9951.rs @@ -4,7 +4,7 @@ #![allow(unused_variables)] trait Bar { - fn noop(&self); + fn noop(&self); //~ WARN method `noop` is never used } impl Bar for u8 { fn noop(&self) {} diff --git a/tests/ui/issues/issue-9951.stderr b/tests/ui/issues/issue-9951.stderr new file mode 100644 index 0000000000000..475f2817914d3 --- /dev/null +++ b/tests/ui/issues/issue-9951.stderr @@ -0,0 +1,12 @@ +warning: method `noop` is never used + --> $DIR/issue-9951.rs:7:6 + | +LL | trait Bar { + | --- method in this trait +LL | fn noop(&self); + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/iterators/collect-into-slice.rs b/tests/ui/iterators/collect-into-slice.rs index 045d40a6f71ae..120e56a6549e4 100644 --- a/tests/ui/iterators/collect-into-slice.rs +++ b/tests/ui/iterators/collect-into-slice.rs @@ -8,7 +8,7 @@ fn main() { //~| ERROR the size for values of type `[i32]` cannot be known at compilation time //~| ERROR a slice of type `[i32]` cannot be built since `[i32]` has no definite size //~| NOTE try explicitly collecting into a `Vec<{integer}>` - //~| NOTE required by a bound in `collect` + //~| NOTE required by an implicit `Sized` bound in `collect` //~| NOTE required by a bound in `collect` //~| NOTE all local variables must have a statically known size //~| NOTE doesn't have a size known at compile-time diff --git a/tests/ui/iterators/collect-into-slice.stderr b/tests/ui/iterators/collect-into-slice.stderr index 45685ef0ce9cd..56f1bf770607e 100644 --- a/tests/ui/iterators/collect-into-slice.stderr +++ b/tests/ui/iterators/collect-into-slice.stderr @@ -25,7 +25,7 @@ LL | let some_generated_vec = (0..10).collect(); | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[i32]` -note: required by a bound in `collect` +note: required by an implicit `Sized` bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0277]: a slice of type `&[i32]` cannot be built since we need to store the elements somewhere diff --git a/tests/ui/iterators/float_iterator_hint.stderr b/tests/ui/iterators/float_iterator_hint.stderr index c3cb00c3c684c..29319b9400f03 100644 --- a/tests/ui/iterators/float_iterator_hint.stderr +++ b/tests/ui/iterators/float_iterator_hint.stderr @@ -4,7 +4,7 @@ error[E0277]: `{float}` is not an iterator LL | for i in 0.2 { | ^^^ `{float}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{float}` + = help: the trait `Iterator` is not implemented for `{float}`, which is required by `{float}: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{float}` to implement `IntoIterator` diff --git a/tests/ui/iterators/integral.stderr b/tests/ui/iterators/integral.stderr index c142fec8da0f6..74bbe28d6b719 100644 --- a/tests/ui/iterators/integral.stderr +++ b/tests/ui/iterators/integral.stderr @@ -4,7 +4,7 @@ error[E0277]: `{integer}` is not an iterator LL | for _ in 42 {} | ^^ `{integer}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{integer}` + = help: the trait `Iterator` is not implemented for `{integer}`, which is required by `{integer}: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{integer}` to implement `IntoIterator` @@ -14,7 +14,7 @@ error[E0277]: `u8` is not an iterator LL | for _ in 42 as u8 {} | ^^^^^^^^ `u8` is not an iterator | - = help: the trait `Iterator` is not implemented for `u8` + = help: the trait `Iterator` is not implemented for `u8`, which is required by `u8: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u8` to implement `IntoIterator` @@ -24,7 +24,7 @@ error[E0277]: `i8` is not an iterator LL | for _ in 42 as i8 {} | ^^^^^^^^ `i8` is not an iterator | - = help: the trait `Iterator` is not implemented for `i8` + = help: the trait `Iterator` is not implemented for `i8`, which is required by `i8: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i8` to implement `IntoIterator` @@ -34,7 +34,7 @@ error[E0277]: `u16` is not an iterator LL | for _ in 42 as u16 {} | ^^^^^^^^^ `u16` is not an iterator | - = help: the trait `Iterator` is not implemented for `u16` + = help: the trait `Iterator` is not implemented for `u16`, which is required by `u16: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u16` to implement `IntoIterator` @@ -44,7 +44,7 @@ error[E0277]: `i16` is not an iterator LL | for _ in 42 as i16 {} | ^^^^^^^^^ `i16` is not an iterator | - = help: the trait `Iterator` is not implemented for `i16` + = help: the trait `Iterator` is not implemented for `i16`, which is required by `i16: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i16` to implement `IntoIterator` @@ -54,7 +54,7 @@ error[E0277]: `u32` is not an iterator LL | for _ in 42 as u32 {} | ^^^^^^^^^ `u32` is not an iterator | - = help: the trait `Iterator` is not implemented for `u32` + = help: the trait `Iterator` is not implemented for `u32`, which is required by `u32: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u32` to implement `IntoIterator` @@ -64,7 +64,7 @@ error[E0277]: `i32` is not an iterator LL | for _ in 42 as i32 {} | ^^^^^^^^^ `i32` is not an iterator | - = help: the trait `Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32`, which is required by `i32: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i32` to implement `IntoIterator` @@ -74,7 +74,7 @@ error[E0277]: `u64` is not an iterator LL | for _ in 42 as u64 {} | ^^^^^^^^^ `u64` is not an iterator | - = help: the trait `Iterator` is not implemented for `u64` + = help: the trait `Iterator` is not implemented for `u64`, which is required by `u64: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u64` to implement `IntoIterator` @@ -84,7 +84,7 @@ error[E0277]: `i64` is not an iterator LL | for _ in 42 as i64 {} | ^^^^^^^^^ `i64` is not an iterator | - = help: the trait `Iterator` is not implemented for `i64` + = help: the trait `Iterator` is not implemented for `i64`, which is required by `i64: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i64` to implement `IntoIterator` @@ -94,7 +94,7 @@ error[E0277]: `usize` is not an iterator LL | for _ in 42 as usize {} | ^^^^^^^^^^^ `usize` is not an iterator | - = help: the trait `Iterator` is not implemented for `usize` + = help: the trait `Iterator` is not implemented for `usize`, which is required by `usize: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `usize` to implement `IntoIterator` @@ -104,7 +104,7 @@ error[E0277]: `isize` is not an iterator LL | for _ in 42 as isize {} | ^^^^^^^^^^^ `isize` is not an iterator | - = help: the trait `Iterator` is not implemented for `isize` + = help: the trait `Iterator` is not implemented for `isize`, which is required by `isize: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `isize` to implement `IntoIterator` @@ -114,7 +114,7 @@ error[E0277]: `{float}` is not an iterator LL | for _ in 42.0 {} | ^^^^ `{float}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{float}` + = help: the trait `Iterator` is not implemented for `{float}`, which is required by `{float}: IntoIterator` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{float}` to implement `IntoIterator` diff --git a/tests/ui/iterators/issue-28098.rs b/tests/ui/iterators/issue-28098.rs index 80c77edae9eb1..62a90d90d12de 100644 --- a/tests/ui/iterators/issue-28098.rs +++ b/tests/ui/iterators/issue-28098.rs @@ -2,14 +2,12 @@ fn main() { let _ = Iterator::next(&mut ()); //~^ ERROR `()` is not an iterator //~| ERROR `()` is not an iterator - //~| ERROR `()` is not an iterator for _ in false {} //~^ ERROR `bool` is not an iterator let _ = Iterator::next(&mut ()); //~^ ERROR `()` is not an iterator - //~| ERROR `()` is not an iterator other() } @@ -20,11 +18,9 @@ pub fn other() { let _ = Iterator::next(&mut ()); //~^ ERROR `()` is not an iterator //~| ERROR `()` is not an iterator - //~| ERROR `()` is not an iterator let _ = Iterator::next(&mut ()); //~^ ERROR `()` is not an iterator - //~| ERROR `()` is not an iterator for _ in false {} //~^ ERROR `bool` is not an iterator diff --git a/tests/ui/iterators/issue-28098.stderr b/tests/ui/iterators/issue-28098.stderr index 3256e57d4361b..3cb1b2f72700c 100644 --- a/tests/ui/iterators/issue-28098.stderr +++ b/tests/ui/iterators/issue-28098.stderr @@ -8,25 +8,17 @@ LL | let _ = Iterator::next(&mut ()); | = help: the trait `Iterator` is not implemented for `()` -error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:2:13 - | -LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator - | - = help: the trait `Iterator` is not implemented for `()` - error[E0277]: `bool` is not an iterator - --> $DIR/issue-28098.rs:7:14 + --> $DIR/issue-28098.rs:6:14 | LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `Iterator` is not implemented for `bool` + = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator` = note: required for `bool` to implement `IntoIterator` error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:10:28 + --> $DIR/issue-28098.rs:9:28 | LL | let _ = Iterator::next(&mut ()); | -------------- ^^^^^^^ `()` is not an iterator @@ -35,24 +27,16 @@ LL | let _ = Iterator::next(&mut ()); | = help: the trait `Iterator` is not implemented for `()` -error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:10:13 - | -LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator - | - = help: the trait `Iterator` is not implemented for `()` - error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:2:13 | LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^^^^^^^^ `()` is not an iterator + | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator | = help: the trait `Iterator` is not implemented for `()` error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:20:28 + --> $DIR/issue-28098.rs:18:28 | LL | let _ = Iterator::next(&mut ()); | -------------- ^^^^^^^ `()` is not an iterator @@ -62,15 +46,7 @@ LL | let _ = Iterator::next(&mut ()); = help: the trait `Iterator` is not implemented for `()` error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:20:13 - | -LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator - | - = help: the trait `Iterator` is not implemented for `()` - -error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:25:28 + --> $DIR/issue-28098.rs:22:28 | LL | let _ = Iterator::next(&mut ()); | -------------- ^^^^^^^ `()` is not an iterator @@ -79,31 +55,23 @@ LL | let _ = Iterator::next(&mut ()); | = help: the trait `Iterator` is not implemented for `()` -error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:25:13 - | -LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator - | - = help: the trait `Iterator` is not implemented for `()` - error[E0277]: `bool` is not an iterator - --> $DIR/issue-28098.rs:29:14 + --> $DIR/issue-28098.rs:25:14 | LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `Iterator` is not implemented for `bool` + = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator` = note: required for `bool` to implement `IntoIterator` error[E0277]: `()` is not an iterator - --> $DIR/issue-28098.rs:20:13 + --> $DIR/issue-28098.rs:18:13 | LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^^^^^^^^ `()` is not an iterator + | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator | = help: the trait `Iterator` is not implemented for `()` -error: aborting due to 12 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/iterators/ranges.stderr b/tests/ui/iterators/ranges.stderr index b9fbcd5304b1f..a5d43ecbb6331 100644 --- a/tests/ui/iterators/ranges.stderr +++ b/tests/ui/iterators/ranges.stderr @@ -4,7 +4,7 @@ error[E0277]: `RangeTo<{integer}>` is not an iterator LL | for _ in ..10 {} | ^^^^ if you meant to iterate until a value, add a starting value | - = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>` + = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>`, which is required by `RangeTo<{integer}>: IntoIterator` = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` = note: required for `RangeTo<{integer}>` to implement `IntoIterator` @@ -14,7 +14,7 @@ error[E0277]: `RangeToInclusive<{integer}>` is not an iterator LL | for _ in ..=10 {} | ^^^^^ if you meant to iterate until a value (including it), add a starting value | - = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` + = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>`, which is required by `RangeToInclusive<{integer}>: IntoIterator` = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` = note: required for `RangeToInclusive<{integer}>` to implement `IntoIterator` diff --git a/tests/ui/iterators/string.stderr b/tests/ui/iterators/string.stderr index ddfe0169b848f..29f560677c07d 100644 --- a/tests/ui/iterators/string.stderr +++ b/tests/ui/iterators/string.stderr @@ -4,7 +4,7 @@ error[E0277]: `String` is not an iterator LL | for _ in "".to_owned() {} | ^^^^^^^^^^^^^ `String` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `Iterator` is not implemented for `String` + = help: the trait `Iterator` is not implemented for `String`, which is required by `String: IntoIterator` = note: required for `String` to implement `IntoIterator` error[E0277]: `&str` is not an iterator @@ -13,7 +13,7 @@ error[E0277]: `&str` is not an iterator LL | for _ in "" {} | ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `Iterator` is not implemented for `&str` + = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator` = note: required for `&str` to implement `IntoIterator` error: aborting due to 2 previous errors diff --git a/tests/ui/iterators/vec-on-unimplemented.stderr b/tests/ui/iterators/vec-on-unimplemented.stderr index e2a80dbffdeaa..29b19d5e3b45b 100644 --- a/tests/ui/iterators/vec-on-unimplemented.stderr +++ b/tests/ui/iterators/vec-on-unimplemented.stderr @@ -3,9 +3,6 @@ error[E0599]: `Vec` is not an iterator | LL | vec![true, false].map(|v| !v).collect::>(); | ^^^ `Vec` is not an iterator; try calling `.into_iter()` or `.iter()` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - | - = note: doesn't satisfy `Vec: Iterator` | = note: the following trait bounds were not satisfied: `Vec: Iterator` diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr index a51232090adbb..46c0bda95352f 100644 --- a/tests/ui/kindck/kindck-impl-type-params-2.stderr +++ b/tests/ui/kindck/kindck-impl-type-params-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Copy` is not satisfied --> $DIR/kindck-impl-type-params-2.rs:13:16 | LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo` | | | required by a bound introduced by this call | diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index 53c1940491f84..fe03ac422d2d2 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -21,7 +21,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:16:13 | LL | let a = &t as &dyn Gettable; - | ^^ the trait `Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T`, which is required by `S: Gettable` | note: required for `S` to implement `Gettable` --> $DIR/kindck-impl-type-params.rs:12:32 @@ -59,7 +59,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:23:31 | LL | let a: &dyn Gettable = &t; - | ^^ the trait `Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T`, which is required by `S: Gettable` | note: required for `S` to implement `Gettable` --> $DIR/kindck-impl-type-params.rs:12:32 @@ -78,7 +78,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:35:13 | LL | let a = t as Box>; - | ^ the trait `Copy` is not implemented for `String` + | ^ the trait `Copy` is not implemented for `String`, which is required by `S: Gettable` | = help: the trait `Gettable` is implemented for `S` note: required for `S` to implement `Gettable` @@ -94,7 +94,7 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:43:37 | LL | let a: Box> = t; - | ^ the trait `Copy` is not implemented for `Foo` + | ^ the trait `Copy` is not implemented for `Foo`, which is required by `S: Gettable` | = help: the trait `Gettable` is implemented for `S` note: required for `S` to implement `Gettable` diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 2949517655640..a85815d8cc498 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Copy` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo` | | | required by a bound introduced by this call | diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index 3e164ebf51439..687660fe7eea3 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Copy` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo` | | | required by a bound introduced by this call | diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr index 8bb784d1d4966..8cc931bc48ed3 100644 --- a/tests/ui/kindck/kindck-nonsendable-1.stderr +++ b/tests/ui/kindck/kindck-nonsendable-1.stderr @@ -8,7 +8,7 @@ LL | bar(move|| foo(x)); | | within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}` | required by a bound introduced by this call | - = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc` + = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc`, which is required by `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}: Send` note: required because it's used within this closure --> $DIR/kindck-nonsendable-1.rs:9:9 | diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr index 284d5dcec3107..0fc9cb14c7d46 100644 --- a/tests/ui/kindck/kindck-send-object.stderr +++ b/tests/ui/kindck/kindck-send-object.stderr @@ -4,7 +4,7 @@ error[E0277]: `(dyn Dummy + 'static)` cannot be shared between threads safely LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object.rs:5:18 @@ -18,7 +18,7 @@ error[E0277]: `dyn Dummy` cannot be sent between threads safely LL | assert_send::>(); | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `dyn Dummy` + = help: the trait `Send` is not implemented for `dyn Dummy`, which is required by `Box: Send` = note: required for `Unique` to implement `Send` note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr index c0d516e3f626b..771c54dce0d10 100644 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ b/tests/ui/kindck/kindck-send-object1.stderr @@ -4,7 +4,7 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be shared between threads safely LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send` = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object1.rs:5:18 @@ -18,7 +18,7 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`, which is required by `Box<(dyn Dummy + 'a)>: Send` = note: required for `Unique<(dyn Dummy + 'a)>` to implement `Send` note: required because it appears within the type `Box<(dyn Dummy + 'a)>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr index 6b8df60227f55..758a517e12885 100644 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ b/tests/ui/kindck/kindck-send-object2.stderr @@ -4,7 +4,7 @@ error[E0277]: `(dyn Dummy + 'static)` cannot be shared between threads safely LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object2.rs:3:18 @@ -18,7 +18,7 @@ error[E0277]: `dyn Dummy` cannot be sent between threads safely LL | assert_send::>(); | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `dyn Dummy` + = help: the trait `Send` is not implemented for `dyn Dummy`, which is required by `Box: Send` = note: required for `Unique` to implement `Send` note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr index 860a9391bbb08..4bc0212089b11 100644 --- a/tests/ui/kindck/kindck-send-owned.stderr +++ b/tests/ui/kindck/kindck-send-owned.stderr @@ -4,7 +4,7 @@ error[E0277]: `*mut u8` cannot be sent between threads safely LL | assert_send::>(); | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `*mut u8` + = help: the trait `Send` is not implemented for `*mut u8`, which is required by `Box<*mut u8>: Send` = note: required for `Unique<*mut u8>` to implement `Send` note: required because it appears within the type `Box<*mut u8>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/lang-items/bad-add-impl.rs b/tests/ui/lang-items/bad-add-impl.rs deleted file mode 100644 index 0c44edbe51a0c..0000000000000 --- a/tests/ui/lang-items/bad-add-impl.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(no_core)] -#![feature(lang_items)] -#![no_core] - -#[lang = "sized"] -trait Sized {} - -#[lang = "add"] -trait Add { - const add: u32 = 1u32; -} - -impl Add for u32 {} - -fn main() { - 1u32 + 1u32; - //~^ ERROR cannot add `u32` to `u32` -} diff --git a/tests/ui/lang-items/bad-add-impl.stderr b/tests/ui/lang-items/bad-add-impl.stderr deleted file mode 100644 index c5ad9ff2a0856..0000000000000 --- a/tests/ui/lang-items/bad-add-impl.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0369]: cannot add `u32` to `u32` - --> $DIR/bad-add-impl.rs:16:10 - | -LL | 1u32 + 1u32; - | ---- ^ ---- u32 - | | - | u32 - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/lang-items/duplicate.rs b/tests/ui/lang-items/duplicate.rs new file mode 100644 index 0000000000000..f88d23544145a --- /dev/null +++ b/tests/ui/lang-items/duplicate.rs @@ -0,0 +1,10 @@ +// normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" +#![feature(lang_items)] + +#[lang = "sized"] +trait Sized {} +//~^ ERROR: duplicate lang item + +#[lang = "tuple_trait"] +pub trait Tuple {} +// no error diff --git a/tests/ui/lang-items/duplicate.stderr b/tests/ui/lang-items/duplicate.stderr new file mode 100644 index 0000000000000..aaa8f5e605afa --- /dev/null +++ b/tests/ui/lang-items/duplicate.stderr @@ -0,0 +1,13 @@ +error[E0152]: found duplicate lang item `sized` + --> $DIR/duplicate.rs:5:1 + | +LL | trait Sized {} + | ^^^^^^^^^^^^^^ + | + = note: the lang item is first defined in crate `core` (which `std` depends on) + = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib + = note: second definition in the local crate (`duplicate`) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0152`. diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_item.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_item.stderr deleted file mode 100644 index ff603111e94c5..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_item.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:39:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:43:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_sig.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_sig.stderr deleted file mode 100644 index ff603111e94c5..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_sig.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:39:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:43:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_bad_item.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_bad_item.stderr deleted file mode 100644 index 02e33c597fe87..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_bad_item.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:42:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:47:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_bad_sig.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_bad_sig.stderr deleted file mode 100644 index 02e33c597fe87..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_bad_sig.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:42:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:47:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_mut_bad_item.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_mut_bad_item.stderr deleted file mode 100644 index 02e33c597fe87..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_mut_bad_item.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:42:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:47:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_mut_bad_sig.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_mut_bad_sig.stderr deleted file mode 100644 index 02e33c597fe87..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_mut_bad_sig.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:42:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:47:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_once_bad_item.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_once_bad_item.stderr deleted file mode 100644 index 02e33c597fe87..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_once_bad_item.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:42:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:47:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_once_bad_sig.stderr b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_once_bad_sig.stderr deleted file mode 100644 index 02e33c597fe87..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.fn_once_bad_sig.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:42:5 - | -LL | a(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: failed to find an overloaded call trait for closure call - --> $DIR/fn-fn_mut-call-ill-formed.rs:47:5 - | -LL | b(); - | ^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.rs b/tests/ui/lang-items/fn-fn_mut-call-ill-formed.rs deleted file mode 100644 index 757c6538d05b0..0000000000000 --- a/tests/ui/lang-items/fn-fn_mut-call-ill-formed.rs +++ /dev/null @@ -1,49 +0,0 @@ -// revisions: fn_once_bad_item fn_once_bad_sig fn_mut_bad_item fn_mut_bad_sig fn_bad_item fn_bad_sig - -#![feature(lang_items)] -#![feature(no_core)] -#![no_core] - -#[lang = "sized"] -trait Sized {} - -#[cfg(any(fn_bad_item, fn_bad_sig))] -#[lang = "fn"] -trait MyFn { - #[cfg(fn_bad_sig)] - fn call(i: i32) -> i32 { 0 } - - #[cfg(fn_bad_item)] - const call: i32 = 42; -} - -#[cfg(any(fn_mut_bad_item, fn_mut_bad_sig))] -#[lang = "fn_mut"] -trait MyFnMut { - #[cfg(fn_mut_bad_sig)] - fn call_mut(i: i32) -> i32 { 0 } - - #[cfg(fn_mut_bad_item)] - const call_mut: i32 = 42; -} - -#[cfg(any(fn_once_bad_item, fn_once_bad_sig))] -#[lang = "fn_once"] -trait MyFnOnce { - #[cfg(fn_once_bad_sig)] - fn call_once(i: i32) -> i32 { 0 } - - #[cfg(fn_once_bad_item)] - const call_once: i32 = 42; -} - -fn main() { - let a = || 42; - a(); - //~^ ERROR failed to find an overloaded call trait for closure call - - let mut i = 0; - let mut b = || { }; - b(); - //~^ ERROR failed to find an overloaded call trait for closure call -} diff --git a/tests/ui/lang-items/issue-31076.rs b/tests/ui/lang-items/issue-31076.rs deleted file mode 100644 index cdb196d4ff23f..0000000000000 --- a/tests/ui/lang-items/issue-31076.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(no_core, lang_items)] -#![no_core] - -#[lang="sized"] -trait Sized {} - -#[lang="add"] -trait Add {} - -impl Add for i32 {} - -fn main() { - let x = 5 + 6; - //~^ ERROR cannot add `i32` to `{integer}` - let y = 5i32 + 6i32; - //~^ ERROR cannot add `i32` to `i32` -} diff --git a/tests/ui/lang-items/issue-31076.stderr b/tests/ui/lang-items/issue-31076.stderr deleted file mode 100644 index ac0d9dc752879..0000000000000 --- a/tests/ui/lang-items/issue-31076.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0369]: cannot add `i32` to `{integer}` - --> $DIR/issue-31076.rs:13:15 - | -LL | let x = 5 + 6; - | - ^ - i32 - | | - | {integer} - -error[E0369]: cannot add `i32` to `i32` - --> $DIR/issue-31076.rs:15:18 - | -LL | let y = 5i32 + 6i32; - | ---- ^ ---- i32 - | | - | i32 - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/lang-items/issue-86238.rs b/tests/ui/lang-items/issue-86238.rs deleted file mode 100644 index 509f94f3834a5..0000000000000 --- a/tests/ui/lang-items/issue-86238.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Regression test for the ICE described in issue #86238. - -#![feature(lang_items)] -#![feature(no_core)] - -#![no_core] -fn main() { - let one = || {}; - one() - //~^ ERROR: failed to find an overloaded call trait for closure call - //~| HELP: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined -} -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} diff --git a/tests/ui/lang-items/issue-86238.stderr b/tests/ui/lang-items/issue-86238.stderr deleted file mode 100644 index b492904bcc73a..0000000000000 --- a/tests/ui/lang-items/issue-86238.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: failed to find an overloaded call trait for closure call - --> $DIR/issue-86238.rs:9:5 - | -LL | one() - | ^^^^^ - | - = help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods - -error: aborting due to 1 previous error - diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 8072e6797e49c..30abdf84046ea 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -50,23 +50,23 @@ LL | LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { | - this function has 0 generic arguments -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/lang-item-generic-requirements.rs:24:22 | LL | struct MyPhantomData; - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T` or referring to it in a field - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error[E0392]: parameter `U` is never used +error[E0392]: type parameter `U` is never used --> $DIR/lang-item-generic-requirements.rs:24:25 | LL | struct MyPhantomData; - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `U` or referring to it in a field - = help: if you intended `U` to be a const parameter, use `const U: usize` instead + = help: if you intended `U` to be a const parameter, use `const U: /* Type */` instead error[E0369]: cannot add `{integer}` to `{integer}` --> $DIR/lang-item-generic-requirements.rs:44:7 diff --git a/tests/ui/layout/issue-112048-unsizing-niche.rs b/tests/ui/layout/issue-112048-unsizing-niche.rs index 23588ba36ee59..e59e063df99be 100644 --- a/tests/ui/layout/issue-112048-unsizing-niche.rs +++ b/tests/ui/layout/issue-112048-unsizing-niche.rs @@ -2,7 +2,6 @@ // Check that unsizing does not change which field is considered for niche layout. -#![feature(offset_of)] #![allow(dead_code)] #[derive(Clone)] diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 8161f97dde06c..0ed743818c573 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -232,7 +232,7 @@ error: layout_of(MultipleAlignments) = Layout { LL | enum MultipleAlignments { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: layout_of(Result<[u32; 0], Packed>) = Layout { +error: layout_of(Result<[u32; 0], Packed>>) = Layout { size: Size(4 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), diff --git a/tests/ui/lazy-type-alias/unused-generic-parameters.rs b/tests/ui/lazy-type-alias/unused-generic-parameters.rs new file mode 100644 index 0000000000000..9d02de7a7212b --- /dev/null +++ b/tests/ui/lazy-type-alias/unused-generic-parameters.rs @@ -0,0 +1,22 @@ +// Check that we reject bivariant generic parameters as unused. +// Furthermore, check that we only emit a single diagnostic for unused type parameters: +// Previously, we would emit *two* errors, namely E0392 and E0091. + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type A<'a> = (); +//~^ ERROR lifetime parameter `'a` is never used +//~| HELP consider removing `'a` + +type B = (); +//~^ ERROR type parameter `T` is never used +//~| HELP consider removing `T` +//~| HELP if you intended `T` to be a const parameter + +// Check that we don't emit the const param help message here: +type C = (); +//~^ ERROR type parameter `T` is never used +//~| HELP consider removing `T` + +fn main() {} diff --git a/tests/ui/lazy-type-alias/unused-generic-parameters.stderr b/tests/ui/lazy-type-alias/unused-generic-parameters.stderr new file mode 100644 index 0000000000000..484e21b0a03f9 --- /dev/null +++ b/tests/ui/lazy-type-alias/unused-generic-parameters.stderr @@ -0,0 +1,28 @@ +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/unused-generic-parameters.rs:8:8 + | +LL | type A<'a> = (); + | ^^ unused lifetime parameter + | + = help: consider removing `'a` or referring to it in the body of the type alias + +error[E0392]: type parameter `T` is never used + --> $DIR/unused-generic-parameters.rs:12:8 + | +LL | type B = (); + | ^ unused type parameter + | + = help: consider removing `T` or referring to it in the body of the type alias + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error[E0392]: type parameter `T` is never used + --> $DIR/unused-generic-parameters.rs:18:8 + | +LL | type C = (); + | ^ unused type parameter + | + = help: consider removing `T` or referring to it in the body of the type alias + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/lexer/lex-emoji-identifiers.rs b/tests/ui/lexer/lex-emoji-identifiers.rs index decf2f0058721..bbc088521b7bd 100644 --- a/tests/ui/lexer/lex-emoji-identifiers.rs +++ b/tests/ui/lexer/lex-emoji-identifiers.rs @@ -4,7 +4,7 @@ fn invalid_emoji_usages() { let wireless🛜 = "basic emoji"; //~ ERROR: identifiers cannot contain emoji // FIXME let key1️⃣ = "keycap sequence"; //~ ERROR: unknown start of token - //~^ WARN: identifier contains uncommon Unicode codepoints + //~^ WARN: identifier contains an uncommon Unicode codepoint let flag🇺🇳 = "flag sequence"; //~ ERROR: identifiers cannot contain emoji let wales🏴 = "tag sequence"; //~ ERROR: identifiers cannot contain emoji let folded🙏🏿 = "modifier sequence"; //~ ERROR: identifiers cannot contain emoji diff --git a/tests/ui/lexer/lex-emoji-identifiers.stderr b/tests/ui/lexer/lex-emoji-identifiers.stderr index 747825fa2a988..679b7422bc150 100644 --- a/tests/ui/lexer/lex-emoji-identifiers.stderr +++ b/tests/ui/lexer/lex-emoji-identifiers.stderr @@ -40,7 +40,7 @@ error: identifiers cannot contain emoji: `folded🙏🏿` LL | let folded🙏🏿 = "modifier sequence"; | ^^^^^^^^^^ -warning: identifier contains uncommon Unicode codepoints +warning: identifier contains an uncommon Unicode codepoint: '\u{fe0f}' --> $DIR/lex-emoji-identifiers.rs:6:9 | LL | let key1️⃣ = "keycap sequence"; diff --git a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr index ec4aea623911a..534ba933ba5d0 100644 --- a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr +++ b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr @@ -13,19 +13,19 @@ error: generic `Self` types are currently not permitted in anonymous constants LL | array: [(); size_of::<&Self>()], | ^^^^ -error[E0392]: parameter `'s` is never used +error[E0392]: lifetime parameter `'s` is never used --> $DIR/issue-64173-unused-lifetimes.rs:3:12 | LL | struct Foo<'s> { - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'s`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/issue-64173-unused-lifetimes.rs:15:12 | LL | struct Bar<'a> { - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 09fda33dbec5c..9740742fbbb0f 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -436,7 +436,7 @@ mod hidden_niche { fn hidden_niche_unsafe_cell() -> Option>; //~^ WARN redeclared with a different signature - //~| WARN block uses type `Option>`, which is not FFI-safe + //~| WARN block uses type `Option>>`, which is not FFI-safe } } } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 0d269e599dd1a..5b9244b699311 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -8,7 +8,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>`, which is not FFI-safe +warning: `extern` block uses type `Option>>`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:437:46 | LL | fn hidden_niche_unsafe_cell() -> Option>; @@ -163,7 +163,7 @@ LL | fn non_zero_usize() -> core::num::NonZeroUsize; LL | fn non_zero_usize() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> NonZeroUsize` + = note: expected `unsafe extern "C" fn() -> NonZero` found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature @@ -224,7 +224,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` - found `unsafe extern "C" fn() -> Option>` + found `unsafe extern "C" fn() -> Option>>` warning: 19 warnings emitted diff --git a/tests/ui/lint/dead-code/anon-const-in-pat.rs b/tests/ui/lint/dead-code/anon-const-in-pat.rs index d3e39c0de69c8..4d7fdddf246ed 100644 --- a/tests/ui/lint/dead-code/anon-const-in-pat.rs +++ b/tests/ui/lint/dead-code/anon-const-in-pat.rs @@ -1,6 +1,5 @@ // check-pass #![feature(inline_const_pat)] -#![allow(incomplete_features)] #![deny(dead_code)] const fn one() -> i32 { diff --git a/tests/ui/lint/dead-code/associated-type.rs b/tests/ui/lint/dead-code/associated-type.rs index 1cf66e75a95a5..25106a66e7e36 100644 --- a/tests/ui/lint/dead-code/associated-type.rs +++ b/tests/ui/lint/dead-code/associated-type.rs @@ -15,5 +15,5 @@ impl Foo for Ex { } pub fn main() { - let _x = Ex; + let _x: &dyn Foo::Bar> = &Ex; } diff --git a/tests/ui/lint/dead-code/issue-41883.rs b/tests/ui/lint/dead-code/issue-41883.rs new file mode 100644 index 0000000000000..e165861e893e0 --- /dev/null +++ b/tests/ui/lint/dead-code/issue-41883.rs @@ -0,0 +1,29 @@ +#![deny(dead_code)] + +enum Category { + Dead, //~ ERROR variant `Dead` is never constructed + Used, +} + +trait UnusedTrait { //~ ERROR trait `UnusedTrait` is never used + fn this_is_unused(&self) -> Category { + Category::Dead + } +} + +struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed + +impl UnusedTrait for UnusedStruct { + fn this_is_unused(&self) -> Category { + Category::Used + } +} + +mod private { + #[derive(Debug)] + struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed +} + +fn main() { + let _c = Category::Used; +} diff --git a/tests/ui/lint/dead-code/issue-41883.stderr b/tests/ui/lint/dead-code/issue-41883.stderr new file mode 100644 index 0000000000000..cf079e4dda33a --- /dev/null +++ b/tests/ui/lint/dead-code/issue-41883.stderr @@ -0,0 +1,36 @@ +error: variant `Dead` is never constructed + --> $DIR/issue-41883.rs:4:5 + | +LL | enum Category { + | -------- variant in this enum +LL | Dead, + | ^^^^ + | +note: the lint level is defined here + --> $DIR/issue-41883.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: trait `UnusedTrait` is never used + --> $DIR/issue-41883.rs:8:7 + | +LL | trait UnusedTrait { + | ^^^^^^^^^^^ + +error: struct `UnusedStruct` is never constructed + --> $DIR/issue-41883.rs:14:8 + | +LL | struct UnusedStruct; + | ^^^^^^^^^^^^ + +error: struct `UnusedStruct` is never constructed + --> $DIR/issue-41883.rs:24:12 + | +LL | struct UnusedStruct; + | ^^^^^^^^^^^^ + | + = note: `UnusedStruct` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs index 942c551650032..2d6364aa0cde1 100644 --- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs +++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs @@ -17,7 +17,7 @@ struct Bar { // Issue 119267: this should not ICE. #[derive(Debug)] -struct Foo(usize, #[allow(unused)] usize); //~ WARN field `0` is never read +struct Foo(usize, #[allow(unused)] usize); //~ WARN struct `Foo` is never constructed fn main() { Bar { diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr index 06f9b229c18c1..b992005318f2e 100644 --- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr +++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr @@ -51,19 +51,13 @@ note: the lint level is defined here LL | #[forbid(dead_code)] | ^^^^^^^^^ -warning: field `0` is never read - --> $DIR/multiple-dead-codes-in-the-same-struct.rs:20:12 +warning: struct `Foo` is never constructed + --> $DIR/multiple-dead-codes-in-the-same-struct.rs:20:8 | LL | struct Foo(usize, #[allow(unused)] usize); - | --- ^^^^^ - | | - | field in this struct + | ^^^ | = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis -help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field - | -LL | struct Foo((), #[allow(unused)] usize); - | ~~ error: aborting due to 2 previous errors; 2 warnings emitted diff --git a/tests/ui/lint/dead-code/offset-of-correct-param-env.rs b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs index 2c6fcef250049..ae81a2524396c 100644 --- a/tests/ui/lint/dead-code/offset-of-correct-param-env.rs +++ b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(offset_of)] +#![feature(offset_of_nested)] #![deny(dead_code)] // This struct contains a projection that can only be normalized after getting the field type. diff --git a/tests/ui/lint/dead-code/offset-of.rs b/tests/ui/lint/dead-code/offset-of.rs index da91de3862fc8..5269426d2ff3a 100644 --- a/tests/ui/lint/dead-code/offset-of.rs +++ b/tests/ui/lint/dead-code/offset-of.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] #![deny(dead_code)] use std::mem::offset_of; diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index 57531b0968f1e..bdf47343114c6 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -316,7 +316,7 @@ LL | let _val: NonNull = mem::uninitialized(); = note: `std::ptr::NonNull` must be non-null = note: raw pointers must be initialized -error: the type `(NonZeroU32, i32)` does not permit zero-initialization +error: the type `(NonZero, i32)` does not permit zero-initialization --> $DIR/invalid_value.rs:95:39 | LL | let _val: (NonZeroU32, i32) = mem::zeroed(); @@ -325,9 +325,9 @@ LL | let _val: (NonZeroU32, i32) = mem::zeroed(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | - = note: `std::num::NonZeroU32` must be non-null + = note: `std::num::NonZero` must be non-null -error: the type `(NonZeroU32, i32)` does not permit being left uninitialized +error: the type `(NonZero, i32)` does not permit being left uninitialized --> $DIR/invalid_value.rs:96:39 | LL | let _val: (NonZeroU32, i32) = mem::uninitialized(); @@ -336,7 +336,7 @@ LL | let _val: (NonZeroU32, i32) = mem::uninitialized(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | - = note: `std::num::NonZeroU32` must be non-null + = note: `std::num::NonZero` must be non-null = note: integers must be initialized error: the type `*const dyn Send` does not permit zero-initialization @@ -417,7 +417,7 @@ LL | let _val: OneFruitNonZero = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | = note: `OneFruitNonZero` must be non-null -note: because `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant) +note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) --> $DIR/invalid_value.rs:39:12 | LL | Banana(NonZeroU32), @@ -433,7 +433,7 @@ LL | let _val: OneFruitNonZero = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | = note: `OneFruitNonZero` must be non-null -note: because `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant) +note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) --> $DIR/invalid_value.rs:39:12 | LL | Banana(NonZeroU32), @@ -603,7 +603,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); | = note: references must be non-null -error: the type `NonZeroU32` does not permit zero-initialization +error: the type `NonZero` does not permit zero-initialization --> $DIR/invalid_value.rs:154:32 | LL | let _val: NonZeroU32 = mem::transmute(0); @@ -612,7 +612,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | - = note: `std::num::NonZeroU32` must be non-null + = note: `std::num::NonZero` must be non-null error: the type `NonNull` does not permit zero-initialization --> $DIR/invalid_value.rs:157:34 diff --git a/tests/ui/lint/issue-20343.rs b/tests/ui/lint/issue-20343.rs index 000b6398442a3..f0f4eccc676a1 100644 --- a/tests/ui/lint/issue-20343.rs +++ b/tests/ui/lint/issue-20343.rs @@ -22,6 +22,8 @@ impl B { // test for unused code in generics fn baz>() {} + + fn foz>(a: A) { a.dummy(D); } } pub fn main() { @@ -29,4 +31,5 @@ pub fn main() { B::foo(b); B::bar(); B::baz::<()>(); + B::foz::<()>(()); } diff --git a/tests/ui/lint/issue-86600-lint-twice.rs b/tests/ui/lint/issue-86600-lint-twice.rs deleted file mode 100644 index 0e8a837d987f6..0000000000000 --- a/tests/ui/lint/issue-86600-lint-twice.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Regression test for #86600, where an instance of the -// `illegal_floating_point_literal_pattern` lint was issued twice. - -// check-pass - -fn main() { - let x = 42.0; - - match x { - 5.0 => {} - //~^ WARNING: floating-point types cannot be used in patterns - //~| WARNING: this was previously accepted by the compiler - _ => {} - } -} diff --git a/tests/ui/lint/issue-86600-lint-twice.stderr b/tests/ui/lint/issue-86600-lint-twice.stderr deleted file mode 100644 index 5a65c61212858..0000000000000 --- a/tests/ui/lint/issue-86600-lint-twice.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: floating-point types cannot be used in patterns - --> $DIR/issue-86600-lint-twice.rs:10:9 - | -LL | 5.0 => {} - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/lint/let_underscore/let_underscore_drop.rs b/tests/ui/lint/let_underscore/let_underscore_drop.rs index f298871f122d3..a31b18ed59465 100644 --- a/tests/ui/lint/let_underscore/let_underscore_drop.rs +++ b/tests/ui/lint/let_underscore/let_underscore_drop.rs @@ -11,4 +11,6 @@ impl Drop for NontrivialDrop { fn main() { let _ = NontrivialDrop; //~WARNING non-binding let on a type that implements `Drop` + + let (_, _) = (NontrivialDrop, NontrivialDrop); // This should be ignored. } diff --git a/tests/ui/lint/let_underscore/let_underscore_lock.rs b/tests/ui/lint/let_underscore/let_underscore_lock.rs index 7423862cdf05d..df7e60e39409d 100644 --- a/tests/ui/lint/let_underscore/let_underscore_lock.rs +++ b/tests/ui/lint/let_underscore/let_underscore_lock.rs @@ -1,7 +1,22 @@ // check-fail use std::sync::{Arc, Mutex}; +struct Struct { + a: T, +} + fn main() { let data = Arc::new(Mutex::new(0)); let _ = data.lock().unwrap(); //~ERROR non-binding let on a synchronization lock + + let _ = data.lock(); //~ERROR non-binding let on a synchronization lock + + let (_, _) = (data.lock(), 1); //~ERROR non-binding let on a synchronization lock + + let (_a, Struct { a: _ }) = (0, Struct { a: data.lock() }); //~ERROR non-binding let on a synchronization lock + + (_ , _) = (data.lock(), 1); //~ERROR non-binding let on a synchronization lock + + let _b; + (_b, Struct { a: _ }) = (0, Struct { a: data.lock() }); //~ERROR non-binding let on a synchronization lock } diff --git a/tests/ui/lint/let_underscore/let_underscore_lock.stderr b/tests/ui/lint/let_underscore/let_underscore_lock.stderr index f88a1df55e066..fb8b9ec220336 100644 --- a/tests/ui/lint/let_underscore/let_underscore_lock.stderr +++ b/tests/ui/lint/let_underscore/let_underscore_lock.stderr @@ -1,10 +1,8 @@ error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:6:9 + --> $DIR/let_underscore_lock.rs:10:9 | LL | let _ = data.lock().unwrap(); - | ^ ^^^^^^^^^^^^^^^^^^^^ this binding will immediately drop the value assigned to it - | | - | this lock is not assigned to a binding and is immediately dropped + | ^ this lock is not assigned to a binding and is immediately dropped | = note: `#[deny(let_underscore_lock)]` on by default help: consider binding to an unused variable to avoid immediately dropping the value @@ -16,5 +14,70 @@ help: consider immediately dropping the value LL | drop(data.lock().unwrap()); | ~~~~~ + -error: aborting due to 1 previous error +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:12:9 + | +LL | let _ = data.lock(); + | ^ this lock is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let _unused = data.lock(); + | ~~~~~~~ +help: consider immediately dropping the value + | +LL | drop(data.lock()); + | ~~~~~ + + +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:14:10 + | +LL | let (_, _) = (data.lock(), 1); + | ^ this lock is not assigned to a binding and is immediately dropped + | + = help: consider immediately dropping the value using `drop(..)` after the `let` statement +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let (_unused, _) = (data.lock(), 1); + | ~~~~~~~ + +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:16:26 + | +LL | let (_a, Struct { a: _ }) = (0, Struct { a: data.lock() }); + | ^ this lock is not assigned to a binding and is immediately dropped + | + = help: consider immediately dropping the value using `drop(..)` after the `let` statement +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let (_a, Struct { a: _unused }) = (0, Struct { a: data.lock() }); + | ~~~~~~~ + +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:18:6 + | +LL | (_ , _) = (data.lock(), 1); + | ^ this lock is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + --> $DIR/let_underscore_lock.rs:18:6 + | +LL | (_ , _) = (data.lock(), 1); + | ^ + = help: consider immediately dropping the value using `drop(..)` after the `let` statement + +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:21:22 + | +LL | (_b, Struct { a: _ }) = (0, Struct { a: data.lock() }); + | ^ this lock is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + --> $DIR/let_underscore_lock.rs:21:22 + | +LL | (_b, Struct { a: _ }) = (0, Struct { a: data.lock() }); + | ^ + = help: consider immediately dropping the value using `drop(..)` after the `let` statement + +error: aborting due to 6 previous errors diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 8554e261778e7..64beefbb7579f 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -61,7 +61,7 @@ LL | fn nonzero_i128(x: Option); | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `Option>`, which is not FFI-safe +error: `extern` block uses type `Option>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:86:28 | LL | fn transparent_union(x: Option>); @@ -70,7 +70,7 @@ LL | fn transparent_union(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `Option>`, which is not FFI-safe +error: `extern` block uses type `Option>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:88:20 | LL | fn repr_rust(x: Option>); @@ -79,7 +79,7 @@ LL | fn repr_rust(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `Result<(), NonZeroI32>`, which is not FFI-safe +error: `extern` block uses type `Result<(), NonZero>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:89:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs index f80fe88cbb97e..82ca49461ed23 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs @@ -22,12 +22,8 @@ mod rustc_ok { pub fn rustc_lints() { let x = 42.0; - #[expect(illegal_floating_point_literal_pattern)] - match x { - 5.0 => {} - 6.0 => {} - _ => {} - } + #[expect(invalid_nan_comparisons)] + let _b = x == f32::NAN; } } @@ -40,13 +36,9 @@ mod rustc_warn { pub fn rustc_lints() { let x = 42; - #[expect(illegal_floating_point_literal_pattern)] + #[expect(invalid_nan_comparisons)] //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] - match x { - 5 => {} - 6 => {} - _ => {} - } + let _b = x == 5; } } diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr index 6d49e7543dc59..efe1aa04e5e29 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr @@ -1,5 +1,5 @@ warning: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:37:14 + --> $DIR/expect_tool_lint_rfc_2383.rs:33:14 | LL | #[expect(dead_code)] | ^^^^^^^^^ @@ -7,10 +7,10 @@ LL | #[expect(dead_code)] = note: `#[warn(unfulfilled_lint_expectations)]` on by default warning: this lint expectation is unfulfilled - --> $DIR/expect_tool_lint_rfc_2383.rs:43:18 + --> $DIR/expect_tool_lint_rfc_2383.rs:39:18 | -LL | #[expect(illegal_floating_point_literal_pattern)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[expect(invalid_nan_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^ warning: 2 warnings emitted diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs index ed8e7ddddc597..c3459930a94c0 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs @@ -1,9 +1,9 @@ #![deny(uncommon_codepoints)] -const µ: f64 = 0.000001; //~ ERROR identifier contains uncommon Unicode codepoints +const µ: f64 = 0.000001; //~ ERROR identifier contains an uncommon Unicode codepoint //~| WARNING should have an upper case name -fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints +fn dijkstra() {} //~ ERROR identifier contains an uncommon Unicode codepoint fn main() { let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr index 0533da03068ae..bae5ac654d354 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr @@ -1,4 +1,4 @@ -error: identifier contains uncommon Unicode codepoints +error: identifier contains an uncommon Unicode codepoint: 'µ' --> $DIR/lint-uncommon-codepoints.rs:3:7 | LL | const µ: f64 = 0.000001; @@ -10,13 +10,13 @@ note: the lint level is defined here LL | #![deny(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ -error: identifier contains uncommon Unicode codepoints +error: identifier contains an uncommon Unicode codepoint: 'ij' --> $DIR/lint-uncommon-codepoints.rs:6:4 | LL | fn dijkstra() {} | ^^^^^^^ -error: identifier contains uncommon Unicode codepoints +error: identifier contains uncommon Unicode codepoints: 'ㇻ', 'ㇲ', and 'ㇳ' --> $DIR/lint-uncommon-codepoints.rs:9:9 | LL | let ㇻㇲㇳ = "rust"; diff --git a/tests/ui/macros/issue-22463.rs b/tests/ui/macros/issue-22463.rs index fdf5a2fca7255..8f7b27cb9a056 100644 --- a/tests/ui/macros/issue-22463.rs +++ b/tests/ui/macros/issue-22463.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass macro_rules! items { () => { type A = (); diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 192e6e0cc985d..8cef833f48d26 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -107,9 +107,9 @@ fn test_expr() { c1!(expr, [ true || false ], "true || false"); c1!(expr, [ true || false && false ], "true || false && false"); c1!(expr, [ a < 1 && 2 < b && c > 3 && 4 > d ], "a < 1 && 2 < b && c > 3 && 4 > d"); - c2!(expr, [ a & b & !c ], "a & b & !c", "a & b &!c"); // FIXME + c1!(expr, [ a & b & !c ], "a & b & !c"); c1!(expr, [ a + b * c - d + -1 * -2 - -3], "a + b * c - d + -1 * -2 - -3"); - c2!(expr, [ x = !y ], "x = !y", "x =!y"); // FIXME + c1!(expr, [ x = !y ], "x = !y"); // ExprKind::Unary c1!(expr, [ *expr ], "*expr"); @@ -141,15 +141,14 @@ fn test_expr() { "if let _ = (true && false) {}", "if let _ = true && false {}", ); - c2!(expr, + c1!(expr, [ match () { _ if let _ = Struct {} => {} } ], - "match () { _ if let _ = Struct {} => {} }", - "match() { _ if let _ = Struct {} => {} }", + "match () { _ if let _ = Struct {} => {} }" ); // ExprKind::If c1!(expr, [ if true {} ], "if true {}"); - c2!(expr, [ if !true {} ], "if !true {}", "if!true {}"); // FIXME + c1!(expr, [ if !true {} ], "if !true {}"); c1!(expr, [ if ::std::blah() { } else { } ], "if ::std::blah() {} else {}"); c1!(expr, [ if let true = true {} else {} ], "if let true = true {} else {}"); c1!(expr, @@ -212,7 +211,7 @@ fn test_expr() { c2_match_arm!( [ { 1 } - 1 ], "match () { _ => ({ 1 }) - 1, }", - "match() { _ => { 1 } - 1 }", + "match () { _ => { 1 } - 1 }", ); // ExprKind::Closure @@ -655,11 +654,11 @@ fn test_stmt() { c2!(stmt, [ let _ ], "let _;", "let _"); c2!(stmt, [ let x = true ], "let x = true;", "let x = true"); c2!(stmt, [ let x: bool = true ], "let x: bool = true;", "let x: bool = true"); - c2!(stmt, [ let (a, b) = (1, 2) ], "let (a, b) = (1, 2);", "let(a, b) = (1, 2)"); // FIXME + c2!(stmt, [ let (a, b) = (1, 2) ], "let (a, b) = (1, 2);", "let (a, b) = (1, 2)"); c2!(stmt, [ let (a, b): (u32, u32) = (1, 2) ], "let (a, b): (u32, u32) = (1, 2);", - "let(a, b): (u32, u32) = (1, 2)" // FIXME + "let (a, b): (u32, u32) = (1, 2)" ); macro_rules! c2_let_expr_minus_one { ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => { @@ -776,8 +775,8 @@ fn test_ty() { c1!(ty, [ Ref<'a> ], "Ref<'a>"); c1!(ty, [ PhantomData ], "PhantomData"); c2!(ty, [ PhantomData:: ], "PhantomData", "PhantomData::"); - c2!(ty, [ Fn() -> ! ], "Fn() -> !", "Fn() ->!"); - c2!(ty, [ Fn(u8) -> ! ], "Fn(u8) -> !", "Fn(u8) ->!"); // FIXME + c1!(ty, [ Fn() -> ! ], "Fn() -> !"); + c1!(ty, [ Fn(u8) -> ! ], "Fn(u8) -> !"); c1!(ty, [ ::Type ], "::Type"); // TyKind::TraitObject @@ -857,16 +856,16 @@ fn test_punct() { // Otherwise, any old proc macro that parses pretty-printed code might glue // together tokens that shouldn't be glued. p!([ = = < < <= <= == == != != >= >= > > ], "= = < < <= <= == == != != >= >= > >"); - p!([ && && & & || || | | ! ! ], "&& && & & || || | |!!"); // FIXME + p!([ && && & & || || | | ! ! ], "&& && & & || || | | ! !"); p!([ ~ ~ @ @ # # ], "~ ~ @ @ # #"); - p!([ . . .. .. ... ... ..= ..=], ".... .. ... ... ..= ..="); // FIXME - p!([ , , ; ; : : :: :: ], ",, ; ; : : :: ::"); // FIXME + p!([ . . .. .. ... ... ..= ..=], ". . .. .. ... ... ..= ..="); + p!([ , , ; ; : : :: :: ], ", , ; ; : : :: ::"); p!([ -> -> <- <- => =>], "-> -> <- <- => =>"); - p!([ $ $ ? ? ' ' ], "$$? ? ' '"); // FIXME + p!([ $ $ ? ? ' ' ], "$ $ ? ? ' '"); p!([ + + += += - - -= -= * * *= *= / / /= /= ], "+ + += += - - -= -= * * *= *= / / /= /="); p!([ % % %= %= ^ ^ ^= ^= << << <<= <<= >> >> >>= >>= ], "% % %= %= ^ ^ ^= ^= << << <<= <<= >> >> >>= >>="); - p!([ +! ?= |> >>@ --> <-- $$ =====> ], "+! ?= |> >>@ --> <-- $$=====>"); - p!([ ,; ;, ** @@ $+$ >< <> ?? +== ], ",; ;, ** @@ $+$>< <> ?? +=="); // FIXME: `$ >` -> `$>` + p!([ +! ?= |> >>@ --> <-- $$ =====> ], "+! ?= |> >>@ --> <-- $$ =====>"); + p!([ ,; ;, ** @@ $+$ >< <> ?? +== ], ",; ;, ** @@ $+$ >< <> ?? +=="); p!([ :#!@|$=&*,+;*~? ], ":#!@|$=&*,+;*~?"); } diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr index 81047c7a21ae7..69607600b55c8 100644 --- a/tests/ui/macros/trace_faulty_macros.stderr +++ b/tests/ui/macros/trace_faulty_macros.stderr @@ -111,7 +111,7 @@ LL | test!(let x = 1+1); = note: expanding `test! { let x = 1+1 }` = note: to `test! ((x, 1 + 1))` = note: expanding `test! { (x, 1 + 1) }` - = note: to `let x = 1 + 1 ;` + = note: to `let x = 1 + 1;` error: aborting due to 5 previous errors diff --git a/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr b/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr index 27b86145e90f4..41d0f17366b1e 100644 --- a/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr +++ b/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr @@ -60,11 +60,11 @@ LL | implA{fn d(){fn d(){Self(1)}}} | | | this type parameter needs to be `Sized` | -note: required by a bound in `A` +note: required by an implicit `Sized` bound in `A` --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 | LL | struct A(B); - | ^ required by this bound in `A` + | ^ required by the implicit `Sized` requirement on this type parameter in `A` help: you could relax the implicit `Sized` bound on `B` if it were used through indirection like `&B` or `Box` --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 | diff --git a/tests/ui/match/issue-112438.rs b/tests/ui/match/issue-112438.rs index 15f380f7fb471..46c69d5ba9c77 100644 --- a/tests/ui/match/issue-112438.rs +++ b/tests/ui/match/issue-112438.rs @@ -1,7 +1,6 @@ // run-pass #![feature(inline_const_pat)] #![allow(dead_code)] -#![allow(incomplete_features)] fn foo() { match 0 { const { 1 << 5 } | _ => {} diff --git a/tests/ui/match/issue-41255.rs b/tests/ui/match/issue-41255.rs deleted file mode 100644 index d163801fd1902..0000000000000 --- a/tests/ui/match/issue-41255.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Matching against float literals should result in a linter error - -#![feature(exclusive_range_pattern)] -#![allow(unused)] -#![forbid(illegal_floating_point_literal_pattern)] - -fn main() { - let x = 42.0; - match x { - 5.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - 5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - 1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - //~| ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - //~| WARNING hard error - - ..71.0 => {} - //~^ ERROR floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - ..=72.0 => {} - //~^ ERROR floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - 71.0.. => {} - //~^ ERROR floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - _ => {}, - }; - let y = 5.0; - // Same for tuples - match (x, 5) { - (3.14, 1) => {}, //~ ERROR floating-point types cannot be used - //~| WARNING hard error - _ => {}, - } - // Or structs - struct Foo { x: f32 }; - match (Foo { x }) { - Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used - //~| WARNING hard error - _ => {}, - } -} diff --git a/tests/ui/match/issue-41255.stderr b/tests/ui/match/issue-41255.stderr deleted file mode 100644 index 9bc49654e6d4b..0000000000000 --- a/tests/ui/match/issue-41255.stderr +++ /dev/null @@ -1,115 +0,0 @@ -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:10:9 - | -LL | 5.0 => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 -note: the lint level is defined here - --> $DIR/issue-41255.rs:5:11 - | -LL | #![forbid(illegal_floating_point_literal_pattern)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:12:9 - | -LL | 5.0f32 => {}, - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:14:10 - | -LL | -5.0 => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:16:9 - | -LL | 1.0 .. 33.0 => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:16:16 - | -LL | 1.0 .. 33.0 => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:20:9 - | -LL | 39.0 ..= 70.0 => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:20:18 - | -LL | 39.0 ..= 70.0 => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:25:11 - | -LL | ..71.0 => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:28:12 - | -LL | ..=72.0 => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:31:9 - | -LL | 71.0.. => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:39:10 - | -LL | (3.14, 1) => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:46:18 - | -LL | Foo { x: 2.0 } => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: aborting due to 12 previous errors - diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs new file mode 100644 index 0000000000000..8da6a9ed2049c --- /dev/null +++ b/tests/ui/match/match-float.rs @@ -0,0 +1,11 @@ +// run-pass +// Makes sure we use `==` (not bitwise) semantics for float comparison. + +fn main() { + const F1: f32 = 0.0; + const F2: f32 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} diff --git a/tests/ui/match/validate-range-endpoints.rs b/tests/ui/match/validate-range-endpoints.rs index 1d1737f8b82f4..31d5bc3b65d50 100644 --- a/tests/ui/match/validate-range-endpoints.rs +++ b/tests/ui/match/validate-range-endpoints.rs @@ -1,6 +1,5 @@ #![feature(exclusive_range_pattern)] #![feature(inline_const_pat)] -#![allow(incomplete_features)] #![allow(overlapping_range_endpoints)] fn main() { diff --git a/tests/ui/match/validate-range-endpoints.stderr b/tests/ui/match/validate-range-endpoints.stderr index 0813fccff5187..b3b4066cd9158 100644 --- a/tests/ui/match/validate-range-endpoints.stderr +++ b/tests/ui/match/validate-range-endpoints.stderr @@ -1,59 +1,59 @@ error: literal out of range for `u8` - --> $DIR/validate-range-endpoints.rs:9:12 + --> $DIR/validate-range-endpoints.rs:8:12 | LL | 1..257 => {} | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` - --> $DIR/validate-range-endpoints.rs:11:13 + --> $DIR/validate-range-endpoints.rs:10:13 | LL | 1..=256 => {} | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/validate-range-endpoints.rs:20:9 + --> $DIR/validate-range-endpoints.rs:19:9 | LL | 1..=TOO_BIG => {} | ^^^^^^^^^^^ lower bound larger than upper bound error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/validate-range-endpoints.rs:22:9 + --> $DIR/validate-range-endpoints.rs:21:9 | LL | 1..=const { 256 } => {} | ^^^^^^^^^^^^^^^^^ lower bound larger than upper bound error: literal out of range for `u64` - --> $DIR/validate-range-endpoints.rs:28:32 + --> $DIR/validate-range-endpoints.rs:27:32 | LL | 10000000000000000000..=99999999999999999999 => {} | ^^^^^^^^^^^^^^^^^^^^ this value does not fit into the type `u64` whose range is `0..=18446744073709551615` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:34:12 + --> $DIR/validate-range-endpoints.rs:33:12 | LL | 0..129 => {} | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:36:13 + --> $DIR/validate-range-endpoints.rs:35:13 | LL | 0..=128 => {} | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:38:9 + --> $DIR/validate-range-endpoints.rs:37:9 | LL | -129..0 => {} | ^^^^ this value does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:40:9 + --> $DIR/validate-range-endpoints.rs:39:9 | LL | -10000..=-20 => {} | ^^^^^^ this value does not fit into the type `i8` whose range is `-128..=127` error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered - --> $DIR/validate-range-endpoints.rs:51:11 + --> $DIR/validate-range-endpoints.rs:50:11 | LL | match 0i8 { | ^^^ patterns `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered @@ -66,7 +66,7 @@ LL + i8::MIN..=-17_i8 | 1_i8..=i8::MAX => todo!() | error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` not covered - --> $DIR/validate-range-endpoints.rs:55:11 + --> $DIR/validate-range-endpoints.rs:54:11 | LL | match 0i8 { | ^^^ pattern `i8::MIN..=-17_i8` not covered diff --git a/tests/ui/methods/issues/issue-61525.stderr b/tests/ui/methods/issues/issue-61525.stderr index a329b52e37375..35001ae22a6c7 100644 --- a/tests/ui/methods/issues/issue-61525.stderr +++ b/tests/ui/methods/issues/issue-61525.stderr @@ -7,11 +7,11 @@ LL | 1.query::("") | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn ToString` -note: required by a bound in `Example::query` +note: required by an implicit `Sized` bound in `Example::query` --> $DIR/issue-61525.rs:2:14 | LL | fn query(self, q: Q); - | ^ required by this bound in `Example::query` + | ^ required by the implicit `Sized` requirement on this type parameter in `Example::query` help: consider relaxing the implicit `Sized` restriction | LL | fn query(self, q: Q); @@ -27,6 +27,7 @@ LL | 1.query::("") | = note: expected trait object `dyn ToString` found reference `&'static str` + = help: `&'static str` implements `ToString` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well note: method defined here --> $DIR/issue-61525.rs:2:8 | diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index bd51378cf1a50..6df49e432a13a 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -49,10 +49,7 @@ error[E0599]: `Foo` is not an iterator --> $DIR/method-call-err-msg.rs:19:7 | LL | pub struct Foo; - | -------------- - | | - | method `take` not found for this struct - | doesn't satisfy `Foo: Iterator` + | -------------- method `take` not found for this struct because it doesn't satisfy `Foo: Iterator` ... LL | / y.zero() LL | | .take() @@ -66,8 +63,9 @@ LL | | .take() note: the trait `Iterator` must be implemented --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `take`, perhaps you need to implement it: - candidate #1: `Iterator` + = note: the following traits define an item `take`, perhaps you need to implement one of them: + candidate #1: `std::io::Read` + candidate #2: `Iterator` error[E0061]: this method takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 diff --git a/tests/ui/methods/method-lookup-order.rs b/tests/ui/methods/method-lookup-order.rs index 986fe103cdc79..5a46cf35dec0e 100644 --- a/tests/ui/methods/method-lookup-order.rs +++ b/tests/ui/methods/method-lookup-order.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength // run-pass +#![allow(dead_code)] // There are five cfg's below. I explored the set of all non-empty combinations // of the below five cfg's, which is 2^5 - 1 = 31 combinations. diff --git a/tests/ui/methods/method-recursive-blanket-impl.rs b/tests/ui/methods/method-recursive-blanket-impl.rs index a2db75b4e85d8..e7e83cbec7756 100644 --- a/tests/ui/methods/method-recursive-blanket-impl.rs +++ b/tests/ui/methods/method-recursive-blanket-impl.rs @@ -11,7 +11,7 @@ use std::marker::Sized; // Note: this must be generic for the problem to show up -trait Foo { +trait Foo { //~ WARN trait `Foo` is never used fn foo(&self, a: A); } diff --git a/tests/ui/methods/method-recursive-blanket-impl.stderr b/tests/ui/methods/method-recursive-blanket-impl.stderr new file mode 100644 index 0000000000000..9797a8f6c8308 --- /dev/null +++ b/tests/ui/methods/method-recursive-blanket-impl.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/method-recursive-blanket-impl.rs:14:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.rs b/tests/ui/methods/method-two-trait-defer-resolution-2.rs index fc5766da9714b..d6076126732bc 100644 --- a/tests/ui/methods/method-two-trait-defer-resolution-2.rs +++ b/tests/ui/methods/method-two-trait-defer-resolution-2.rs @@ -14,7 +14,7 @@ trait Foo { fn foo(&self) -> isize; } -trait MyCopy { fn foo(&self) { } } +trait MyCopy { fn foo(&self) { } } //~ WARN method `foo` is never used impl MyCopy for i32 { } impl Foo for Vec { diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.stderr b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr new file mode 100644 index 0000000000000..4501ea5d24334 --- /dev/null +++ b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/method-two-trait-defer-resolution-2.rs:17:19 + | +LL | trait MyCopy { fn foo(&self) { } } + | ------ ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs index d820d2ad08ae8..2fd6c3bfab868 100644 --- a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs +++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 -trait A { +trait A { //~ WARN trait `A` is never used fn foo(self); } diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr new file mode 100644 index 0000000000000..0a60c6242bb2d --- /dev/null +++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr @@ -0,0 +1,10 @@ +warning: trait `A` is never used + --> $DIR/method-two-traits-distinguished-via-where-clause.rs:7:7 + | +LL | trait A { + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/mir/mir_raw_fat_ptr.rs b/tests/ui/mir/mir_raw_fat_ptr.rs index 8e5a2043dc696..e141aa03aa985 100644 --- a/tests/ui/mir/mir_raw_fat_ptr.rs +++ b/tests/ui/mir/mir_raw_fat_ptr.rs @@ -98,7 +98,7 @@ fn assert_inorder(a: &[T], } } -trait Foo { fn foo(&self) -> usize; } +trait Foo { fn foo(&self) -> usize; } //~ WARN method `foo` is never used impl Foo for T { fn foo(&self) -> usize { mem::size_of::() diff --git a/tests/ui/mir/mir_raw_fat_ptr.stderr b/tests/ui/mir/mir_raw_fat_ptr.stderr new file mode 100644 index 0000000000000..a9e9dd66ebdfa --- /dev/null +++ b/tests/ui/mir/mir_raw_fat_ptr.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/mir_raw_fat_ptr.rs:101:16 + | +LL | trait Foo { fn foo(&self) -> usize; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/mismatched_types/E0631.stderr b/tests/ui/mismatched_types/E0631.stderr index 9ba8f5035c5f6..dcd66c28e3cfb 100644 --- a/tests/ui/mismatched_types/E0631.stderr +++ b/tests/ui/mismatched_types/E0631.stderr @@ -2,8 +2,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:7:5 | LL | foo(|_: isize| {}); - | ^^^ ---------- found signature defined here - | | + | ^^^^----------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `fn(usize) -> _` @@ -18,8 +19,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:8:5 | LL | bar(|_: isize| {}); - | ^^^ ---------- found signature defined here - | | + | ^^^^----------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `fn(usize) -> _` diff --git a/tests/ui/mismatched_types/closure-arg-count.stderr b/tests/ui/mismatched_types/closure-arg-count.stderr index 2ecab9f024a12..0e2ca8feec545 100644 --- a/tests/ui/mismatched_types/closure-arg-count.stderr +++ b/tests/ui/mismatched_types/closure-arg-count.stderr @@ -49,8 +49,9 @@ error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:13:5 | LL | f(|| panic!()); - | ^ -- takes 0 arguments - | | + | ^^--^^^^^^^^^^ + | | | + | | takes 0 arguments | expected closure that takes 1 argument | note: required by a bound in `f` @@ -67,8 +68,9 @@ error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:15:5 | LL | f( move || panic!()); - | ^ ---------- takes 0 arguments - | | + | ^^^^----------^^^^^^^^^^ + | | | + | | takes 0 arguments | expected closure that takes 1 argument | note: required by a bound in `f` diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr index 292525daa3d6b..6d23319ca7e64 100644 --- a/tests/ui/mismatched_types/issue-36053-2.stderr +++ b/tests/ui/mismatched_types/issue-36053-2.stderr @@ -21,11 +21,7 @@ error[E0599]: the method `count` exists for struct `Filter>, {cl LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds | | - | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` - | doesn't satisfy `_: FnMut<(&&str,)>` - --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL - | - = note: doesn't satisfy `_: Iterator` + | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` or `_: FnMut<(&&str,)>` | = note: the following trait bounds were not satisfied: `<{closure@$DIR/issue-36053-2.rs:7:39: 7:48} as FnOnce<(&&str,)>>::Output = bool` diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr index 57db71f889cf7..f8e86905ab9bb 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr @@ -2,10 +2,12 @@ error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:2:35 | LL | let _: std::num::NonZeroU64 = 1; - | -------------------- ^ expected `NonZeroU64`, found integer + | -------------------- ^ expected `NonZero`, found integer | | | expected due to this | + = note: expected struct `NonZero` + found type `{integer}` help: consider calling `NonZeroU64::new` | LL | let _: std::num::NonZeroU64 = NonZeroU64::new(1).unwrap(); @@ -15,11 +17,11 @@ error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:6:43 | LL | let _: Option = 1; - | ---------------------------- ^ expected `Option`, found integer + | ---------------------------- ^ expected `Option>`, found integer | | | expected due to this | - = note: expected enum `Option` + = note: expected enum `Option>` found type `{integer}` help: consider calling `NonZeroU64::new` | diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 0d203c1aacba4..d5405c6576a8b 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -4,7 +4,7 @@ error[E0277]: `Dummy` doesn't implement `Debug` 105 | dbg!(lib::Dummy); | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Dummy` + = help: the trait `Debug` is not implemented for `Dummy`, which is required by `&Dummy: Debug` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.rs b/tests/ui/moves/issue-22536-copy-mustnt-zero.rs index 017f36484c1cf..b3fc1a56f882f 100644 --- a/tests/ui/moves/issue-22536-copy-mustnt-zero.rs +++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.rs @@ -5,7 +5,7 @@ trait Resources { type Buffer: Copy; - fn foo(&self) {} + fn foo(&self) {} //~ WARN method `foo` is never used } struct BufferHandle { diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr new file mode 100644 index 0000000000000..b1fcdfa44c33d --- /dev/null +++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr @@ -0,0 +1,13 @@ +warning: method `foo` is never used + --> $DIR/issue-22536-copy-mustnt-zero.rs:8:8 + | +LL | trait Resources { + | --------- method in this trait +LL | type Buffer: Copy; +LL | fn foo(&self) {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/mut/mutable-enum-indirect.stderr b/tests/ui/mut/mutable-enum-indirect.stderr index 0b7783b3318b1..d7af327df5a33 100644 --- a/tests/ui/mut/mutable-enum-indirect.stderr +++ b/tests/ui/mut/mutable-enum-indirect.stderr @@ -6,7 +6,7 @@ LL | bar(&x); | | | required by a bound introduced by this call | - = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync` + = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`, which is required by `&Foo: Sync` note: required because it appears within the type `Foo` --> $DIR/mutable-enum-indirect.rs:11:6 | diff --git a/tests/ui/never_type/never-type-in-nested-fn-decl.rs b/tests/ui/never_type/never-type-in-nested-fn-decl.rs new file mode 100644 index 0000000000000..df546c4717eb6 --- /dev/null +++ b/tests/ui/never_type/never-type-in-nested-fn-decl.rs @@ -0,0 +1,7 @@ +// build-pass + +trait X {} + +fn hello ! { loop {} } 1 }>>() {} + +fn main() {} diff --git a/tests/ui/no-send-res-ports.stderr b/tests/ui/no-send-res-ports.stderr index 9c30261e5cb73..c71d8ecba371c 100644 --- a/tests/ui/no-send-res-ports.stderr +++ b/tests/ui/no-send-res-ports.stderr @@ -13,7 +13,7 @@ LL | | println!("{:?}", y); LL | | }); | |_____^ `Rc<()>` cannot be sent between threads safely | - = help: within `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}`, the trait `Send` is not implemented for `Rc<()>` + = help: within `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}`, the trait `Send` is not implemented for `Rc<()>`, which is required by `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}: Send` note: required because it appears within the type `Port<()>` --> $DIR/no-send-res-ports.rs:5:8 | diff --git a/tests/ui/no_send-enum.stderr b/tests/ui/no_send-enum.stderr index 3b66c7db545e1..e24f79c7dd6aa 100644 --- a/tests/ui/no_send-enum.stderr +++ b/tests/ui/no_send-enum.stderr @@ -6,7 +6,7 @@ LL | bar(x); | | | required by a bound introduced by this call | - = help: within `Foo`, the trait `Send` is not implemented for `NoSend` + = help: within `Foo`, the trait `Send` is not implemented for `NoSend`, which is required by `Foo: Send` note: required because it appears within the type `Foo` --> $DIR/no_send-enum.rs:8:6 | diff --git a/tests/ui/no_share-enum.stderr b/tests/ui/no_share-enum.stderr index 89939216d5b16..5b6c8bf0b4fd9 100644 --- a/tests/ui/no_share-enum.stderr +++ b/tests/ui/no_share-enum.stderr @@ -6,7 +6,7 @@ LL | bar(x); | | | required by a bound introduced by this call | - = help: within `Foo`, the trait `Sync` is not implemented for `NoSync` + = help: within `Foo`, the trait `Sync` is not implemented for `NoSync`, which is required by `Foo: Sync` note: required because it appears within the type `Foo` --> $DIR/no_share-enum.rs:8:6 | diff --git a/tests/ui/not-clone-closure.stderr b/tests/ui/not-clone-closure.stderr index 783c165eeb21c..9b557b1558290 100644 --- a/tests/ui/not-clone-closure.stderr +++ b/tests/ui/not-clone-closure.stderr @@ -5,7 +5,7 @@ LL | let hello = move || { | ------- within this `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}` ... LL | let hello = hello.clone(); - | ^^^^^ within `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`, the trait `Clone` is not implemented for `S` + | ^^^^^ within `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`, the trait `Clone` is not implemented for `S`, which is required by `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}: Clone` | note: required because it's used within this closure --> $DIR/not-clone-closure.rs:7:17 diff --git a/tests/ui/not-panic/not-panic-safe-2.stderr b/tests/ui/not-panic/not-panic-safe-2.stderr index 0c399f15a25bb..8c4cf9c98ed61 100644 --- a/tests/ui/not-panic/not-panic-safe-2.stderr +++ b/tests/ui/not-panic/not-panic-safe-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a r LL | assert::>>(); | ^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `Rc>: UnwindSafe` note: required because it appears within the type `RefCell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `Rc>` to implement `UnwindSafe` @@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a LL | assert::>>(); | ^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `Rc>: UnwindSafe` note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell` diff --git a/tests/ui/not-panic/not-panic-safe-3.stderr b/tests/ui/not-panic/not-panic-safe-3.stderr index 53028d6a3371a..2373ada63f66d 100644 --- a/tests/ui/not-panic/not-panic-safe-3.stderr +++ b/tests/ui/not-panic/not-panic-safe-3.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a r LL | assert::>>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `Arc>: UnwindSafe` note: required because it appears within the type `RefCell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `Arc>` to implement `UnwindSafe` @@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a LL | assert::>>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `Arc>: UnwindSafe` note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell` diff --git a/tests/ui/not-panic/not-panic-safe-4.stderr b/tests/ui/not-panic/not-panic-safe-4.stderr index b1361cfd87ef2..d77cac8f272d0 100644 --- a/tests/ui/not-panic/not-panic-safe-4.stderr +++ b/tests/ui/not-panic/not-panic-safe-4.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a r LL | assert::<&RefCell>(); | ^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `&RefCell: UnwindSafe` note: required because it appears within the type `RefCell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `&RefCell` to implement `UnwindSafe` @@ -25,7 +25,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a LL | assert::<&RefCell>(); | ^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `&RefCell: UnwindSafe` note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell` diff --git a/tests/ui/not-panic/not-panic-safe-5.stderr b/tests/ui/not-panic/not-panic-safe-5.stderr index fbbd81d6d4c53..0de9a2cc0cd93 100644 --- a/tests/ui/not-panic/not-panic-safe-5.stderr +++ b/tests/ui/not-panic/not-panic-safe-5.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a r LL | assert::<*const UnsafeCell>(); | ^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `*const UnsafeCell: UnwindSafe` = note: required for `*const UnsafeCell` to implement `UnwindSafe` note: required by a bound in `assert` --> $DIR/not-panic-safe-5.rs:6:14 diff --git a/tests/ui/not-panic/not-panic-safe-6.stderr b/tests/ui/not-panic/not-panic-safe-6.stderr index 47f28257409eb..7714a577f8a25 100644 --- a/tests/ui/not-panic/not-panic-safe-6.stderr +++ b/tests/ui/not-panic/not-panic-safe-6.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a r LL | assert::<*mut RefCell>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `*mut RefCell: UnwindSafe` note: required because it appears within the type `RefCell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `*mut RefCell` to implement `UnwindSafe` @@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a LL | assert::<*mut RefCell>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell`, which is required by `*mut RefCell: UnwindSafe` note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell` diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index e1825eb5b541d..be0fc0f98e24d 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -124,7 +124,7 @@ LL | x / 100.0 = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div`: - > + >> > <&'a u8 as Div> <&u8 as Div<&u8>> diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed index 45c7e07a26471..52046a8ab693d 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait TraitWithAType { type Item: ?Sized; } diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs index c3e958f498390..96620c0abda34 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait TraitWithAType { type Item; } diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr index cd2aa9fdbe3e4..9bb770ce43199 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr @@ -1,12 +1,12 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time - --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17 + --> $DIR/assoc_type_bounds_implicit_sized.rs:9:17 | LL | type Item = dyn Trait; | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` note: required by a bound in `TraitWithAType::Item` - --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5 + --> $DIR/assoc_type_bounds_implicit_sized.rs:4:5 | LL | type Item; | ^^^^^^^^^^ required by this bound in `TraitWithAType::Item` diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr new file mode 100644 index 0000000000000..7aec3a73fe964 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr @@ -0,0 +1,12 @@ +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/avoid-ice-on-warning-2.rs:4:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr new file mode 100644 index 0000000000000..41c09b7df6289 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr @@ -0,0 +1,40 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-2.rs:4:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: use `dyn` + | +LL | fn id(f: dyn Copy) -> usize { + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-2.rs:4:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use `dyn` + | +LL | fn id(f: dyn Copy) -> usize { + | +++ + +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/avoid-ice-on-warning-2.rs:4:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error: aborting due to 1 previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.rs b/tests/ui/object-safety/avoid-ice-on-warning-2.rs new file mode 100644 index 0000000000000..9a6a4378fa383 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.rs @@ -0,0 +1,12 @@ +// revisions: old new +//[old] edition:2015 +//[new] edition:2021 +fn id(f: Copy) -> usize { +//~^ ERROR the trait `Copy` cannot be made into an object +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + f() +} +fn main() {} diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr new file mode 100644 index 0000000000000..fd92d43ef9a24 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr @@ -0,0 +1,47 @@ +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/avoid-ice-on-warning-3.rs:4:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/avoid-ice-on-warning-3.rs:12:14 + | +LL | trait A { fn g(b: B) -> B; } + | - ^ ...because associated function `g` has no `self` parameter + | | + | this trait cannot be made into an object... +help: consider turning `g` into a method by giving it a `&self` argument + | +LL | trait A { fn g(&self, b: B) -> B; } + | ++++++ +help: alternatively, consider constraining `g` so it does not apply to trait objects + | +LL | trait A { fn g(b: B) -> B where Self: Sized; } + | +++++++++++++++++ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/avoid-ice-on-warning-3.rs:12:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/avoid-ice-on-warning-3.rs:4:14 + | +LL | trait B { fn f(a: A) -> A; } + | - ^ ...because associated function `f` has no `self` parameter + | | + | this trait cannot be made into an object... +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | trait B { fn f(&self, a: A) -> A; } + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | trait B { fn f(a: A) -> A where Self: Sized; } + | +++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr new file mode 100644 index 0000000000000..a36e2519c804d --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr @@ -0,0 +1,128 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:4:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: use `dyn` + | +LL | trait B { fn f(a: dyn A) -> A; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:4:25 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: use `dyn` + | +LL | trait B { fn f(a: A) -> dyn A; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:12:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: use `dyn` + | +LL | trait A { fn g(b: dyn B) -> B; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:12:25 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: use `dyn` + | +LL | trait A { fn g(b: B) -> dyn B; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:4:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use `dyn` + | +LL | trait B { fn f(a: dyn A) -> A; } + | +++ + +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/avoid-ice-on-warning-3.rs:4:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/avoid-ice-on-warning-3.rs:12:14 + | +LL | trait A { fn g(b: B) -> B; } + | - ^ ...because associated function `g` has no `self` parameter + | | + | this trait cannot be made into an object... +help: consider turning `g` into a method by giving it a `&self` argument + | +LL | trait A { fn g(&self, b: B) -> B; } + | ++++++ +help: alternatively, consider constraining `g` so it does not apply to trait objects + | +LL | trait A { fn g(b: B) -> B where Self: Sized; } + | +++++++++++++++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:12:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use `dyn` + | +LL | trait A { fn g(b: dyn B) -> B; } + | +++ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/avoid-ice-on-warning-3.rs:12:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/avoid-ice-on-warning-3.rs:4:14 + | +LL | trait B { fn f(a: A) -> A; } + | - ^ ...because associated function `f` has no `self` parameter + | | + | this trait cannot be made into an object... +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | trait B { fn f(&self, a: A) -> A; } + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | trait B { fn f(a: A) -> A where Self: Sized; } + | +++++++++++++++++ + +error: aborting due to 2 previous errors; 6 warnings emitted + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.rs b/tests/ui/object-safety/avoid-ice-on-warning-3.rs new file mode 100644 index 0000000000000..40563e233dec6 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.rs @@ -0,0 +1,20 @@ +// revisions: old new +//[old] edition:2015 +//[new] edition:2021 +trait B { fn f(a: A) -> A; } +//~^ ERROR the trait `A` cannot be made into an object +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN this is accepted in the current edition +//[old]~| WARN this is accepted in the current edition +//[old]~| WARN this is accepted in the current edition +trait A { fn g(b: B) -> B; } +//~^ ERROR the trait `B` cannot be made into an object +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN this is accepted in the current edition +//[old]~| WARN this is accepted in the current edition +//[old]~| WARN this is accepted in the current edition +fn main() {} diff --git a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr new file mode 100644 index 0000000000000..517f910080de7 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr @@ -0,0 +1,15 @@ +error: return types are denoted using `->` + --> $DIR/avoid-ice-on-warning.rs:4:23 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^ help: use `->` instead + +error[E0405]: cannot find trait `call_that` in this scope + --> $DIR/avoid-ice-on-warning.rs:4:36 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr new file mode 100644 index 0000000000000..7c7af9682800f --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr @@ -0,0 +1,29 @@ +error: return types are denoted using `->` + --> $DIR/avoid-ice-on-warning.rs:4:23 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^ help: use `->` instead + +error[E0405]: cannot find trait `call_that` in this scope + --> $DIR/avoid-ice-on-warning.rs:4:36 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^ not found in this scope + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning.rs:4:25 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: use `dyn` + | +LL | fn call_this(f: F) : dyn Fn(&str) + call_that {} + | +++ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning.rs b/tests/ui/object-safety/avoid-ice-on-warning.rs new file mode 100644 index 0000000000000..5192da94216e1 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning.rs @@ -0,0 +1,9 @@ +// revisions: old new +//[old] edition:2015 +//[new] edition:2021 +fn call_this(f: F) : Fn(&str) + call_that {} +//~^ ERROR return types are denoted using `->` +//~| ERROR cannot find trait `call_that` in this scope +//[old]~| WARN trait objects without an explicit `dyn` are deprecated +//[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +fn main() {} diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed deleted file mode 100644 index e95b982966d0b..0000000000000 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed +++ /dev/null @@ -1,9 +0,0 @@ -// run-rustfix -#![deny(bare_trait_objects)] -fn ord_prefer_dot(s: String) -> impl Ord { - //~^ ERROR the trait `Ord` cannot be made into an object - (s.starts_with("."), s) -} -fn main() { - let _ = ord_prefer_dot(String::new()); -} diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed new file mode 100644 index 0000000000000..301c36c619139 --- /dev/null +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed @@ -0,0 +1,16 @@ +// revisions: old new +//[old] edition:2015 +//[new] edition:2021 +//[new] run-rustfix +// FIXME: the test suite tries to create a crate called `bare_trait_dont_suggest_dyn.new` +#![crate_name="bare_trait_dont_suggest_dyn"] +#![deny(bare_trait_objects)] +fn ord_prefer_dot(s: String) -> impl Ord { + //~^ ERROR the trait `Ord` cannot be made into an object + //[old]~| ERROR trait objects without an explicit `dyn` are deprecated + //[old]~| WARNING this is accepted in the current edition (Rust 2015) + (s.starts_with("."), s) +} +fn main() { + let _ = ord_prefer_dot(String::new()); +} diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr similarity index 95% rename from tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr rename to tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr index 2c499d240ab0b..52db31d620c3d 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Ord` cannot be made into an object - --> $DIR/bare-trait-dont-suggest-dyn.rs:3:33 + --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 | LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` cannot be made into an object diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr new file mode 100644 index 0000000000000..274d5a639a43b --- /dev/null +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr @@ -0,0 +1,39 @@ +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 + | +LL | fn ord_prefer_dot(s: String) -> Ord { + | ^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +note: the lint level is defined here + --> $DIR/bare-trait-dont-suggest-dyn.rs:7:9 + | +LL | #![deny(bare_trait_objects)] + | ^^^^^^^^^^^^^^^^^^ +help: use `dyn` + | +LL | fn ord_prefer_dot(s: String) -> dyn Ord { + | +++ + +error[E0038]: the trait `Ord` cannot be made into an object + --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 + | +LL | fn ord_prefer_dot(s: String) -> Ord { + | ^^^ `Ord` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | fn ord_prefer_dot(s: String) -> impl Ord { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs index fdf7e0a77aa34..64586b77b8c2b 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs @@ -1,7 +1,14 @@ -// run-rustfix +// revisions: old new +//[old] edition:2015 +//[new] edition:2021 +//[new] run-rustfix +// FIXME: the test suite tries to create a crate called `bare_trait_dont_suggest_dyn.new` +#![crate_name="bare_trait_dont_suggest_dyn"] #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> Ord { //~^ ERROR the trait `Ord` cannot be made into an object + //[old]~| ERROR trait objects without an explicit `dyn` are deprecated + //[old]~| WARNING this is accepted in the current edition (Rust 2015) (s.starts_with("."), s) } fn main() { diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr index 22adc19c8029f..e7fcdbd0c9c53 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr @@ -22,11 +22,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | trait Baz : Bar { | ^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Bar` +note: required by an implicit `Sized` bound in `Bar` --> $DIR/object-safety-supertrait-mentions-Self.rs:4:11 | LL | trait Bar { - | ^ required by this bound in `Bar` + | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` help: consider further restricting `Self` | LL | trait Baz : Bar + Sized { diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 7b92698c25e8a..c86e61a61a725 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -1,5 +1,3 @@ -#![feature(offset_of)] - use std::mem::offset_of; fn main() { diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index af0d42de30d60..4cb24b3d034b6 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -1,5 +1,5 @@ error: unexpected end of macro invocation - --> $DIR/offset-of-arg-count.rs:6:34 + --> $DIR/offset-of-arg-count.rs:4:34 | LL | offset_of!(NotEnoughArguments); | ^ missing tokens in macro arguments @@ -8,7 +8,7 @@ note: while trying to match `,` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: unexpected end of macro invocation - --> $DIR/offset-of-arg-count.rs:7:45 + --> $DIR/offset-of-arg-count.rs:5:45 | LL | offset_of!(NotEnoughArgumentsWithAComma, ); | ^ missing tokens in macro arguments @@ -17,7 +17,7 @@ note: while trying to match meta-variable `$fields:expr` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: no rules expected the token `too` - --> $DIR/offset-of-arg-count.rs:8:34 + --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(Container, field, too many arguments); | ^^^ no rules expected this token in macro call @@ -25,25 +25,25 @@ LL | offset_of!(Container, field, too many arguments); = note: while trying to match sequence end error: unexpected token: `)` - --> $DIR/offset-of-arg-count.rs:11:21 + --> $DIR/offset-of-arg-count.rs:9:21 | LL | offset_of!(S, f.); | ^ error: unexpected token: `,` - --> $DIR/offset-of-arg-count.rs:12:21 + --> $DIR/offset-of-arg-count.rs:10:21 | LL | offset_of!(S, f.,); | ^ error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-arg-count.rs:13:19 + --> $DIR/offset-of-arg-count.rs:11:19 | LL | offset_of!(S, f..); | ^^^ error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-arg-count.rs:14:19 + --> $DIR/offset-of-arg-count.rs:12:19 | LL | offset_of!(S, f..,); | ^^^ diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs index e393b159e64d5..016ebfadd1420 100644 --- a/tests/ui/offset-of/offset-of-dst-field.rs +++ b/tests/ui/offset-of/offset-of-dst-field.rs @@ -1,4 +1,4 @@ -#![feature(offset_of, extern_types)] +#![feature(extern_types)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 658678dc4ed3c..753ba809e7da1 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -40,7 +40,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | offset_of!(Delta, z); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized` note: required because it appears within the type `Alpha` --> $DIR/offset-of-dst-field.rs:5:8 | diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs index a2d6aace47da1..cb2f04786ac5c 100644 --- a/tests/ui/offset-of/offset-of-enum.rs +++ b/tests/ui/offset-of/offset-of-enum.rs @@ -1,4 +1,4 @@ -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-inference.rs b/tests/ui/offset-of/offset-of-inference.rs index ba87574eae047..1b1ae25e1ee65 100644 --- a/tests/ui/offset-of/offset-of-inference.rs +++ b/tests/ui/offset-of/offset-of-inference.rs @@ -1,7 +1,5 @@ // Test that inference types in `offset_of!` don't ICE. -#![feature(offset_of)] - struct Foo { x: T, } diff --git a/tests/ui/offset-of/offset-of-inference.stderr b/tests/ui/offset-of/offset-of-inference.stderr index 1845822f11db1..8bd104ed7e277 100644 --- a/tests/ui/offset-of/offset-of-inference.stderr +++ b/tests/ui/offset-of/offset-of-inference.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/offset-of-inference.rs:10:35 + --> $DIR/offset-of-inference.rs:8:35 | LL | let _ = core::mem::offset_of!(Foo<_>, x); | ^^^^^^ cannot infer type diff --git a/tests/ui/offset-of/offset-of-must-use.rs b/tests/ui/offset-of/offset-of-must-use.rs index e30145d7a2fe3..e4b092fcedf3b 100644 --- a/tests/ui/offset-of/offset-of-must-use.rs +++ b/tests/ui/offset-of/offset-of-must-use.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(offset_of)] #![warn(unused)] fn main() { diff --git a/tests/ui/offset-of/offset-of-must-use.stderr b/tests/ui/offset-of/offset-of-must-use.stderr index 5fe387a72553c..b6d88e098d00c 100644 --- a/tests/ui/offset-of/offset-of-must-use.stderr +++ b/tests/ui/offset-of/offset-of-must-use.stderr @@ -1,11 +1,11 @@ warning: unused return value of `must_use` that must be used - --> $DIR/offset-of-must-use.rs:7:5 + --> $DIR/offset-of-must-use.rs:6:5 | LL | core::mem::offset_of!((String,), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/offset-of-must-use.rs:4:9 + --> $DIR/offset-of-must-use.rs:3:9 | LL | #![warn(unused)] | ^^^^^^ diff --git a/tests/ui/offset-of/offset-of-output-type.rs b/tests/ui/offset-of/offset-of-output-type.rs index 50c2e93841f9f..76a33154ba3d1 100644 --- a/tests/ui/offset-of/offset-of-output-type.rs +++ b/tests/ui/offset-of/offset-of-output-type.rs @@ -1,5 +1,3 @@ -#![feature(offset_of)] - use std::mem::offset_of; struct S { diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr index 233d49876436a..34ad931d0caac 100644 --- a/tests/ui/offset-of/offset-of-output-type.stderr +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:12:17 + --> $DIR/offset-of-output-type.rs:10:17 | LL | let _: u8 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` @@ -7,7 +7,7 @@ LL | let _: u8 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:13:18 + --> $DIR/offset-of-output-type.rs:11:18 | LL | let _: u16 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` @@ -15,7 +15,7 @@ LL | let _: u16 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:14:18 + --> $DIR/offset-of-output-type.rs:12:18 | LL | let _: u32 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` @@ -23,7 +23,7 @@ LL | let _: u32 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:15:18 + --> $DIR/offset-of-output-type.rs:13:18 | LL | let _: u64 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` @@ -31,7 +31,7 @@ LL | let _: u64 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:16:20 + --> $DIR/offset-of-output-type.rs:14:20 | LL | let _: isize = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` @@ -39,7 +39,7 @@ LL | let _: isize = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:19:5 + --> $DIR/offset-of-output-type.rs:17:5 | LL | fn main() { | - expected `()` because of default return type diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs index b7affdb794395..1c326b5c79a5e 100644 --- a/tests/ui/offset-of/offset-of-private.rs +++ b/tests/ui/offset-of/offset-of-private.rs @@ -1,4 +1,4 @@ -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-self.rs b/tests/ui/offset-of/offset-of-self.rs index 04dcaf7c0a6b6..1558e13b53095 100644 --- a/tests/ui/offset-of/offset-of-self.rs +++ b/tests/ui/offset-of/offset-of-self.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-tuple-nested.rs b/tests/ui/offset-of/offset-of-tuple-nested.rs index 59b02e3c5c433..212176b24271a 100644 --- a/tests/ui/offset-of/offset-of-tuple-nested.rs +++ b/tests/ui/offset-of/offset-of-tuple-nested.rs @@ -2,7 +2,7 @@ // Test for issue #112204 -- make sure this goes through the entire compilation pipeline, // similar to why `offset-of-unsized.rs` is also build-pass -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs index b6fc1e32229a1..75ba8d77f2fbd 100644 --- a/tests/ui/offset-of/offset-of-tuple.rs +++ b/tests/ui/offset-of/offset-of-tuple.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] #![feature(builtin_syntax)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-unsized.rs b/tests/ui/offset-of/offset-of-unsized.rs index 49c8328da5c55..b70529ed7b85e 100644 --- a/tests/ui/offset-of/offset-of-unsized.rs +++ b/tests/ui/offset-of/offset-of-unsized.rs @@ -2,8 +2,6 @@ // regression test for #112051, not in `offset-of-dst` as the issue is in codegen, // and isn't triggered in the presence of typeck errors -#![feature(offset_of)] - struct S { a: u64, b: T, diff --git a/tests/ui/offset-of/offset-of-unstable-with-feature.rs b/tests/ui/offset-of/offset-of-unstable-with-feature.rs index 7d2eb46c056eb..be275564a0a4f 100644 --- a/tests/ui/offset-of/offset-of-unstable-with-feature.rs +++ b/tests/ui/offset-of/offset-of-unstable-with-feature.rs @@ -1,7 +1,7 @@ // check-pass // aux-build:offset-of-staged-api.rs -#![feature(offset_of, unstable_test_feature)] +#![feature(offset_of_nested, unstable_test_feature)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-unstable.rs b/tests/ui/offset-of/offset-of-unstable.rs index 1e19f2091f29f..da0882abd2286 100644 --- a/tests/ui/offset-of/offset-of-unstable.rs +++ b/tests/ui/offset-of/offset-of-unstable.rs @@ -1,6 +1,6 @@ // aux-build:offset-of-staged-api.rs -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/on-unimplemented/multiple-impls.rs b/tests/ui/on-unimplemented/multiple-impls.rs index a32fd4566231d..b74957ebcd406 100644 --- a/tests/ui/on-unimplemented/multiple-impls.rs +++ b/tests/ui/on-unimplemented/multiple-impls.rs @@ -33,13 +33,10 @@ fn main() { Index::index(&[] as &[i32], 2u32); //~^ ERROR E0277 //~| ERROR E0277 - //~| ERROR E0277 Index::index(&[] as &[i32], Foo(2u32)); //~^ ERROR E0277 //~| ERROR E0277 - //~| ERROR E0277 Index::index(&[] as &[i32], Bar(2u32)); //~^ ERROR E0277 //~| ERROR E0277 - //~| ERROR E0277 } diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr index 3d0e36db75215..f59c93a7c375e 100644 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ b/tests/ui/on-unimplemented/multiple-impls.stderr @@ -11,19 +11,8 @@ LL | Index::index(&[] as &[i32], 2u32); <[i32] as Index>> <[i32] as Index>> -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/multiple-impls.rs:33:5 - | -LL | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message - | - = help: the trait `Index` is not implemented for `[i32]` - = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> - error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:37:33 + --> $DIR/multiple-impls.rs:36:33 | LL | Index::index(&[] as &[i32], Foo(2u32)); | ------------ ^^^^^^^^^ on impl for Foo @@ -35,19 +24,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); <[i32] as Index>> <[i32] as Index>> -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:37:5 - | -LL | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo - | - = help: the trait `Index>` is not implemented for `[i32]` - = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> - error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:41:33 + --> $DIR/multiple-impls.rs:39:33 | LL | Index::index(&[] as &[i32], Bar(2u32)); | ------------ ^^^^^^^^^ on impl for Bar @@ -59,22 +37,11 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); <[i32] as Index>> <[i32] as Index>> -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:41:5 - | -LL | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar - | - = help: the trait `Index>` is not implemented for `[i32]` - = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> - error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 | LL | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^ trait message + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: @@ -82,10 +49,10 @@ LL | Index::index(&[] as &[i32], 2u32); <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:37:5 + --> $DIR/multiple-impls.rs:36:5 | LL | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^ on impl for Foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: @@ -93,16 +60,16 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:41:5 + --> $DIR/multiple-impls.rs:39:5 | LL | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^ on impl for Bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: <[i32] as Index>> <[i32] as Index>> -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/on-impl.rs b/tests/ui/on-unimplemented/on-impl.rs index d0537810ce11e..ab3e67d01fe44 100644 --- a/tests/ui/on-unimplemented/on-impl.rs +++ b/tests/ui/on-unimplemented/on-impl.rs @@ -22,5 +22,4 @@ fn main() { Index::::index(&[1, 2, 3] as &[i32], 2u32); //~^ ERROR E0277 //~| ERROR E0277 - //~| ERROR E0277 } diff --git a/tests/ui/on-unimplemented/on-impl.stderr b/tests/ui/on-unimplemented/on-impl.stderr index 3a0b8353fa5eb..c7d2a78af6cba 100644 --- a/tests/ui/on-unimplemented/on-impl.stderr +++ b/tests/ui/on-unimplemented/on-impl.stderr @@ -20,16 +20,6 @@ LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); = help: the trait `Index` is implemented for `[i32]` = help: for that trait implementation, expected `usize`, found `u32` -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/on-impl.rs:22:5 - | -LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice - | - = help: the trait `Index` is not implemented for `[i32]` - = help: the trait `Index` is implemented for `[i32]` - = help: for that trait implementation, expected `usize`, found `u32` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/on-trait.stderr b/tests/ui/on-unimplemented/on-trait.stderr index 4847a1a5a6119..4097ee1350dbc 100644 --- a/tests/ui/on-unimplemented/on-trait.stderr +++ b/tests/ui/on-unimplemented/on-trait.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Option>: MyFromIterator<&u8>` is not sati --> $DIR/on-trait.rs:28:30 | LL | let y: Option> = collect(x.iter()); // this should give approximately the same error for x.iter().collect() - | ^^^^^^^ a collection of type `Option>` cannot be built from an iterator over elements of type `&u8` + | ^^^^^^^^^^^^^^^^^ a collection of type `Option>` cannot be built from an iterator over elements of type `&u8` | = help: the trait `MyFromIterator<&u8>` is not implemented for `Option>` help: this trait has no implementations, consider adding one @@ -20,7 +20,7 @@ error[E0277]: the trait bound `String: Foo` is not satisfied --> $DIR/on-trait.rs:31:21 | LL | let x: String = foobar(); - | ^^^^^^ test error `String` with `u8` `_` `u32` in `Foo` + | ^^^^^^^^ test error `String` with `u8` `_` `u32` in `Foo` | = help: the trait `Foo` is not implemented for `String` help: this trait has no implementations, consider adding one diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index 5e0117be5295c..c0314fa42d721 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32` LL | x[1i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[i32]>` is not implemented for `i32` + = help: the trait `SliceIndex<[i32]>` is not implemented for `i32`, which is required by `[i32]: Index<_>` = help: the trait `SliceIndex<[i32]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `[i32]` to implement `Index` @@ -15,7 +15,7 @@ error[E0277]: the type `[i32]` cannot be indexed by `RangeTo` LL | x[..1i32]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo` + = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo`, which is required by `[i32]: Index<_>` = help: the following other types implement trait `SliceIndex`: as SliceIndex> as SliceIndex<[T]>> diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 20a8d7549961f..1ad335bf39481 100644 --- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -160,3 +160,23 @@ fn main() { | (y, x) => {} //~ ERROR unreachable } } + +fn unreachable_in_param((_ | (_, _)): (bool, bool)) {} +//~^ ERROR unreachable + +fn unreachable_in_binding() { + let bool_pair = (true, true); + let bool_option = Some(true); + + let (_ | (_, _)) = bool_pair; + //~^ ERROR unreachable + for (_ | (_, _)) in [bool_pair] {} + //~^ ERROR unreachable + + let (Some(_) | Some(true)) = bool_option else { return }; + //~^ ERROR unreachable + if let Some(_) | Some(true) = bool_option {} + //~^ ERROR unreachable + while let Some(_) | Some(true) = bool_option {} + //~^ ERROR unreachable +} diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index 3616dda99812f..336530d1b320a 100644 --- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -184,5 +184,41 @@ error: unreachable pattern LL | | (y, x) => {} | ^^^^^^ -error: aborting due to 29 previous errors +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:164:30 + | +LL | fn unreachable_in_param((_ | (_, _)): (bool, bool)) {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:171:14 + | +LL | let (_ | (_, _)) = bool_pair; + | ^^^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:173:14 + | +LL | for (_ | (_, _)) in [bool_pair] {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:176:20 + | +LL | let (Some(_) | Some(true)) = bool_option else { return }; + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:178:22 + | +LL | if let Some(_) | Some(true) = bool_option {} + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:180:25 + | +LL | while let Some(_) | Some(true) = bool_option {} + | ^^^^^^^^^^ + +error: aborting due to 35 previous errors diff --git a/tests/ui/overloaded/issue-14958.rs b/tests/ui/overloaded/issue-14958.rs index a12564ca9c0ee..80abf5e4e7689 100644 --- a/tests/ui/overloaded/issue-14958.rs +++ b/tests/ui/overloaded/issue-14958.rs @@ -3,7 +3,7 @@ #![feature(fn_traits, unboxed_closures)] -trait Foo { fn dummy(&self) { }} +trait Foo { fn dummy(&self) { }} //~ WARN method `dummy` is never used struct Bar; diff --git a/tests/ui/overloaded/issue-14958.stderr b/tests/ui/overloaded/issue-14958.stderr new file mode 100644 index 0000000000000..cc97730239c30 --- /dev/null +++ b/tests/ui/overloaded/issue-14958.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-14958.rs:6:16 + | +LL | trait Foo { fn dummy(&self) { }} + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/overloaded/overloaded-index-in-field.rs b/tests/ui/overloaded/overloaded-index-in-field.rs index 8a1fa7deb9996..0dc45ea8ca2b8 100644 --- a/tests/ui/overloaded/overloaded-index-in-field.rs +++ b/tests/ui/overloaded/overloaded-index-in-field.rs @@ -27,7 +27,7 @@ impl Index for Foo { trait Int { fn get(self) -> isize; - fn get_from_ref(&self) -> isize; + fn get_from_ref(&self) -> isize; //~ WARN methods `get_from_ref` and `inc` are never used fn inc(&mut self); } diff --git a/tests/ui/overloaded/overloaded-index-in-field.stderr b/tests/ui/overloaded/overloaded-index-in-field.stderr new file mode 100644 index 0000000000000..10c0a3faeb59a --- /dev/null +++ b/tests/ui/overloaded/overloaded-index-in-field.stderr @@ -0,0 +1,15 @@ +warning: methods `get_from_ref` and `inc` are never used + --> $DIR/overloaded-index-in-field.rs:30:8 + | +LL | trait Int { + | --- methods in this trait +LL | fn get(self) -> isize; +LL | fn get_from_ref(&self) -> isize; + | ^^^^^^^^^^^^ +LL | fn inc(&mut self); + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/panic-handler/panic-handler-requires-panic-info.rs b/tests/ui/panic-handler/panic-handler-requires-panic-info.rs index f13c12fc52e4e..b59023b50e1e0 100644 --- a/tests/ui/panic-handler/panic-handler-requires-panic-info.rs +++ b/tests/ui/panic-handler/panic-handler-requires-panic-info.rs @@ -1,5 +1,4 @@ // compile-flags:-C panic=abort -// error-pattern: language item required, but not found: `panic_info` #![feature(lang_items)] #![feature(no_core)] @@ -8,6 +7,7 @@ #[panic_handler] fn panic() -> ! { + //~^ ERROR requires `panic_info` lang_item loop {} } diff --git a/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr b/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr index 06ff8e3098aa4..873f61a51632b 100644 --- a/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr +++ b/tests/ui/panic-handler/panic-handler-requires-panic-info.stderr @@ -1,4 +1,8 @@ -error: language item required, but not found: `panic_info` +error: requires `panic_info` lang_item + --> $DIR/panic-handler-requires-panic-info.rs:9:1 + | +LL | fn panic() -> ! { + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs new file mode 100644 index 0000000000000..a7412f51782fb --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs @@ -0,0 +1,9 @@ +// Issue #118164: recovery path leaving unemitted error behind +fn bar() -> String { + #[cfg(feature = )] + [1, 2, 3].iter().map().collect::() //~ ERROR expected `;`, found `#` + #[attr] //~ ERROR expected statement after outer attribute +} +fn main() { + let _ = bar(); +} diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr new file mode 100644 index 0000000000000..dd0081cc2dff9 --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr @@ -0,0 +1,27 @@ +error: expected `;`, found `#` + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:4:47 + | +LL | #[cfg(feature = )] + | ------------------ only `;` terminated statements or tail expressions are allowed after this attribute +LL | [1, 2, 3].iter().map().collect::() + | ^ expected `;` here +LL | #[attr] + | - unexpected token + | +help: add `;` here + | +LL | [1, 2, 3].iter().map().collect::(); + | + +help: alternatively, consider surrounding the expression with a block + | +LL | { [1, 2, 3].iter().map().collect::() } + | + + + +error: expected statement after outer attribute + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:5:5 + | +LL | #[attr] + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issues/issue-24197.rs b/tests/ui/parser/issues/issue-24197.rs index aaf5137461fa6..9bba16e5596ff 100644 --- a/tests/ui/parser/issues/issue-24197.rs +++ b/tests/ui/parser/issues/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let buf[0] = 0; //~ error: expected a pattern, found an expression } diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 3ef707f3953cf..7ebbf4ac370d7 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/issue-24197.rs:2:12 +error: expected a pattern, found an expression + --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs index 1d128d33e4f49..a5e256b7f1554 100644 --- a/tests/ui/parser/issues/issue-24375.rs +++ b/tests/ui/parser/issues/issue-24375.rs @@ -3,7 +3,7 @@ static tmp : [&'static str; 2] = ["hello", "he"]; fn main() { let z = "hello"; match z { - tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[` + tmp[0] => {} //~ error: expected a pattern, found an expression _ => {} } } diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index bb1e19e9e6d8d..e6ef07d13fd8d 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -1,8 +1,8 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `[` - --> $DIR/issue-24375.rs:6:12 +error: expected a pattern, found an expression + --> $DIR/issue-24375.rs:6:9 | LL | tmp[0] => {} - | ^ expected one of `=>`, `@`, `if`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-7222.rs b/tests/ui/parser/issues/issue-7222.rs index 6490731662664..fb18f4cd62eca 100644 --- a/tests/ui/parser/issues/issue-7222.rs +++ b/tests/ui/parser/issues/issue-7222.rs @@ -1,6 +1,5 @@ // run-pass // pretty-expanded FIXME #23616 -#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620 pub fn main() { const FOO: f64 = 10.0; diff --git a/tests/ui/parser/issues/issue-89574.rs b/tests/ui/parser/issues/issue-89574.rs index 0a477f1aa5fb6..bafb0ce5e6680 100644 --- a/tests/ui/parser/issues/issue-89574.rs +++ b/tests/ui/parser/issues/issue-89574.rs @@ -1,4 +1,6 @@ fn main() { const EMPTY_ARRAY = []; //~^ missing type for `const` item + //~| ERROR type annotations needed + //~| ERROR type annotations needed } diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/parser/issues/issue-89574.stderr index 5f8f6f9396938..a0586d41e2e59 100644 --- a/tests/ui/parser/issues/issue-89574.stderr +++ b/tests/ui/parser/issues/issue-89574.stderr @@ -1,8 +1,23 @@ +error[E0282]: type annotations needed + --> $DIR/issue-89574.rs:2:25 + | +LL | const EMPTY_ARRAY = []; + | ^^ cannot infer type + error: missing type for `const` item --> $DIR/issue-89574.rs:2:22 | LL | const EMPTY_ARRAY = []; | ^ help: provide a type for the item: `: ` -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/issue-89574.rs:2:25 + | +LL | const EMPTY_ARRAY = []; + | ^^ cannot infer type + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/parser/item-free-type-bounds-semantic-fail.rs b/tests/ui/parser/item-free-type-bounds-semantic-fail.rs index 9db4111fbabd9..062b51e597845 100644 --- a/tests/ui/parser/item-free-type-bounds-semantic-fail.rs +++ b/tests/ui/parser/item-free-type-bounds-semantic-fail.rs @@ -13,8 +13,8 @@ fn semantics() { //~| ERROR free type alias without body type E<_T>: Ord = u8; //~^ ERROR bounds on `type`s in this context have no effect - //~| ERROR type parameter `_T` is unused + //~| ERROR type parameter `_T` is never used type F<_T>: Ord where 'static: 'static = u8; //~^ ERROR bounds on `type`s in this context have no effect - //~| ERROR type parameter `_T` is unused + //~| ERROR type parameter `_T` is never used } diff --git a/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr b/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr index 1b086512891f2..1077c10392888 100644 --- a/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr +++ b/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr @@ -50,17 +50,23 @@ error: bounds on `type`s in this context have no effect LL | type F<_T>: Ord where 'static: 'static = u8; | ^^^ -error[E0091]: type parameter `_T` is unused +error[E0091]: type parameter `_T` is never used --> $DIR/item-free-type-bounds-semantic-fail.rs:14:12 | LL | type E<_T>: Ord = u8; | ^^ unused type parameter + | + = help: consider removing `_T` or referring to it in the body of the type alias + = help: if you intended `_T` to be a const parameter, use `const _T: /* Type */` instead -error[E0091]: type parameter `_T` is unused +error[E0091]: type parameter `_T` is never used --> $DIR/item-free-type-bounds-semantic-fail.rs:17:12 | LL | type F<_T>: Ord where 'static: 'static = u8; | ^^ unused type parameter + | + = help: consider removing `_T` or referring to it in the body of the type alias + = help: if you intended `_T` to be a const parameter, use `const _T: /* Type */` instead error: aborting due to 10 previous errors diff --git a/tests/ui/parser/label-is-actually-char.rs b/tests/ui/parser/label-is-actually-char.rs index 183da603da434..74df898d1910a 100644 --- a/tests/ui/parser/label-is-actually-char.rs +++ b/tests/ui/parser/label-is-actually-char.rs @@ -1,16 +1,43 @@ +// Note: it's ok to interpret 'a as 'a', but but not ok to interpret 'abc as +// 'abc' because 'abc' is not a valid char literal. + fn main() { let c = 'a; //~^ ERROR expected `while`, `for`, `loop` or `{` after a label //~| HELP add `'` to close the char literal - match c { + + let c = 'abc; + //~^ ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR expected expression, found `;` +} + +fn f() { + match 'a' { 'a'..='b => {} //~^ ERROR unexpected token: `'b` //~| HELP add `'` to close the char literal - _ => {} + 'c'..='def => {} + //~^ ERROR unexpected token: `'def` } - let x = ['a, 'b]; - //~^ ERROR expected `while`, `for`, `loop` or `{` after a label - //~| ERROR expected `while`, `for`, `loop` or `{` after a label - //~| HELP add `'` to close the char literal - //~| HELP add `'` to close the char literal +} + +fn g() { + match 'g' { + 'g => {} + //~^ ERROR expected pattern, found `=>` + //~| HELP add `'` to close the char literal + 'hij => {} + //~^ ERROR expected pattern, found `'hij` + _ => {} + } +} + +fn h() { + let x = ['a, 'b, 'cde]; + //~^ ERROR expected `while`, `for`, `loop` or `{` after a label + //~| HELP add `'` to close the char literal + //~| ERROR expected `while`, `for`, `loop` or `{` after a label + //~| HELP add `'` to close the char literal + //~| ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR expected expression, found `]` } diff --git a/tests/ui/parser/label-is-actually-char.stderr b/tests/ui/parser/label-is-actually-char.stderr index 28c8d2ada3adb..10a7e1803b532 100644 --- a/tests/ui/parser/label-is-actually-char.stderr +++ b/tests/ui/parser/label-is-actually-char.stderr @@ -1,5 +1,5 @@ error: expected `while`, `for`, `loop` or `{` after a label - --> $DIR/label-is-actually-char.rs:2:15 + --> $DIR/label-is-actually-char.rs:5:15 | LL | let c = 'a; | ^ expected `while`, `for`, `loop` or `{` after a label @@ -9,8 +9,20 @@ help: add `'` to close the char literal LL | let c = 'a'; | + +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/label-is-actually-char.rs:9:17 + | +LL | let c = 'abc; + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: expected expression, found `;` + --> $DIR/label-is-actually-char.rs:9:17 + | +LL | let c = 'abc; + | ^ expected expression + error: unexpected token: `'b` - --> $DIR/label-is-actually-char.rs:6:15 + --> $DIR/label-is-actually-char.rs:16:15 | LL | 'a'..='b => {} | ^^ @@ -20,27 +32,62 @@ help: add `'` to close the char literal LL | 'a'..='b' => {} | + +error: unexpected token: `'def` + --> $DIR/label-is-actually-char.rs:19:15 + | +LL | 'c'..='def => {} + | ^^^^ + +error: expected pattern, found `=>` + --> $DIR/label-is-actually-char.rs:26:11 + | +LL | 'g => {} + | ^^ expected pattern + | +help: add `'` to close the char literal + | +LL | 'g' => {} + | + + +error: expected pattern, found `'hij` + --> $DIR/label-is-actually-char.rs:29:8 + | +LL | 'hij => {} + | ^^^^ expected pattern + error: expected `while`, `for`, `loop` or `{` after a label - --> $DIR/label-is-actually-char.rs:11:16 + --> $DIR/label-is-actually-char.rs:36:15 | -LL | let x = ['a, 'b]; - | ^ expected `while`, `for`, `loop` or `{` after a label +LL | let x = ['a, 'b, 'cde]; + | ^ expected `while`, `for`, `loop` or `{` after a label | help: add `'` to close the char literal | -LL | let x = ['a', 'b]; - | + +LL | let x = ['a', 'b, 'cde]; + | + error: expected `while`, `for`, `loop` or `{` after a label - --> $DIR/label-is-actually-char.rs:11:20 + --> $DIR/label-is-actually-char.rs:36:19 | -LL | let x = ['a, 'b]; - | ^ expected `while`, `for`, `loop` or `{` after a label +LL | let x = ['a, 'b, 'cde]; + | ^ expected `while`, `for`, `loop` or `{` after a label | help: add `'` to close the char literal | -LL | let x = ['a, 'b']; - | + +LL | let x = ['a, 'b', 'cde]; + | + + +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/label-is-actually-char.rs:36:25 + | +LL | let x = ['a, 'b, 'cde]; + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: expected expression, found `]` + --> $DIR/label-is-actually-char.rs:36:25 + | +LL | let x = ['a, 'b, 'cde]; + | ^ expected expression -error: aborting due to 4 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr index e40d985826282..b21e788aa7300 100644 --- a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr +++ b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr @@ -41,7 +41,7 @@ error[E0282]: type annotations needed for `Vec<_>` --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:7 | LL | let v : Vec<(u32,_) = vec![]; - | ^ + | ^ ------ type must be known at this point | help: consider giving `v` an explicit type, where the placeholders `_` are specified | @@ -52,7 +52,7 @@ error[E0282]: type annotations needed for `Vec<_>` --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:7 | LL | let v : Vec<'a = vec![]; - | ^ + | ^ ------ type must be known at this point | help: consider giving `v` an explicit type, where the placeholders `_` are specified | diff --git a/tests/ui/parser/parse-assoc-type-lt.rs b/tests/ui/parser/parse-assoc-type-lt.rs index d3fe6079a5d2a..913fcd920bdb6 100644 --- a/tests/ui/parser/parse-assoc-type-lt.rs +++ b/tests/ui/parser/parse-assoc-type-lt.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/parser/pat-lt-bracket-5.rs b/tests/ui/parser/pat-lt-bracket-5.rs index aaece1f6bd9cb..6d784494d56a3 100644 --- a/tests/ui/parser/pat-lt-bracket-5.rs +++ b/tests/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,5 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let v[0] = v[1]; + //~^ error: expected a pattern, found an expression + //~| error: cannot find value `v` in this scope } diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index e556e6c0206fb..18cf2df028216 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,15 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-5.rs:2:10 +error: expected a pattern, found an expression + --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error[E0425]: cannot find value `v` in this scope + --> $DIR/pat-lt-bracket-5.rs:2:16 + | +LL | let v[0] = v[1]; + | ^ not found in this scope + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/pat-lt-bracket-6.rs b/tests/ui/parser/pat-lt-bracket-6.rs index 7becffa9fe2f7..496525ed5370c 100644 --- a/tests/ui/parser/pat-lt-bracket-6.rs +++ b/tests/ui/parser/pat-lt-bracket-6.rs @@ -3,7 +3,8 @@ fn main() { let x = Test(&0, []); let Test(&desc[..]) = x; - //~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[` + //~^ error: expected a pattern, found an expression + //~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields } const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 035d0dbfe06d6..10c638a63e44c 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -1,18 +1,30 @@ -error: expected one of `)`, `,`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-6.rs:5:19 +error: expected a pattern, found an expression + --> $DIR/pat-lt-bracket-6.rs:5:15 | LL | let Test(&desc[..]) = x; - | ^ - | | - | expected one of `)`, `,`, `@`, or `|` - | help: missing `,` + | ^^^^^^^^ arbitrary expressions are not allowed in patterns error[E0308]: mismatched types - --> $DIR/pat-lt-bracket-6.rs:9:30 + --> $DIR/pat-lt-bracket-6.rs:10:30 | LL | const RECOVERY_WITNESS: () = 0; | ^ expected `()`, found integer -error: aborting due to 2 previous errors +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-lt-bracket-6.rs:5:14 + | +LL | struct Test(&'static u8, [u8; 0]); + | ----------- ------- tuple struct has 2 fields +... +LL | let Test(&desc[..]) = x; + | ^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | let Test(&desc[..], _) = x; + | +++ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0023, E0308. +For more information about an error, try `rustc --explain E0023`. diff --git a/tests/ui/parser/pat-ranges-3.rs b/tests/ui/parser/pat-ranges-3.rs index 8976dcf0d90f9..419768a2a2022 100644 --- a/tests/ui/parser/pat-ranges-3.rs +++ b/tests/ui/parser/pat-ranges-3.rs @@ -1,5 +1,9 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` + let 10 ..= 10 + 3 = 12; + //~^ error: expected a pattern range bound, found an expression + + let 10 - 3 ..= 10 = 8; + //~^ error: expected a pattern range bound, found an expression } diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 611b35a650280..5e1f35d1b6f9a 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,14 @@ -error: expected one of `:`, `;`, `=`, or `|`, found `+` - --> $DIR/pat-ranges-3.rs:4:19 +error: expected a pattern range bound, found an expression + --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, `=`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error: expected a pattern range bound, found an expression + --> $DIR/pat-ranges-3.rs:7:9 + | +LL | let 10 - 3 ..= 10 = 8; + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/pat-ranges-4.rs b/tests/ui/parser/pat-ranges-4.rs deleted file mode 100644 index 61188976b028c..0000000000000 --- a/tests/ui/parser/pat-ranges-4.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Parsing of range patterns - -fn main() { - let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` -} diff --git a/tests/ui/parser/pat-ranges-4.stderr b/tests/ui/parser/pat-ranges-4.stderr deleted file mode 100644 index c30160291d608..0000000000000 --- a/tests/ui/parser/pat-ranges-4.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` - --> $DIR/pat-ranges-4.rs:4:12 - | -LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of 7 possible tokens - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/pat-recover-exprs.rs b/tests/ui/parser/pat-recover-exprs.rs new file mode 100644 index 0000000000000..ecd471467e380 --- /dev/null +++ b/tests/ui/parser/pat-recover-exprs.rs @@ -0,0 +1,28 @@ +fn main() { + match u8::MAX { + u8::MAX.abs() => (), + //~^ error: expected a pattern, found a method call + x.sqrt() @ .. => (), + //~^ error: expected a pattern, found a method call + //~| error: left-hand side of `@` must be a binding + z @ w @ v.u() => (), + //~^ error: expected a pattern, found a method call + y.ilog(3) => (), + //~^ error: expected a pattern, found a method call + n + 1 => (), + //~^ error: expected a pattern, found an expression + ("".f() + 14 * 8) => (), + //~^ error: expected a pattern, found an expression + 0 | ((1) | 2) | 3 => (), + f?() => (), + //~^ error: expected a pattern, found an expression + (_ + 1) => (), + //~^ error: expected one of `)`, `,`, or `|`, found `+` + } + + let 1 + 1 = 2; + //~^ error: expected a pattern, found an expression + + let b = matches!(x, (x * x | x.f()) | x[0]); + //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` +} diff --git a/tests/ui/parser/pat-recover-exprs.stderr b/tests/ui/parser/pat-recover-exprs.stderr new file mode 100644 index 0000000000000..787fd03b0c30d --- /dev/null +++ b/tests/ui/parser/pat-recover-exprs.stderr @@ -0,0 +1,76 @@ +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:3:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:5:9 + | +LL | x.sqrt() @ .. => (), + | ^^^^^^^^ method calls are not allowed in patterns + +error: left-hand side of `@` must be a binding + --> $DIR/pat-recover-exprs.rs:5:9 + | +LL | x.sqrt() @ .. => (), + | --------^^^-- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:8:17 + | +LL | z @ w @ v.u() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:10:9 + | +LL | y.ilog(3) => (), + | ^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:12:9 + | +LL | n + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:14:10 + | +LL | ("".f() + 14 * 8) => (), + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:17:9 + | +LL | f?() => (), + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/pat-recover-exprs.rs:19:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:23:9 + | +LL | let 1 + 1 = 2; + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, `@`, or `|`, found `*` + --> $DIR/pat-recover-exprs.rs:26:28 + | +LL | let b = matches!(x, (x * x | x.f()) | x[0]); + | ^ expected one of `)`, `,`, `@`, or `|` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | + = note: while parsing argument for this `pat` macro fragment + +error: aborting due to 11 previous errors + diff --git a/tests/ui/parser/pat-recover-methodcalls.rs b/tests/ui/parser/pat-recover-methodcalls.rs new file mode 100644 index 0000000000000..54104e9a53559 --- /dev/null +++ b/tests/ui/parser/pat-recover-methodcalls.rs @@ -0,0 +1,37 @@ +struct Foo(String); +struct Bar { baz: String } + +fn foo(foo: Foo) -> bool { + match foo { + Foo("hi".to_owned()) => true, + //~^ error: expected a pattern, found a method call + _ => false + } +} + +fn bar(bar: Bar) -> bool { + match bar { + Bar { baz: "hi".to_owned() } => true, + //~^ error: expected a pattern, found a method call + _ => false + } +} + +fn baz() { // issue #90121 + let foo = vec!["foo".to_string()]; + + match foo.as_slice() { + &["foo".to_string()] => {} + //~^ error: expected a pattern, found a method call + _ => {} + }; +} + +fn main() { + if let (-1.some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found a method call + + if let (-1.Some(4)) = (0, Some(4)) {} + //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + //~| help: missing `,` +} diff --git a/tests/ui/parser/pat-recover-methodcalls.stderr b/tests/ui/parser/pat-recover-methodcalls.stderr new file mode 100644 index 0000000000000..1f9ae81dc0c55 --- /dev/null +++ b/tests/ui/parser/pat-recover-methodcalls.stderr @@ -0,0 +1,35 @@ +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:6:13 + | +LL | Foo("hi".to_owned()) => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:14:20 + | +LL | Bar { baz: "hi".to_owned() } => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:24:11 + | +LL | &["foo".to_string()] => {} + | ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:31:13 + | +LL | if let (-1.some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ method calls are not allowed in patterns + +error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + --> $DIR/pat-recover-methodcalls.rs:34:15 + | +LL | if let (-1.Some(4)) = (0, Some(4)) {} + | ^ + | | + | expected one of `)`, `,`, `...`, `..=`, `..`, or `|` + | help: missing `,` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/pat-recover-ranges.rs b/tests/ui/parser/pat-recover-ranges.rs index 65a6fc6fe21f3..7d77e950d905a 100644 --- a/tests/ui/parser/pat-recover-ranges.rs +++ b/tests/ui/parser/pat-recover-ranges.rs @@ -8,6 +8,22 @@ fn main() { (0)..=(-4) => (), //~^ error: range pattern bounds cannot have parentheses //~| error: range pattern bounds cannot have parentheses + ..=1 + 2 => (), + //~^ error: expected a pattern range bound, found an expression + (4).. => (), + //~^ error: range pattern bounds cannot have parentheses + (-4 + 0).. => (), + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + (1 + 4)...1 * 2 => (), + //~^ error: expected a pattern range bound, found an expression + //~| error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + //~| warning: `...` range patterns are deprecated + //~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + 0.x()..="y".z() => (), + //~^ error: expected a pattern range bound, found a method call + //~| error: expected a pattern range bound, found a method call }; } diff --git a/tests/ui/parser/pat-recover-ranges.stderr b/tests/ui/parser/pat-recover-ranges.stderr index 0d722b5aa95c8..a7d62bd7f8ad2 100644 --- a/tests/ui/parser/pat-recover-ranges.stderr +++ b/tests/ui/parser/pat-recover-ranges.stderr @@ -46,5 +46,87 @@ LL - (0)..=(-4) => (), LL + (0)..=-4 => (), | -error: aborting due to 4 previous errors +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:11:12 + | +LL | ..=1 + 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:13:9 + | +LL | (4).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (4).. => (), +LL + 4.. => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:15:10 + | +LL | (-4 + 0).. => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:15:9 + | +LL | (-4 + 0).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (-4 + 0).. => (), +LL + -4 + 0.. => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:18:10 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:18:9 + | +LL | (1 + 4)...1 * 2 => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (1 + 4)...1 * 2 => (), +LL + 1 + 4...1 * 2 => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:18:19 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern range bound, found a method call + --> $DIR/pat-recover-ranges.rs:24:9 + | +LL | 0.x()..="y".z() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected a pattern range bound, found a method call + --> $DIR/pat-recover-ranges.rs:24:17 + | +LL | 0.x()..="y".z() => (), + | ^^^^^^^ method calls are not allowed in patterns + +warning: `...` range patterns are deprecated + --> $DIR/pat-recover-ranges.rs:18:16 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^ help: use `..=` for an inclusive range + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default + +error: aborting due to 13 previous errors; 1 warning emitted diff --git a/tests/ui/parser/pat-recover-wildcards.rs b/tests/ui/parser/pat-recover-wildcards.rs new file mode 100644 index 0000000000000..f506e2223d608 --- /dev/null +++ b/tests/ui/parser/pat-recover-wildcards.rs @@ -0,0 +1,61 @@ +// check that we can't do funny things with wildcards. + +fn a() { + match 1 { + _ + 1 => () //~ error: expected one of `=>`, `if`, or `|`, found `+` + } +} + +fn b() { + match 2 { + (_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%` + } +} + +fn c() { + match 3 { + _.x() => () //~ error: expected one of `=>`, `if`, or `|`, found `.` + } +} + +fn d() { + match 4 { + _..=4 => () //~ error: expected one of `=>`, `if`, or `|`, found `..=` + } +} + +fn e() { + match 5 { + .._ => () //~ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn f() { + match 6 { + 0..._ => () + //~^ error: inclusive range with no end + //~| error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn g() { + match 7 { + (_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*` + } +} + +fn h() { + match 8 { + ..(_) => () //~ error: expected one of `=>`, `if`, or `|`, found `(` + } +} + +fn i() { + match 9 { + 4..=(2 + _) => () + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + } +} + +fn main() {} diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr new file mode 100644 index 0000000000000..2b0c9bbc5be86 --- /dev/null +++ b/tests/ui/parser/pat-recover-wildcards.stderr @@ -0,0 +1,77 @@ +error: expected one of `=>`, `if`, or `|`, found `+` + --> $DIR/pat-recover-wildcards.rs:5:11 + | +LL | _ + 1 => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `%` + --> $DIR/pat-recover-wildcards.rs:11:12 + | +LL | (_ % 4) => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `.` + --> $DIR/pat-recover-wildcards.rs:17:10 + | +LL | _.x() => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `..=` + --> $DIR/pat-recover-wildcards.rs:23:10 + | +LL | _..=4 => () + | ^^^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/pat-recover-wildcards.rs:29:11 + | +LL | .._ => () + | ^ expected one of `=>`, `if`, or `|` + +error[E0586]: inclusive range with no end + --> $DIR/pat-recover-wildcards.rs:35:10 + | +LL | 0..._ => () + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/pat-recover-wildcards.rs:35:13 + | +LL | 0..._ => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `*` + --> $DIR/pat-recover-wildcards.rs:43:12 + | +LL | (_ * 0)..5 => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `(` + --> $DIR/pat-recover-wildcards.rs:49:11 + | +LL | ..(_) => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-wildcards.rs:55:14 + | +LL | 4..=(2 + _) => () + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-wildcards.rs:55:13 + | +LL | 4..=(2 + _) => () + | ^ ^ + | +help: remove these parentheses + | +LL - 4..=(2 + _) => () +LL + 4..=2 + _ => () + | + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0586`. diff --git a/tests/ui/parser/range-exclusive-dotdotlt.rs b/tests/ui/parser/range-exclusive-dotdotlt.rs new file mode 100644 index 0000000000000..5752566026f02 --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.rs @@ -0,0 +1,43 @@ +fn foo() { + let _ = 0..<10; + //~^ ERROR: expected type, found `10` + //~| HELP: remove the `<` to write an exclusive range +} + +fn bar() { + let _ = 0..`, or `as`, found `;` + //~| HELP: remove the `<` to write an exclusive range +} + +fn baz() { + let _ = ; + //~^ ERROR: expected `::`, found `;` +} + +fn qux() { + let _ = [1, 2, 3][..<1]; + //~^ ERROR: expected type, found `1` + //~| HELP: remove the `<` to write an exclusive range +} + +fn quux() { + let _ = [1, 2, 3][..`, or `as`, found `]` + //~| HELP: remove the `<` to write an exclusive range +} + +fn foobar() { + let _ = [1, 2, 3][..]; + //~^ ERROR: expected `::`, found `]` +} + +fn ok1() { + let _ = [1, 2, 3][..::default()]; +} + +fn ok2() { + let _ = 0..::default(); +} + +fn main() {} diff --git a/tests/ui/parser/range-exclusive-dotdotlt.stderr b/tests/ui/parser/range-exclusive-dotdotlt.stderr new file mode 100644 index 0000000000000..af25e1df343de --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.stderr @@ -0,0 +1,46 @@ +error: expected type, found `10` + --> $DIR/range-exclusive-dotdotlt.rs:2:17 + | +LL | let _ = 0..<10; + | -^^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;` + --> $DIR/range-exclusive-dotdotlt.rs:8:20 + | +LL | let _ = 0.. $DIR/range-exclusive-dotdotlt.rs:14:18 + | +LL | let _ = ; + | ^ expected `::` + +error: expected type, found `1` + --> $DIR/range-exclusive-dotdotlt.rs:19:26 + | +LL | let _ = [1, 2, 3][..<1]; + | -^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]` + --> $DIR/range-exclusive-dotdotlt.rs:25:29 + | +LL | let _ = [1, 2, 3][.. $DIR/range-exclusive-dotdotlt.rs:31:30 + | +LL | let _ = [1, 2, 3][..]; + | ^ expected `::` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr index 3681a796c53ed..17138a6f07921 100644 --- a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr +++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr @@ -30,8 +30,9 @@ error[E0631]: type mismatch in closure arguments --> $DIR/recover-fn-trait-from-fn-kw.rs:10:5 | LL | foo2(|_: ()| {}); - | ^^^^ ------- found signature defined here - | | + | ^^^^^-------^^^^ + | | | + | | found signature defined here | expected due to this | = note: expected closure signature `fn(i32) -> _` diff --git a/tests/ui/parser/removed-syntax-box.fixed b/tests/ui/parser/removed-syntax/removed-syntax-box.fixed similarity index 100% rename from tests/ui/parser/removed-syntax-box.fixed rename to tests/ui/parser/removed-syntax/removed-syntax-box.fixed diff --git a/tests/ui/parser/removed-syntax-box.rs b/tests/ui/parser/removed-syntax/removed-syntax-box.rs similarity index 100% rename from tests/ui/parser/removed-syntax-box.rs rename to tests/ui/parser/removed-syntax/removed-syntax-box.rs diff --git a/tests/ui/parser/removed-syntax-box.stderr b/tests/ui/parser/removed-syntax/removed-syntax-box.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-box.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-box.stderr diff --git a/tests/ui/parser/removed-syntax-closure-lifetime.rs b/tests/ui/parser/removed-syntax/removed-syntax-closure-lifetime.rs similarity index 100% rename from tests/ui/parser/removed-syntax-closure-lifetime.rs rename to tests/ui/parser/removed-syntax/removed-syntax-closure-lifetime.rs diff --git a/tests/ui/parser/removed-syntax-closure-lifetime.stderr b/tests/ui/parser/removed-syntax/removed-syntax-closure-lifetime.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-closure-lifetime.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-closure-lifetime.stderr diff --git a/tests/ui/parser/removed-syntax-enum-newtype.rs b/tests/ui/parser/removed-syntax/removed-syntax-enum-newtype.rs similarity index 100% rename from tests/ui/parser/removed-syntax-enum-newtype.rs rename to tests/ui/parser/removed-syntax/removed-syntax-enum-newtype.rs diff --git a/tests/ui/parser/removed-syntax-enum-newtype.stderr b/tests/ui/parser/removed-syntax/removed-syntax-enum-newtype.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-enum-newtype.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-enum-newtype.stderr diff --git a/tests/ui/parser/removed-syntax-field-let-2.rs b/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.rs similarity index 100% rename from tests/ui/parser/removed-syntax-field-let-2.rs rename to tests/ui/parser/removed-syntax/removed-syntax-field-let-2.rs diff --git a/tests/ui/parser/removed-syntax-field-let-2.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-field-let-2.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr diff --git a/tests/ui/parser/removed-syntax-field-let.rs b/tests/ui/parser/removed-syntax/removed-syntax-field-let.rs similarity index 100% rename from tests/ui/parser/removed-syntax-field-let.rs rename to tests/ui/parser/removed-syntax/removed-syntax-field-let.rs diff --git a/tests/ui/parser/removed-syntax-field-let.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-field-let.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr diff --git a/tests/ui/parser/removed-syntax-field-semicolon.rs b/tests/ui/parser/removed-syntax/removed-syntax-field-semicolon.rs similarity index 100% rename from tests/ui/parser/removed-syntax-field-semicolon.rs rename to tests/ui/parser/removed-syntax/removed-syntax-field-semicolon.rs diff --git a/tests/ui/parser/removed-syntax-field-semicolon.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-semicolon.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-field-semicolon.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-field-semicolon.stderr diff --git a/tests/ui/parser/removed-syntax-fixed-vec.rs b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs similarity index 100% rename from tests/ui/parser/removed-syntax-fixed-vec.rs rename to tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs diff --git a/tests/ui/parser/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-fixed-vec.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr diff --git a/tests/ui/parser/removed-syntax-fn-sigil.rs b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.rs similarity index 100% rename from tests/ui/parser/removed-syntax-fn-sigil.rs rename to tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.rs diff --git a/tests/ui/parser/removed-syntax-fn-sigil.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-fn-sigil.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr diff --git a/tests/ui/parser/removed-syntax-mode.rs b/tests/ui/parser/removed-syntax/removed-syntax-mode.rs similarity index 100% rename from tests/ui/parser/removed-syntax-mode.rs rename to tests/ui/parser/removed-syntax/removed-syntax-mode.rs diff --git a/tests/ui/parser/removed-syntax-mode.stderr b/tests/ui/parser/removed-syntax/removed-syntax-mode.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-mode.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-mode.stderr diff --git a/tests/ui/parser/removed-syntax-mut-vec-expr.rs b/tests/ui/parser/removed-syntax/removed-syntax-mut-vec-expr.rs similarity index 100% rename from tests/ui/parser/removed-syntax-mut-vec-expr.rs rename to tests/ui/parser/removed-syntax/removed-syntax-mut-vec-expr.rs diff --git a/tests/ui/parser/removed-syntax-mut-vec-expr.stderr b/tests/ui/parser/removed-syntax/removed-syntax-mut-vec-expr.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-mut-vec-expr.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-mut-vec-expr.stderr diff --git a/tests/ui/parser/removed-syntax-mut-vec-ty.rs b/tests/ui/parser/removed-syntax/removed-syntax-mut-vec-ty.rs similarity index 100% rename from tests/ui/parser/removed-syntax-mut-vec-ty.rs rename to tests/ui/parser/removed-syntax/removed-syntax-mut-vec-ty.rs diff --git a/tests/ui/parser/removed-syntax-mut-vec-ty.stderr b/tests/ui/parser/removed-syntax/removed-syntax-mut-vec-ty.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-mut-vec-ty.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-mut-vec-ty.stderr diff --git a/tests/ui/parser/removed-syntax-ptr-lifetime.rs b/tests/ui/parser/removed-syntax/removed-syntax-ptr-lifetime.rs similarity index 100% rename from tests/ui/parser/removed-syntax-ptr-lifetime.rs rename to tests/ui/parser/removed-syntax/removed-syntax-ptr-lifetime.rs diff --git a/tests/ui/parser/removed-syntax-ptr-lifetime.stderr b/tests/ui/parser/removed-syntax/removed-syntax-ptr-lifetime.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-ptr-lifetime.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-ptr-lifetime.stderr diff --git a/tests/ui/parser/removed-syntax-record.rs b/tests/ui/parser/removed-syntax/removed-syntax-record.rs similarity index 100% rename from tests/ui/parser/removed-syntax-record.rs rename to tests/ui/parser/removed-syntax/removed-syntax-record.rs diff --git a/tests/ui/parser/removed-syntax-record.stderr b/tests/ui/parser/removed-syntax/removed-syntax-record.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-record.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-record.stderr diff --git a/tests/ui/parser/removed-syntax-static-fn.rs b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.rs similarity index 100% rename from tests/ui/parser/removed-syntax-static-fn.rs rename to tests/ui/parser/removed-syntax/removed-syntax-static-fn.rs diff --git a/tests/ui/parser/removed-syntax-static-fn.stderr b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-static-fn.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr diff --git a/tests/ui/parser/removed-syntax-uniq-mut-expr.rs b/tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-expr.rs similarity index 100% rename from tests/ui/parser/removed-syntax-uniq-mut-expr.rs rename to tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-expr.rs diff --git a/tests/ui/parser/removed-syntax-uniq-mut-expr.stderr b/tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-expr.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-uniq-mut-expr.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-expr.stderr diff --git a/tests/ui/parser/removed-syntax-uniq-mut-ty.rs b/tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-ty.rs similarity index 100% rename from tests/ui/parser/removed-syntax-uniq-mut-ty.rs rename to tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-ty.rs diff --git a/tests/ui/parser/removed-syntax-uniq-mut-ty.stderr b/tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-ty.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-uniq-mut-ty.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-uniq-mut-ty.stderr diff --git a/tests/ui/parser/removed-syntax-with-1.rs b/tests/ui/parser/removed-syntax/removed-syntax-with-1.rs similarity index 100% rename from tests/ui/parser/removed-syntax-with-1.rs rename to tests/ui/parser/removed-syntax/removed-syntax-with-1.rs diff --git a/tests/ui/parser/removed-syntax-with-1.stderr b/tests/ui/parser/removed-syntax/removed-syntax-with-1.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-with-1.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-with-1.stderr diff --git a/tests/ui/parser/removed-syntax-with-2.rs b/tests/ui/parser/removed-syntax/removed-syntax-with-2.rs similarity index 100% rename from tests/ui/parser/removed-syntax-with-2.rs rename to tests/ui/parser/removed-syntax/removed-syntax-with-2.rs diff --git a/tests/ui/parser/removed-syntax-with-2.stderr b/tests/ui/parser/removed-syntax/removed-syntax-with-2.stderr similarity index 100% rename from tests/ui/parser/removed-syntax-with-2.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-with-2.stderr diff --git a/tests/ui/parser/struct-literal-in-for.stderr b/tests/ui/parser/struct-literal-in-for.stderr index 1c91eba68e399..d2ef2ad7b5ad1 100644 --- a/tests/ui/parser/struct-literal-in-for.stderr +++ b/tests/ui/parser/struct-literal-in-for.stderr @@ -23,7 +23,7 @@ LL | | x: 3 LL | | }.hi() { | |__________^ `bool` is not an iterator | - = help: the trait `Iterator` is not implemented for `bool` + = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator` = note: required for `bool` to implement `IntoIterator` error: aborting due to 2 previous errors diff --git a/tests/ui/parser/suggest-assoc-const.fixed b/tests/ui/parser/suggest-assoc-const.fixed index 259f37b23a584..4229135ebb23b 100644 --- a/tests/ui/parser/suggest-assoc-const.fixed +++ b/tests/ui/parser/suggest-assoc-const.fixed @@ -1,5 +1,6 @@ // Issue: 101797, Suggest associated const for incorrect use of let in traits // run-rustfix +#![allow(dead_code)] trait Trait { const _X: i32; //~^ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-assoc-const.rs b/tests/ui/parser/suggest-assoc-const.rs index c7be712ec076e..0cf695bd40aff 100644 --- a/tests/ui/parser/suggest-assoc-const.rs +++ b/tests/ui/parser/suggest-assoc-const.rs @@ -1,5 +1,6 @@ // Issue: 101797, Suggest associated const for incorrect use of let in traits // run-rustfix +#![allow(dead_code)] trait Trait { let _X: i32; //~^ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr index 7ba1dbdff7e59..6e29fad98d466 100644 --- a/tests/ui/parser/suggest-assoc-const.stderr +++ b/tests/ui/parser/suggest-assoc-const.stderr @@ -1,5 +1,5 @@ error: non-item in item list - --> $DIR/suggest-assoc-const.rs:4:5 + --> $DIR/suggest-assoc-const.rs:5:5 | LL | let _X: i32; | ^^^ help: consider using `const` instead of `let` for associated const: `const` diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed index 63704735490fa..81ee6cdf0a722 100644 --- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed +++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn bar() {} //~ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs index 4650b05e20ce8..c8f525fc4f0ad 100644 --- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs +++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn bar() {}; //~ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr index c716d5908ea11..396c76ac85f2f 100644 --- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr +++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr @@ -1,5 +1,5 @@ error: non-item in item list - --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:4:16 + --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:5:16 | LL | trait Foo { | - item list starts here diff --git a/tests/ui/pattern/issue-115599.rs b/tests/ui/pattern/issue-115599.rs index 7a222b90aec97..1521d728d9561 100644 --- a/tests/ui/pattern/issue-115599.rs +++ b/tests/ui/pattern/issue-115599.rs @@ -3,5 +3,5 @@ const CONST_STRING: String = String::new(); fn main() { let empty_str = String::from(""); if let CONST_STRING = empty_str {} - //~^ ERROR to use a constant of type `Vec` in a pattern, `Vec` must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR to use a constant of type `Vec` in a pattern, `Vec` must be annotated with `#[derive(PartialEq)]` } diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr index c1e85d0bb48a9..adab4e4d241b7 100644 --- a/tests/ui/pattern/issue-115599.stderr +++ b/tests/ui/pattern/issue-115599.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `Vec` in a pattern, `Vec` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `Vec` in a pattern, `Vec` must be annotated with `#[derive(PartialEq)]` --> $DIR/issue-115599.rs:5:12 | LL | if let CONST_STRING = empty_str {} | ^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs index c26e457f9e452..8a0f51d0b84b9 100644 --- a/tests/ui/pattern/issue-22546.rs +++ b/tests/ui/pattern/issue-22546.rs @@ -15,7 +15,7 @@ impl Foo { } } -trait Tr { +trait Tr { //~ WARN trait `Tr` is never used type U; } diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr new file mode 100644 index 0000000000000..e067a95e4226c --- /dev/null +++ b/tests/ui/pattern/issue-22546.stderr @@ -0,0 +1,10 @@ +warning: trait `Tr` is never used + --> $DIR/issue-22546.rs:18:7 + | +LL | trait Tr { + | ^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/pattern/never_patterns.rs b/tests/ui/pattern/never_patterns.rs deleted file mode 100644 index 8f44f8a655931..0000000000000 --- a/tests/ui/pattern/never_patterns.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![feature(never_patterns)] -#![allow(incomplete_features)] - -enum Void {} - -fn main() {} - -// The classic use for empty types. -fn safe_unwrap_result(res: Result) { - let Ok(_x) = res; //~ ERROR refutable pattern in local binding - let (Ok(_x) | Err(!)) = &res; - let (Ok(_x) | Err(&!)) = res.as_ref(); -} - -// Check we only accept `!` where we want to. -fn never_pattern_location(void: Void) { - // FIXME(never_patterns): Don't accept on a non-empty type. - match Some(0) { - None => {} - Some(!), - } - // FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches. - match () { - () => {} - !, - } - // FIXME(never_patterns): Don't accept even on an empty branch. - match None:: { - None => {} - !, - } - // FIXME(never_patterns): Let alone if the emptiness is behind a reference. - match None::<&Void> { - None => {} - !, - } - // Participate in match ergonomics. - match &void { - ! - } - match &&void { - ! - } - match &&void { - &! - } - match &None:: { - None => {} - Some(!) - } - match None::<&Void> { - None => {} - Some(!), - } - // Accept on a composite empty type. - match None::<&(u32, Void)> { - None => {} - Some(&!), - } - // Accept on an simple empty type. - match None:: { - None => {} - Some(!), - } - match None::<&Void> { - None => {} - Some(&!), - } - match None::<&(u32, Void)> { - None => {} - Some(&(_, !)), - } -} diff --git a/tests/ui/pattern/never_patterns.stderr b/tests/ui/pattern/never_patterns.stderr deleted file mode 100644 index 20eeb01cf7140..0000000000000 --- a/tests/ui/pattern/never_patterns.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0005]: refutable pattern in local binding - --> $DIR/never_patterns.rs:10:9 - | -LL | let Ok(_x) = res; - | ^^^^^^ pattern `Err(_)` not covered - | - = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant - = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `Result` -help: you might want to use `let else` to handle the variant that isn't matched - | -LL | let Ok(_x) = res else { todo!() }; - | ++++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index b4f19bb829407..552342a1d3841 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -1,6 +1,5 @@ // edition:2021 -#![allow(incomplete_features)] #![allow(unreachable_code)] #![feature(const_async_blocks)] #![feature(inline_const_pat)] diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index 4a6990da56f6d..f3e0665fef51d 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -1,11 +1,11 @@ -error: `{closure@$DIR/non-structural-match-types.rs:10:17: 10:19}` cannot be used in patterns - --> $DIR/non-structural-match-types.rs:10:9 +error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:9:9 | LL | const { || {} } => {} | ^^^^^^^^^^^^^^^ -error: `{async block@$DIR/non-structural-match-types.rs:13:17: 13:25}` cannot be used in patterns - --> $DIR/non-structural-match-types.rs:13:9 +error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:12:9 | LL | const { async {} } => {} | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs index a619fcafc8614..1eba7aeb4d64a 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs @@ -1,9 +1,23 @@ fn main() { match &[1, 2, 3][..] { - [1, rest..] => println!("{rest:?}"), + [1, rest..] => println!("{rest}"), //~^ ERROR cannot find value `rest` in this scope //~| ERROR cannot find value `rest` in this scope //~| ERROR `X..` patterns in slices are experimental _ => {} } + match &[4, 5, 6][..] { + [] => {} + [_, ..tail] => println!("{tail}"), + //~^ ERROR cannot find value `tail` in this scope + //~| ERROR cannot find value `tail` in this scope + //~| ERROR exclusive range pattern syntax is experimental + } + match &[7, 8, 9][..] { + [] => {} + [_, ...tail] => println!("{tail}"), + //~^ ERROR cannot find value `tail` in this scope + //~| ERROR cannot find value `tail` in this scope + //~| ERROR range-to patterns with `...` are not allowed + } } diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr index c3c9131b63eb2..3a19517c85bd2 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr @@ -1,31 +1,82 @@ +error: range-to patterns with `...` are not allowed + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:13 + | +LL | [_, ...tail] => println!("{tail}"), + | ^^^ help: use `..=` instead + error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13 | -LL | [1, rest..] => println!("{rest:?}"), +LL | [1, rest..] => println!("{rest}"), | ^^^^ not found in this scope | help: if you meant to collect the rest of the slice in `rest`, use the at operator | -LL | [1, rest @ ..] => println!("{rest:?}"), +LL | [1, rest @ ..] => println!("{rest}"), | + error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35 | -LL | [1, rest..] => println!("{rest:?}"), +LL | [1, rest..] => println!("{rest}"), + | ^^^^ not found in this scope + +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:15 + | +LL | [_, ..tail] => println!("{tail}"), + | ^^^^ not found in this scope + | +help: if you meant to collect the rest of the slice in `tail`, use the at operator + | +LL | [_, tail @ ..] => println!("{tail}"), + | ~~~~~~~~~ + +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35 + | +LL | [_, ..tail] => println!("{tail}"), | ^^^^ not found in this scope +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:16 + | +LL | [_, ...tail] => println!("{tail}"), + | ^^^^ not found in this scope + | +help: if you meant to collect the rest of the slice in `tail`, use the at operator + | +LL | [_, tail @ ..] => println!("{tail}"), + | ~~~~~~~~~ + +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:36 + | +LL | [_, ...tail] => println!("{tail}"), + | ^^^^ not found in this scope + error[E0658]: `X..` patterns in slices are experimental --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13 | -LL | [1, rest..] => println!("{rest:?}"), +LL | [1, rest..] => println!("{rest}"), | ^^^^^^ | = note: see issue #67264 for more information = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:13 + | +LL | [_, ..tail] => println!("{tail}"), + | ^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0425, E0658. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs index 02599d7c05b59..f34093ef1498b 100644 --- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs +++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs @@ -12,7 +12,7 @@ const CONSTANT: &&MyType = &&MyType; fn main() { if let CONSTANT = &&MyType { - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` println!("did match!"); } } diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr index 2352ecd0a470d..59b454d398195 100644 --- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr +++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr @@ -1,11 +1,29 @@ -error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]` --> $DIR/const-partial_eq-fallback-ice.rs:14:12 | LL | if let CONSTANT = &&MyType { | ^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]` + --> $DIR/const-partial_eq-fallback-ice.rs:14:12 + | +LL | if let CONSTANT = &&MyType { + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/const-partial_eq-fallback-ice.rs:1:10 + | +LL | #![allow(warnings)] + | ^^^^^^^^ + = note: `#[allow(indirect_structural_match)]` implied by `#[allow(warnings)]` + diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs index 27e305a397242..3e4617851823e 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.rs +++ b/tests/ui/pattern/usefulness/consts-opaque.rs @@ -29,65 +29,63 @@ const BAZ: Baz = Baz::Baz1; fn main() { match FOO { FOO => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } match FOO_REF { FOO_REF => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` Foo(_) => {} } // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) match FOO_REF_REF { FOO_REF_REF => {} - //~^ WARNING must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARNING this was previously accepted by the compiler but is being phased out Foo(_) => {} } match BAR { Bar => {} BAR => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR unreachable pattern _ => {} + //~^ ERROR unreachable pattern } match BAR { BAR => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` Bar => {} + //~^ ERROR unreachable pattern _ => {} + //~^ ERROR unreachable pattern } match BAR { BAR => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - BAR => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - _ => {} + BAR => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + _ => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern } match BAZ { BAZ => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Baz::Baz1 => {} + Baz::Baz1 => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern _ => {} } match BAZ { Baz::Baz1 => {} BAZ => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR unreachable pattern _ => {} } match BAZ { BAZ => {} - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` Baz::Baz2 => {} - _ => {} + _ => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern } type Quux = fn(usize, usize) -> usize; diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index 09f72ba927e1f..6a5bd185e39b3 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -1,186 +1,256 @@ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:31:9 +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:96:9 | -LL | FOO => {} - | ^^^ +LL | QUUX => {} + | ^^^^ | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:37:9 +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:98:9 | -LL | FOO_REF => {} - | ^^^^^^^ +LL | QUUX => {} + | ^^^^ | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 -warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:44:9 +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:108:9 | -LL | FOO_REF_REF => {} - | ^^^^^^^^^^^ +LL | WRAPQUUX => {} + | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `#[warn(indirect_structural_match)]` on by default + = note: for more information, see issue #120362 -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:52:9 +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:110:9 | -LL | BAR => {} - | ^^^ +LL | WRAPQUUX => {} + | ^^^^^^^^ | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:58:9 +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:117:9 | -LL | BAR => {} - | ^^^ +LL | WRAPQUUX => {} + | ^^^^^^^^ | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:65:9 +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:127:9 + | +LL | WRAPQUUX => {} + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:139:9 + | +LL | WHOKNOWSQUUX => {} + | ^^^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:142:9 + | +LL | WHOKNOWSQUUX => {} + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + +error: unreachable pattern + --> $DIR/consts-opaque.rs:48:9 + | +LL | Bar => {} + | --- matches any value LL | BAR => {} - | ^^^ + | ^^^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/consts-opaque.rs:6:9 | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:50:9 + | +LL | Bar => {} + | --- matches any value +... +LL | _ => {} + | ^ unreachable pattern -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:67:9 +error: unreachable pattern + --> $DIR/consts-opaque.rs:56:9 | LL | BAR => {} - | ^^^ + | --- matches any value +LL | Bar => {} + | ^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:58:9 | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +LL | BAR => {} + | --- matches any value +... +LL | _ => {} + | ^ unreachable pattern -error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:73:9 +error: unreachable pattern + --> $DIR/consts-opaque.rs:64:9 | -LL | BAZ => {} - | ^^^ +LL | BAR => {} + | --- matches any value +LL | BAR => {} // should not be emitting unreachable warning + | ^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:66:9 + | +LL | BAR => {} + | --- matches any value +... +LL | _ => {} // should not be emitting unreachable warning + | ^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:72:9 | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +LL | Baz::Baz1 => {} // should not be emitting unreachable warning + | ^^^^^^^^^ -error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:81:9 +error: unreachable pattern + --> $DIR/consts-opaque.rs:79:9 | LL | BAZ => {} | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` +error: unreachable pattern --> $DIR/consts-opaque.rs:87:9 | -LL | BAZ => {} - | ^^^ +LL | _ => {} // should not be emitting unreachable warning + | ^ + +error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered + --> $DIR/consts-opaque.rs:125:11 + | +LL | match WRAPQUUX { + | ^^^^^^^^ pattern `Wrap(_)` not covered + | +note: `Wrap usize>` defined here + --> $DIR/consts-opaque.rs:104:12 + | +LL | struct Wrap(T); + | ^^^^ + = note: the matched value is of type `Wrap usize>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +LL | WRAPQUUX => {}, Wrap(_) => todo!() + | ++++++++++++++++++++ +error: aborting due to 10 previous errors; 8 warnings emitted + +For more information about this error, try `rustc --explain E0004`. +Future incompatibility report: Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:98:9 + --> $DIR/consts-opaque.rs:96:9 | LL | QUUX => {} | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:100:9 + --> $DIR/consts-opaque.rs:98:9 | LL | QUUX => {} | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:110:9 + --> $DIR/consts-opaque.rs:108:9 | LL | WRAPQUUX => {} | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:112:9 + --> $DIR/consts-opaque.rs:110:9 | LL | WRAPQUUX => {} | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:119:9 + --> $DIR/consts-opaque.rs:117:9 | LL | WRAPQUUX => {} | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:129:9 + --> $DIR/consts-opaque.rs:127:9 | LL | WRAPQUUX => {} | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:141:9 + --> $DIR/consts-opaque.rs:139:9 | LL | WHOKNOWSQUUX => {} | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default +Future breakage diagnostic: warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. - --> $DIR/consts-opaque.rs:144:9 + --> $DIR/consts-opaque.rs:142:9 | LL | WHOKNOWSQUUX => {} | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 - -error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered - --> $DIR/consts-opaque.rs:127:11 - | -LL | match WRAPQUUX { - | ^^^^^^^^ pattern `Wrap(_)` not covered - | -note: `Wrap usize>` defined here - --> $DIR/consts-opaque.rs:106:12 - | -LL | struct Wrap(T); - | ^^^^ - = note: the matched value is of type `Wrap usize>` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown - | -LL | WRAPQUUX => {}, Wrap(_) => todo!() - | ++++++++++++++++++++ - -error: aborting due to 10 previous errors; 9 warnings emitted + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default -For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr index 367aba3bdd6e6..0c55164a780b5 100644 --- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr @@ -1,23 +1,23 @@ error: unreachable pattern - --> $DIR/empty-types.rs:47:9 + --> $DIR/empty-types.rs:50:9 | LL | _ => {} | ^ | note: the lint level is defined here - --> $DIR/empty-types.rs:13:9 + --> $DIR/empty-types.rs:16:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:50:9 + --> $DIR/empty-types.rs:53:9 | LL | _x => {} | ^^ error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:54:11 + --> $DIR/empty-types.rs:57:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -32,31 +32,31 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:69:9 + --> $DIR/empty-types.rs:72:9 | LL | (_, _) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:76:9 + --> $DIR/empty-types.rs:79:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:79:9 + --> $DIR/empty-types.rs:82:9 | LL | (_, _) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:83:9 + --> $DIR/empty-types.rs:86:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `Ok(_)` not covered - --> $DIR/empty-types.rs:87:11 + --> $DIR/empty-types.rs:90:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered @@ -75,19 +75,19 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:95:9 + --> $DIR/empty-types.rs:98:9 | LL | Err(_) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:100:9 + --> $DIR/empty-types.rs:103:9 | LL | Err(_) => {} | ^^^^^^ error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:97:11 + --> $DIR/empty-types.rs:100:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -105,7 +105,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:104:9 + --> $DIR/empty-types.rs:107:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -119,121 +119,121 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:115:9 + --> $DIR/empty-types.rs:118:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:119:9 + --> $DIR/empty-types.rs:122:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:122:9 + --> $DIR/empty-types.rs:125:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:123:9 + --> $DIR/empty-types.rs:126:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:126:9 + --> $DIR/empty-types.rs:129:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:127:9 + --> $DIR/empty-types.rs:130:9 | LL | Err(_) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:136:13 + --> $DIR/empty-types.rs:139:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:139:13 + --> $DIR/empty-types.rs:142:13 | LL | _ if false => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:148:13 + --> $DIR/empty-types.rs:151:13 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:152:13 + --> $DIR/empty-types.rs:155:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:204:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:209:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:214:13 + --> $DIR/empty-types.rs:217:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:222:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:225:13 + --> $DIR/empty-types.rs:228:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:284:9 + --> $DIR/empty-types.rs:287:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:287:9 + --> $DIR/empty-types.rs:290:9 | LL | (_, _) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:290:9 + --> $DIR/empty-types.rs:293:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:291:9 + --> $DIR/empty-types.rs:294:9 | LL | Err(_) => {} | ^^^^^^ error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:323:11 + --> $DIR/empty-types.rs:326:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -247,7 +247,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `&[]` not covered - --> $DIR/empty-types.rs:334:11 + --> $DIR/empty-types.rs:337:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[]` not covered @@ -260,7 +260,7 @@ LL + &[] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` not covered - --> $DIR/empty-types.rs:347:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[]` not covered @@ -274,7 +274,7 @@ LL + &[] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:353:11 + --> $DIR/empty-types.rs:356:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -288,25 +288,25 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:363:9 + --> $DIR/empty-types.rs:366:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:366:9 + --> $DIR/empty-types.rs:369:9 | LL | [_, _, _] => {} | ^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:369:9 + --> $DIR/empty-types.rs:372:9 | LL | [_, ..] => {} | ^^^^^^^ error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:383:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -320,13 +320,13 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:390:9 + --> $DIR/empty-types.rs:393:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:392:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -340,49 +340,49 @@ LL + [] => todo!() | error: unreachable pattern - --> $DIR/empty-types.rs:411:9 + --> $DIR/empty-types.rs:414:9 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:416:9 + --> $DIR/empty-types.rs:419:9 | LL | Some(_a) => {} | ^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:421:9 + --> $DIR/empty-types.rs:424:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:426:9 + --> $DIR/empty-types.rs:429:9 | LL | _a => {} | ^^ error: unreachable pattern - --> $DIR/empty-types.rs:598:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:601:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^ error: unreachable pattern - --> $DIR/empty-types.rs:604:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:607:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^ diff --git a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr new file mode 100644 index 0000000000000..ed5d125e68404 --- /dev/null +++ b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr @@ -0,0 +1,630 @@ +warning: the feature `min_exhaustive_patterns` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/empty-types.rs:13:35 + | +LL | #![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #119612 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: unreachable pattern + --> $DIR/empty-types.rs:50:9 + | +LL | _ => {} + | ^ + | +note: the lint level is defined here + --> $DIR/empty-types.rs:16:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:53:9 + | +LL | _x => {} + | ^^ + +error[E0004]: non-exhaustive patterns: type `&!` is non-empty + --> $DIR/empty-types.rs:57:11 + | +LL | match ref_never {} + | ^^^^^^^^^ + | + = note: the matched value is of type `&!` + = note: references are always considered inhabited +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match ref_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:72:9 + | +LL | (_, _) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:79:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:82:9 + | +LL | (_, _) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:86:9 + | +LL | _ => {} + | ^ + +error[E0004]: non-exhaustive patterns: `Ok(_)` not covered + --> $DIR/empty-types.rs:90:11 + | +LL | match res_u32_never {} + | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered + | +note: `Result` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ match res_u32_never { +LL + Ok(_) => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:98:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:103:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered + --> $DIR/empty-types.rs:100:11 + | +LL | match res_u32_never { + | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered + | +note: `Result` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Err(_) => {}, +LL ~ Ok(1_u32..=u32::MAX) => todo!() + | + +error[E0005]: refutable pattern in local binding + --> $DIR/empty-types.rs:107:9 + | +LL | let Ok(_x) = res_u32_never.as_ref(); + | ^^^^^^ pattern `Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `Result<&u32, &!>` +help: you might want to use `let else` to handle the variant that isn't matched + | +LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; + | ++++++++++++++++ + +error[E0005]: refutable pattern in local binding + --> $DIR/empty-types.rs:111:9 + | +LL | let Ok(_x) = &res_u32_never; + | ^^^^^^ pattern `&Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `&Result` +help: you might want to use `let else` to handle the variant that isn't matched + | +LL | let Ok(_x) = &res_u32_never else { todo!() }; + | ++++++++++++++++ + +error: unreachable pattern + --> $DIR/empty-types.rs:118:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:122:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:125:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:126:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:129:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:130:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:139:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:142:13 + | +LL | _ if false => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:151:13 + | +LL | Some(_) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:155:13 + | +LL | _ => {} + | ^ + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:164:15 + | +LL | match *ref_opt_void { + | ^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error: unreachable pattern + --> $DIR/empty-types.rs:207:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:212:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:217:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:222:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:228:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:287:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:290:9 + | +LL | (_, _) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:293:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:294:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty + --> $DIR/empty-types.rs:315:11 + | +LL | match *x {} + | ^^ + | + = note: the matched value is of type `(u32, !)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty + --> $DIR/empty-types.rs:317:11 + | +LL | match *x {} + | ^^ + | + = note: the matched value is of type `(!, !)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered + --> $DIR/empty-types.rs:319:11 + | +LL | match *x {} + | ^^ patterns `Ok(_)` and `Err(_)` not covered + | +note: `Result` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match *x { +LL + Ok(_) | Err(_) => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty + --> $DIR/empty-types.rs:321:11 + | +LL | match *x {} + | ^^ + | + = note: the matched value is of type `[!; 3]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty + --> $DIR/empty-types.rs:326:11 + | +LL | match slice_never {} + | ^^^^^^^^^^^ + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match slice_never { +LL + _ => todo!(), +LL + } + | + +error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered + --> $DIR/empty-types.rs:328:11 + | +LL | match slice_never { + | ^^^^^^^^^^^ pattern `&[_, ..]` not covered + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [] => {}, +LL + &[_, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered + --> $DIR/empty-types.rs:337:11 + | +LL | match slice_never { + | ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ [_, _, _, ..] => {}, +LL + &[] | &[_] | &[_, _] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered + --> $DIR/empty-types.rs:350:11 + | +LL | match slice_never { + | ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered + | + = note: the matched value is of type `&[!]` + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ &[..] if false => {}, +LL + &[] | &[_, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: type `[!]` is non-empty + --> $DIR/empty-types.rs:356:11 + | +LL | match *slice_never {} + | ^^^^^^^^^^^^ + | + = note: the matched value is of type `[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *slice_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:366:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:369:9 + | +LL | [_, _, _] => {} + | ^^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:372:9 + | +LL | [_, ..] => {} + | ^^^^^^^ + +error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty + --> $DIR/empty-types.rs:386:11 + | +LL | match array_0_never {} + | ^^^^^^^^^^^^^ + | + = note: the matched value is of type `[!; 0]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match array_0_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:393:9 + | +LL | _ => {} + | ^ + +error[E0004]: non-exhaustive patterns: `[]` not covered + --> $DIR/empty-types.rs:395:11 + | +LL | match array_0_never { + | ^^^^^^^^^^^^^ pattern `[]` not covered + | + = note: the matched value is of type `[!; 0]` + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [..] if false => {}, +LL + [] => todo!() + | + +error: unreachable pattern + --> $DIR/empty-types.rs:414:9 + | +LL | Some(_) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:419:9 + | +LL | Some(_a) => {} + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:424:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:429:9 + | +LL | _a => {} + | ^^ + +error[E0004]: non-exhaustive patterns: `&Some(_)` not covered + --> $DIR/empty-types.rs:449:11 + | +LL | match ref_opt_never { + | ^^^^^^^^^^^^^ pattern `&Some(_)` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `&Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ &None => {}, +LL + &Some(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:490:11 + | +LL | match *ref_opt_never { + | ^^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Err(_)` not covered + --> $DIR/empty-types.rs:538:11 + | +LL | match *ref_res_never { + | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered + | +note: `Result` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Ok(_) => {}, +LL + Err(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Err(_)` not covered + --> $DIR/empty-types.rs:549:11 + | +LL | match *ref_res_never { + | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered + | +note: `Result` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Ok(_a) => {}, +LL + Err(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty + --> $DIR/empty-types.rs:568:11 + | +LL | match *ref_tuple_half_never {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the matched value is of type `(u32, !)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *ref_tuple_half_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:601:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:604:9 + | +LL | _x => {} + | ^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:607:9 + | +LL | _ if false => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:610:9 + | +LL | _x if false => {} + | ^^ + +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/empty-types.rs:635:11 + | +LL | match ref_never { + | ^^^^^^^^^ pattern `&_` not covered + | + = note: the matched value is of type `&!` + = note: references are always considered inhabited + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ &_a if false => {}, +LL + &_ => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:663:11 + | +LL | match *x { + | ^^ pattern `Some(_)` not covered + | +note: `Option>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error: aborting due to 63 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index 133a95a821ba3..2fdb51677dac5 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -1,23 +1,23 @@ error: unreachable pattern - --> $DIR/empty-types.rs:47:9 + --> $DIR/empty-types.rs:50:9 | LL | _ => {} | ^ | note: the lint level is defined here - --> $DIR/empty-types.rs:13:9 + --> $DIR/empty-types.rs:16:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:50:9 + --> $DIR/empty-types.rs:53:9 | LL | _x => {} | ^^ error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:54:11 + --> $DIR/empty-types.rs:57:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:66:11 + --> $DIR/empty-types.rs:69:11 | LL | match tuple_half_never {} | ^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty - --> $DIR/empty-types.rs:73:11 + --> $DIR/empty-types.rs:76:11 | LL | match tuple_never {} | ^^^^^^^^^^^ @@ -60,13 +60,13 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:83:9 + --> $DIR/empty-types.rs:86:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:87:11 + --> $DIR/empty-types.rs:90:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered @@ -88,7 +88,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:89:11 + --> $DIR/empty-types.rs:92:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -106,7 +106,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:97:11 + --> $DIR/empty-types.rs:100:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -124,7 +124,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:102:9 + --> $DIR/empty-types.rs:105:9 | LL | let Ok(_x) = res_u32_never; | ^^^^^^ pattern `Err(_)` not covered @@ -138,7 +138,7 @@ LL | let Ok(_x) = res_u32_never else { todo!() }; | ++++++++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:104:9 + --> $DIR/empty-types.rs:107:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -152,7 +152,7 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:108:9 + --> $DIR/empty-types.rs:111:9 | LL | let Ok(_x) = &res_u32_never; | ^^^^^^ pattern `&Err(_)` not covered @@ -166,7 +166,7 @@ LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:112:11 + --> $DIR/empty-types.rs:115:11 | LL | match result_never {} | ^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered @@ -188,7 +188,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:117:11 + --> $DIR/empty-types.rs:120:11 | LL | match result_never { | ^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -205,19 +205,19 @@ LL | Ok(_) => {}, Err(_) => todo!() | +++++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:136:13 + --> $DIR/empty-types.rs:139:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:139:13 + --> $DIR/empty-types.rs:142:13 | LL | _ if false => {} | ^ error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:142:15 + --> $DIR/empty-types.rs:145:15 | LL | match opt_void { | ^^^^^^^^ pattern `Some(_)` not covered @@ -235,7 +235,7 @@ LL + Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:161:15 + --> $DIR/empty-types.rs:164:15 | LL | match *ref_opt_void { | ^^^^^^^^^^^^^ pattern `Some(_)` not covered @@ -253,43 +253,43 @@ LL + Some(_) => todo!() | error: unreachable pattern - --> $DIR/empty-types.rs:204:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:209:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:214:13 + --> $DIR/empty-types.rs:217:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:222:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:225:13 + --> $DIR/empty-types.rs:228:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:284:9 + --> $DIR/empty-types.rs:287:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:312:11 + --> $DIR/empty-types.rs:315:11 | LL | match *x {} | ^^ @@ -303,7 +303,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty - --> $DIR/empty-types.rs:314:11 + --> $DIR/empty-types.rs:317:11 | LL | match *x {} | ^^ @@ -317,7 +317,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:316:11 + --> $DIR/empty-types.rs:319:11 | LL | match *x {} | ^^ patterns `Ok(_)` and `Err(_)` not covered @@ -339,7 +339,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty - --> $DIR/empty-types.rs:318:11 + --> $DIR/empty-types.rs:321:11 | LL | match *x {} | ^^ @@ -353,7 +353,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:323:11 + --> $DIR/empty-types.rs:326:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered - --> $DIR/empty-types.rs:325:11 + --> $DIR/empty-types.rs:328:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[_, ..]` not covered @@ -380,7 +380,7 @@ LL + &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered - --> $DIR/empty-types.rs:334:11 + --> $DIR/empty-types.rs:337:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered @@ -393,7 +393,7 @@ LL + &[] | &[_] | &[_, _] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered - --> $DIR/empty-types.rs:347:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered @@ -407,7 +407,7 @@ LL + &[] | &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:353:11 + --> $DIR/empty-types.rs:356:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -421,7 +421,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty - --> $DIR/empty-types.rs:360:11 + --> $DIR/empty-types.rs:363:11 | LL | match array_3_never {} | ^^^^^^^^^^^^^ @@ -435,7 +435,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:383:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -449,13 +449,13 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:390:9 + --> $DIR/empty-types.rs:393:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:392:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -469,7 +469,7 @@ LL + [] => todo!() | error[E0004]: non-exhaustive patterns: `&Some(_)` not covered - --> $DIR/empty-types.rs:446:11 + --> $DIR/empty-types.rs:449:11 | LL | match ref_opt_never { | ^^^^^^^^^^^^^ pattern `&Some(_)` not covered @@ -487,7 +487,7 @@ LL + &Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:487:11 + --> $DIR/empty-types.rs:490:11 | LL | match *ref_opt_never { | ^^^^^^^^^^^^^^ pattern `Some(_)` not covered @@ -505,7 +505,7 @@ LL + Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:535:11 + --> $DIR/empty-types.rs:538:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -523,7 +523,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:546:11 + --> $DIR/empty-types.rs:549:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -541,7 +541,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:565:11 + --> $DIR/empty-types.rs:568:11 | LL | match *ref_tuple_half_never {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -555,31 +555,31 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:598:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:601:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^ error: unreachable pattern - --> $DIR/empty-types.rs:604:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:607:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^ error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/empty-types.rs:631:11 + --> $DIR/empty-types.rs:635:11 | LL | match ref_never { | ^^^^^^^^^ pattern `&_` not covered @@ -594,7 +594,7 @@ LL + &_ => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:659:11 + --> $DIR/empty-types.rs:663:11 | LL | match *x { | ^^ pattern `Some(_)` not covered diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs index 1e1d23e446d4c..c66fd1edc19ec 100644 --- a/tests/ui/pattern/usefulness/empty-types.rs +++ b/tests/ui/pattern/usefulness/empty-types.rs @@ -1,4 +1,5 @@ -// revisions: normal exhaustive_patterns +// revisions: normal min_exh_pats exhaustive_patterns +// gate-test-min_exhaustive_patterns // // This tests correct handling of empty types in exhaustiveness checking. // @@ -9,6 +10,8 @@ // This feature is useful to avoid `!` falling back to `()` all the time. #![feature(never_type_fallback)] #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] +#![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))] +//[min_exh_pats]~^ WARN the feature `min_exhaustive_patterns` is incomplete #![allow(dead_code, unreachable_code)] #![deny(unreachable_patterns)] @@ -66,17 +69,17 @@ fn basic(x: NeverBundle) { match tuple_half_never {} //[normal]~^ ERROR non-empty match tuple_half_never { - (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let tuple_never: (!, !) = x.tuple_never; match tuple_never {} //[normal]~^ ERROR non-empty match tuple_never { - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match tuple_never { - (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match tuple_never.0 {} match tuple_never.0 { @@ -92,12 +95,12 @@ fn basic(x: NeverBundle) { } match res_u32_never { Ok(_) => {} - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match res_u32_never { //~^ ERROR non-exhaustive Ok(0) => {} - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let Ok(_x) = res_u32_never; //[normal]~^ ERROR refutable @@ -106,25 +109,25 @@ fn basic(x: NeverBundle) { // Non-obvious difference: here there's an implicit dereference in the patterns, which makes the // inner place !known_valid. `exhaustive_patterns` ignores this. let Ok(_x) = &res_u32_never; - //[normal]~^ ERROR refutable + //[normal,min_exh_pats]~^ ERROR refutable let result_never: Result = x.result_never; match result_never {} //[normal]~^ ERROR non-exhaustive match result_never { - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { //[normal]~^ ERROR non-exhaustive - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } } @@ -145,11 +148,11 @@ fn void_same_as_never(x: NeverBundle) { } match opt_void { None => {} - Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_void { None => {} - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let ref_void: &Void = &x.void; @@ -159,7 +162,7 @@ fn void_same_as_never(x: NeverBundle) { } let ref_opt_void: &Option = &None; match *ref_opt_void { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive None => {} } match *ref_opt_void { @@ -284,11 +287,11 @@ fn nested_validity_tracking(bundle: NeverBundle) { _ => {} //~ ERROR unreachable pattern } match tuple_never { - (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } // These should be considered !known_valid and not warn unreachable. @@ -309,13 +312,13 @@ fn invalid_empty_match(bundle: NeverBundle) { match *x {} let x: &(u32, !) = &bundle.tuple_half_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive let x: &(!, !) = &bundle.tuple_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive let x: &Result = &bundle.result_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive let x: &[!; 3] = &bundle.array_3_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive } fn arrays_and_slices(x: NeverBundle) { @@ -323,7 +326,7 @@ fn arrays_and_slices(x: NeverBundle) { match slice_never {} //~^ ERROR non-empty match slice_never { - //[normal]~^ ERROR not covered + //[normal,min_exh_pats]~^ ERROR not covered [] => {} } match slice_never { @@ -332,7 +335,7 @@ fn arrays_and_slices(x: NeverBundle) { [_, _, ..] => {} } match slice_never { - //[normal]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered + //[normal,min_exh_pats]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered //[exhaustive_patterns]~^^ ERROR `&[]` not covered [_, _, _, ..] => {} } @@ -345,7 +348,7 @@ fn arrays_and_slices(x: NeverBundle) { _x => {} } match slice_never { - //[normal]~^ ERROR `&[]` and `&[_, ..]` not covered + //[normal,min_exh_pats]~^ ERROR `&[]` and `&[_, ..]` not covered //[exhaustive_patterns]~^^ ERROR `&[]` not covered &[..] if false => {} } @@ -360,13 +363,13 @@ fn arrays_and_slices(x: NeverBundle) { match array_3_never {} //[normal]~^ ERROR non-empty match array_3_never { - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match array_3_never { - [_, _, _] => {} //[exhaustive_patterns]~ ERROR unreachable pattern + [_, _, _] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match array_3_never { - [_, ..] => {} //[exhaustive_patterns]~ ERROR unreachable pattern + [_, ..] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let ref_array_3_never: &[!; 3] = &array_3_never; @@ -408,22 +411,22 @@ fn bindings(x: NeverBundle) { match opt_never { None => {} // !useful, !reachable - Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - Some(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Some(_a) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _a => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } // The scrutinee is known_valid, but under the `&` isn't anymore. @@ -444,7 +447,7 @@ fn bindings(x: NeverBundle) { &_a => {} } match ref_opt_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive &None => {} } match ref_opt_never { @@ -485,7 +488,7 @@ fn bindings(x: NeverBundle) { ref _a => {} } match *ref_opt_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive None => {} } match *ref_opt_never { @@ -533,7 +536,7 @@ fn bindings(x: NeverBundle) { let ref_res_never: &Result = &x.result_never; match *ref_res_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive // useful, reachable Ok(_) => {} } @@ -544,7 +547,7 @@ fn bindings(x: NeverBundle) { _ => {} } match *ref_res_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive // useful, !reachable Ok(_a) => {} } @@ -563,7 +566,7 @@ fn bindings(x: NeverBundle) { let ref_tuple_half_never: &(u32, !) = &x.tuple_half_never; match *ref_tuple_half_never {} - //[normal]~^ ERROR non-empty + //[normal,min_exh_pats]~^ ERROR non-empty match *ref_tuple_half_never { // useful, reachable (_, _) => {} @@ -614,6 +617,7 @@ fn guards_and_validity(x: NeverBundle) { // useful, reachable _ => {} } + // Now the madness commences. The guard caused a load of the value thus asserting validity. So // there's no invalid value for `_` to catch. So the second pattern is unreachable despite the // guard not being taken. @@ -629,7 +633,7 @@ fn guards_and_validity(x: NeverBundle) { _a if false => {} } match ref_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive // useful, !reachable &_a if false => {} } @@ -657,7 +661,7 @@ fn diagnostics_subtlety(x: NeverBundle) { // Regression test for diagnostics: don't report `Some(Ok(_))` and `Some(Err(_))`. let x: &Option> = &None; match *x { - //[normal]~^ ERROR `Some(_)` not covered + //[normal,min_exh_pats]~^ ERROR `Some(_)` not covered None => {} } } diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs index 2616dfadb85e8..63ce26adab2a4 100644 --- a/tests/ui/pattern/usefulness/floats.rs +++ b/tests/ui/pattern/usefulness/floats.rs @@ -1,5 +1,4 @@ #![feature(exclusive_range_pattern)] -#![allow(illegal_floating_point_literal_pattern)] #![deny(unreachable_patterns)] fn main() { diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr index f50419118246b..d99f05f52842d 100644 --- a/tests/ui/pattern/usefulness/floats.stderr +++ b/tests/ui/pattern/usefulness/floats.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/floats.rs:11:11 + --> $DIR/floats.rs:10:11 | LL | match 0.0 { | ^^^ pattern `_` not covered @@ -12,49 +12,49 @@ LL + _ => todo!() | error: unreachable pattern - --> $DIR/floats.rs:19:9 + --> $DIR/floats.rs:18:9 | LL | 0.01f64 => {} | ^^^^^^^ | note: the lint level is defined here - --> $DIR/floats.rs:3:9 + --> $DIR/floats.rs:2:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:20:9 + --> $DIR/floats.rs:19:9 | LL | 0.02f64 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:21:9 + --> $DIR/floats.rs:20:9 | LL | 6.5f64 => {} | ^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:23:9 + --> $DIR/floats.rs:22:9 | LL | 1.0f64..=4.0f64 => {} | ^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:35:9 + --> $DIR/floats.rs:34:9 | LL | 0.01f32 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:36:9 + --> $DIR/floats.rs:35:9 | LL | 0.02f32 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:37:9 + --> $DIR/floats.rs:36:9 | LL | 6.5f32 => {} | ^^^^^^ diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.rs b/tests/ui/pattern/usefulness/non-exhaustive-match.rs index 1cb58b8cebef7..44acd397f8d58 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/tests/ui/pattern/usefulness/non-exhaustive-match.rs @@ -1,5 +1,3 @@ -#![allow(illegal_floating_point_literal_pattern)] - enum T { A, B } fn main() { diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr index 4bebd3cbbefd0..61ed0eb4fc4e2 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -1,11 +1,11 @@ error[E0004]: non-exhaustive patterns: `T::A` not covered - --> $DIR/non-exhaustive-match.rs:7:11 + --> $DIR/non-exhaustive-match.rs:5:11 | LL | match x { T::B => { } } | ^ pattern `T::A` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match.rs:3:6 + --> $DIR/non-exhaustive-match.rs:1:6 | LL | enum T { A, B } | ^ - not covered @@ -16,7 +16,7 @@ LL | match x { T::B => { }, T::A => todo!() } | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `false` not covered - --> $DIR/non-exhaustive-match.rs:8:11 + --> $DIR/non-exhaustive-match.rs:6:11 | LL | match true { | ^^^^ pattern `false` not covered @@ -29,7 +29,7 @@ LL + false => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/non-exhaustive-match.rs:11:11 + --> $DIR/non-exhaustive-match.rs:9:11 | LL | match Some(10) { | ^^^^^^^^ pattern `Some(_)` not covered @@ -47,7 +47,7 @@ LL + Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered - --> $DIR/non-exhaustive-match.rs:14:11 + --> $DIR/non-exhaustive-match.rs:12:11 | LL | match (2, 3, 4) { | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered @@ -60,7 +60,7 @@ LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!() | error[E0004]: non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered - --> $DIR/non-exhaustive-match.rs:18:11 + --> $DIR/non-exhaustive-match.rs:16:11 | LL | match (T::A, T::A) { | ^^^^^^^^^^^^ patterns `(T::A, T::A)` and `(T::B, T::B)` not covered @@ -73,13 +73,13 @@ LL + (T::A, T::A) | (T::B, T::B) => todo!() | error[E0004]: non-exhaustive patterns: `T::B` not covered - --> $DIR/non-exhaustive-match.rs:22:11 + --> $DIR/non-exhaustive-match.rs:20:11 | LL | match T::A { | ^^^^ pattern `T::B` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match.rs:3:6 + --> $DIR/non-exhaustive-match.rs:1:6 | LL | enum T { A, B } | ^ - not covered @@ -91,7 +91,7 @@ LL + T::B => todo!() | error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/non-exhaustive-match.rs:33:11 + --> $DIR/non-exhaustive-match.rs:31:11 | LL | match *vec { | ^^^^ pattern `[]` not covered @@ -104,7 +104,7 @@ LL + [] => todo!() | error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered - --> $DIR/non-exhaustive-match.rs:46:11 + --> $DIR/non-exhaustive-match.rs:44:11 | LL | match *vec { | ^^^^ pattern `[_, _, _, _, ..]` not covered diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs index 4203dd94d43aa..51ff641509df5 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs @@ -1,6 +1,6 @@ fn main() { let f = |3: isize| println!("hello"); - //~^ ERROR refutable pattern in function argument + //~^ ERROR refutable pattern in closure argument //~| `..=2_isize` and `4_isize..` not covered f(4); } diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr index bd6c5002e63e8..be119d27ab254 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in function argument +error[E0005]: refutable pattern in closure argument --> $DIR/refutable-pattern-in-fn-arg.rs:2:14 | LL | let f = |3: isize| println!("hello"); diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs index 5826a18b5718b..4aeb6a643d959 100644 --- a/tests/ui/pin-macro/cant_access_internals.rs +++ b/tests/ui/pin-macro/cant_access_internals.rs @@ -8,5 +8,5 @@ use core::{ fn main() { let mut phantom_pinned = pin!(PhantomPinned); - mem::take(phantom_pinned.pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' + mem::take(phantom_pinned.__pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' } diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr index 2737b84f5995b..444314a9d8bb3 100644 --- a/tests/ui/pin-macro/cant_access_internals.stderr +++ b/tests/ui/pin-macro/cant_access_internals.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature 'unsafe_pin_internals' --> $DIR/cant_access_internals.rs:11:15 | -LL | mem::take(phantom_pinned.pointer); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | mem::take(phantom_pinned.__pointer); + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index d1753c26ca83b..b53b893660321 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -14,17 +14,17 @@ print-type-size field `.pre`: 1 bytes print-type-size field `.post`: 2 bytes print-type-size field `.val`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption>`: 8 bytes, alignment: 4 bytes +print-type-size type: `MyOption>>`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption>`: 8 bytes, alignment: 4 bytes +print-type-size type: `MyOption, std::num::NonZero>>`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption>`: 8 bytes, alignment: 4 bytes +print-type-size type: `MyOption, u32>>`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes @@ -53,22 +53,22 @@ print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes +print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `Union1`: 4 bytes, alignment: 4 bytes +print-type-size type: `Union1>`: 4 bytes, alignment: 4 bytes print-type-size variant `Union1`: 4 bytes print-type-size field `.a`: 4 bytes -print-type-size type: `Union2`: 4 bytes, alignment: 4 bytes +print-type-size type: `Union2, std::num::NonZero>`: 4 bytes, alignment: 4 bytes print-type-size variant `Union2`: 4 bytes print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes -print-type-size type: `Union2`: 4 bytes, alignment: 4 bytes +print-type-size type: `Union2, u32>`: 4 bytes, alignment: 4 bytes print-type-size variant `Union2`: 4 bytes print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes -print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes +print-type-size type: `std::num::NonZero`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `Enum4<(), (), (), MyOption>`: 2 bytes, alignment: 1 bytes print-type-size variant `Four`: 2 bytes diff --git a/tests/ui/privacy/private-type-in-interface.rs b/tests/ui/privacy/private-type-in-interface.rs index 39e0bf23cacb2..9f55127fd168e 100644 --- a/tests/ui/privacy/private-type-in-interface.rs +++ b/tests/ui/privacy/private-type-in-interface.rs @@ -26,6 +26,7 @@ type A = ::X; //~ ERROR type `Priv` is private trait Tr2 {} impl Tr2 for u8 {} fn g() -> impl Tr2 { 0 } //~ ERROR type `Priv` is private + //~| ERROR type `Priv` is private fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private - + //~| ERROR type `ext::Priv` is private fn main() {} diff --git a/tests/ui/privacy/private-type-in-interface.stderr b/tests/ui/privacy/private-type-in-interface.stderr index 03225d84fdb34..a5e80d6962dba 100644 --- a/tests/ui/privacy/private-type-in-interface.stderr +++ b/tests/ui/privacy/private-type-in-interface.stderr @@ -46,11 +46,23 @@ error: type `Priv` is private LL | fn g() -> impl Tr2 { 0 } | ^^^^^^^^^^^^^^^^^^ private type +error: type `Priv` is private + --> $DIR/private-type-in-interface.rs:28:16 + | +LL | fn g() -> impl Tr2 { 0 } + | ^^^^^^^^^^^^^ private type + error: type `ext::Priv` is private - --> $DIR/private-type-in-interface.rs:29:15 + --> $DIR/private-type-in-interface.rs:30:15 | LL | fn g_ext() -> impl Tr2 { 0 } | ^^^^^^^^^^^^^^^^^^^^ private type -error: aborting due to 9 previous errors +error: type `ext::Priv` is private + --> $DIR/private-type-in-interface.rs:30:20 + | +LL | fn g_ext() -> impl Tr2 { 0 } + | ^^^^^^^^^^^^^^^ private type + +error: aborting due to 11 previous errors diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed index 79b6a6516ab26..6de7b865a9914 100644 --- a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] pub mod a { pub use self::b::Trait; diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.rs b/tests/ui/privacy/sealed-traits/re-exported-trait.rs index 5f96dfdcbd6c4..bf07d666dff89 100644 --- a/tests/ui/privacy/sealed-traits/re-exported-trait.rs +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] pub mod a { pub use self::b::Trait; diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr index 9f2291e6825a6..6e2f36e3f381d 100644 --- a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr @@ -1,11 +1,11 @@ error[E0603]: module `b` is private - --> $DIR/re-exported-trait.rs:11:9 + --> $DIR/re-exported-trait.rs:12:9 | LL | impl a::b::Trait for S {} | ^ private module | note: the module `b` is defined here - --> $DIR/re-exported-trait.rs:5:5 + --> $DIR/re-exported-trait.rs:6:5 | LL | mod b { | ^^^^^ diff --git a/tests/ui/proc-macro/allowed-attr-stmt-expr.stdout b/tests/ui/proc-macro/allowed-attr-stmt-expr.stdout index 8459f4e630550..947d411e8495e 100644 --- a/tests/ui/proc-macro/allowed-attr-stmt-expr.stdout +++ b/tests/ui/proc-macro/allowed-attr-stmt-expr.stdout @@ -1,5 +1,4 @@ PRINT-ATTR INPUT (DISPLAY): struct ItemWithSemi; -PRINT-ATTR RE-COLLECTED (DISPLAY): struct ItemWithSemi ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -47,7 +46,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): #[expect_let] let string = "Hello, world!"; -PRINT-ATTR RE-COLLECTED (DISPLAY): #[expect_let] let string = "Hello, world!" ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -90,7 +88,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): #[expect_my_macro_stmt] my_macro!("{}", string); -PRINT-ATTR RE-COLLECTED (DISPLAY): #[expect_my_macro_stmt] my_macro! ("{}", string) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): #[expect_my_macro_stmt] my_macro! ("{}", string); PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -144,7 +142,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): second_make_stmt!(#[allow(dead_code)] struct Bar {}); -PRINT-ATTR RE-COLLECTED (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}); PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "second_make_stmt", @@ -293,7 +291,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct NonBracedStruct; -PRINT-ATTR RE-COLLECTED (DISPLAY): #[rustc_dummy] struct NonBracedStruct ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', diff --git a/tests/ui/proc-macro/attr-stmt-expr.stdout b/tests/ui/proc-macro/attr-stmt-expr.stdout index 5e09198bbd498..e9fcbe304a0ff 100644 --- a/tests/ui/proc-macro/attr-stmt-expr.stdout +++ b/tests/ui/proc-macro/attr-stmt-expr.stdout @@ -30,7 +30,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): #[expect_let] let string = "Hello, world!"; -PRINT-ATTR RE-COLLECTED (DISPLAY): #[expect_let] let string = "Hello, world!" ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -73,7 +72,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): #[expect_my_macro_stmt] my_macro!("{}", string); -PRINT-ATTR RE-COLLECTED (DISPLAY): #[expect_my_macro_stmt] my_macro! ("{}", string) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): #[expect_my_macro_stmt] my_macro! ("{}", string); PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -127,7 +126,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): second_make_stmt!(#[allow(dead_code)] struct Bar {}); -PRINT-ATTR RE-COLLECTED (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}); PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "second_make_stmt", diff --git a/tests/ui/proc-macro/attribute-spans-preserved.stdout b/tests/ui/proc-macro/attribute-spans-preserved.stdout index 190098d021154..28f4daecc0e8e 100644 --- a/tests/ui/proc-macro/attribute-spans-preserved.stdout +++ b/tests/ui/proc-macro/attribute-spans-preserved.stdout @@ -1 +1 @@ -fn main() { let y : u32 = "z" ; { let x: u32 = "y"; } } +fn main() { let y : u32 = "z"; { let x: u32 = "y"; } } diff --git a/tests/ui/proc-macro/auxiliary/attr-stmt-expr.rs b/tests/ui/proc-macro/auxiliary/attr-stmt-expr.rs index 7a29894bbcfeb..0af628884498c 100644 --- a/tests/ui/proc-macro/auxiliary/attr-stmt-expr.rs +++ b/tests/ui/proc-macro/auxiliary/attr-stmt-expr.rs @@ -10,14 +10,14 @@ use proc_macro::TokenStream; #[proc_macro_attribute] pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "let string = \"Hello, world!\" ;"); + assert_eq!(item.to_string(), "let string = \"Hello, world!\";"); item } #[proc_macro_attribute] pub fn expect_my_macro_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "my_macro! (\"{}\", string) ;"); + assert_eq!(item.to_string(), "my_macro! (\"{}\", string);"); item } diff --git a/tests/ui/proc-macro/cfg-eval-inner.stdout b/tests/ui/proc-macro/cfg-eval-inner.stdout index 43ae47c201f8f..9fa8f437d0efa 100644 --- a/tests/ui/proc-macro/cfg-eval-inner.stdout +++ b/tests/ui/proc-macro/cfg-eval-inner.stdout @@ -11,10 +11,10 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): impl Foo < { field: [u8; { #![rustc_dummy(another_cursed_inner)] 1 }] } 0 }] > { #![rustc_dummy(evaluated_attr)] fn bar() {} } PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): impl Foo < -[u8 ; +[u8; { #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner - { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0 + { field : [u8; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0 }] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { diff --git a/tests/ui/proc-macro/derive-helper-legacy-spurious.rs b/tests/ui/proc-macro/derive-helper-legacy-spurious.rs index 4a7e48eed46c3..b484b42e56672 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-spurious.rs +++ b/tests/ui/proc-macro/derive-helper-legacy-spurious.rs @@ -5,7 +5,7 @@ #[macro_use] extern crate test_macros; -#[derive(Empty)] //~ ERROR cannot determine resolution for the attribute macro `derive` +#[derive(Empty)] #[empty_helper] //~ ERROR cannot find attribute `empty_helper` in this scope struct Foo {} diff --git a/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr b/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr index fd1ed8a3d0ff3..b34713b8ca68e 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr +++ b/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr @@ -4,19 +4,11 @@ error: cannot find attribute `dummy` in this scope LL | #![dummy] | ^^^^^ -error: cannot determine resolution for the attribute macro `derive` - --> $DIR/derive-helper-legacy-spurious.rs:8:3 - | -LL | #[derive(Empty)] - | ^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: cannot find attribute `empty_helper` in this scope --> $DIR/derive-helper-legacy-spurious.rs:9:3 | LL | #[empty_helper] | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/doc-comment-preserved.stdout b/tests/ui/proc-macro/doc-comment-preserved.stdout index b0ea180d9bdba..e9db3785d3d1d 100644 --- a/tests/ui/proc-macro/doc-comment-preserved.stdout +++ b/tests/ui/proc-macro/doc-comment-preserved.stdout @@ -6,7 +6,7 @@ PRINT-BANG INPUT (DISPLAY): /** ******* */ pub struct S; -PRINT-BANG RE-COLLECTED (DISPLAY): #[doc = "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n"] pub struct S ; +PRINT-BANG RE-COLLECTED (DISPLAY): #[doc = "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n"] pub struct S; PRINT-BANG INPUT (DEBUG): TokenStream [ Punct { ch: '#', diff --git a/tests/ui/proc-macro/dollar-crate-issue-57089.stdout b/tests/ui/proc-macro/dollar-crate-issue-57089.stdout index 7f97ac9dbc20f..79b39d36ffb7d 100644 --- a/tests/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/tests/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -1,5 +1,4 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S); -PRINT-BANG RE-COLLECTED (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -40,7 +39,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/tests/ui/proc-macro/dollar-crate-issue-62325.stdout b/tests/ui/proc-macro/dollar-crate-issue-62325.stdout index 96161049e30b0..bfd013476f3a9 100644 --- a/tests/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/tests/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -1,5 +1,4 @@ PRINT-ATTR INPUT (DISPLAY): struct A(identity! ($crate :: S)); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A(identity! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -55,7 +54,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct B(identity! ($crate :: S)); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct B(identity! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/tests/ui/proc-macro/dollar-crate.stdout b/tests/ui/proc-macro/dollar-crate.stdout index a6bdab00441a2..0278ef1ad0fcd 100644 --- a/tests/ui/proc-macro/dollar-crate.stdout +++ b/tests/ui/proc-macro/dollar-crate.stdout @@ -1,5 +1,4 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S); -PRINT-BANG RE-COLLECTED (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -40,7 +39,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -81,7 +79,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S); -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -122,7 +119,6 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-BANG INPUT (DISPLAY): struct M($crate :: S); -PRINT-BANG RE-COLLECTED (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -163,7 +159,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -204,7 +199,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S); -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/tests/ui/proc-macro/expand-to-derive.stdout b/tests/ui/proc-macro/expand-to-derive.stdout index 9f03a469aebf5..d59b7e5b88f45 100644 --- a/tests/ui/proc-macro/expand-to-derive.stdout +++ b/tests/ui/proc-macro/expand-to-derive.stdout @@ -1,12 +1,12 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo { field : - [bool ; { #[rustc_dummy] struct Inner { other_inner_field: u8, } 0 }] + [bool; { #[rustc_dummy] struct Inner { other_inner_field: u8, } 0 }] } PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct Foo { field : - [bool ; { #[rustc_dummy] struct Inner { other_inner_field : u8, } 0 }] + [bool; { #[rustc_dummy] struct Inner { other_inner_field : u8, } 0 }] } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { diff --git a/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout index eda2f433bce6e..ddd59b583a814 100644 --- a/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout +++ b/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout @@ -1,5 +1,5 @@ -PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, } +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -123,7 +123,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; }; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 }; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -203,7 +203,6 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} }; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -282,7 +281,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; }; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH }; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -360,7 +359,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; }; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 }; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -451,7 +450,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; }; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 }; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", diff --git a/tests/ui/proc-macro/inert-attribute-order.stdout b/tests/ui/proc-macro/inert-attribute-order.stdout index 86b2721797439..95b34ae84fd10 100644 --- a/tests/ui/proc-macro/inert-attribute-order.stdout +++ b/tests/ui/proc-macro/inert-attribute-order.stdout @@ -2,10 +2,10 @@ PRINT-ATTR INPUT (DISPLAY): /// 1 #[rustfmt::attr2] #[doc = "3"] #[doc = "4"] #[rustfmt::attr5] /// 6 #[print_attr(nodebug)] struct S; PRINT-ATTR RE-COLLECTED (DISPLAY): #[doc = " 1"] #[rustfmt::attr2] #[doc = "3"] #[doc = "4"] #[rustfmt::attr5] -#[doc = " 6"] #[print_attr(nodebug)] struct S ; +#[doc = " 6"] #[print_attr(nodebug)] struct S; PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[doc = " 1"] #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"] -#[rustfmt :: attr5] #[doc = " 6"] #[print_attr(nodebug)] struct S ; +#[rustfmt :: attr5] #[doc = " 6"] #[print_attr(nodebug)] struct S; PRINT-ATTR INPUT (DISPLAY): #[doc = " 1"] #[rustfmt::attr2] #[doc = "3"] #[doc = "4"] #[rustfmt::attr5] -#[doc = " 6"] struct S ; +#[doc = " 6"] struct S; PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[doc = " 1"] #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"] -#[rustfmt :: attr5] #[doc = " 6"] struct S ; +#[rustfmt :: attr5] #[doc = " 6"] struct S; diff --git a/tests/ui/proc-macro/inner-attrs.stdout b/tests/ui/proc-macro/inner-attrs.stdout index 39ec6834f0658..c8d93babe3a48 100644 --- a/tests/ui/proc-macro/inner-attrs.stdout +++ b/tests/ui/proc-macro/inner-attrs.stdout @@ -581,10 +581,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint { field: [u8; { match true { _ => { #![rustc_dummy(third)] true } }; 0 }] } PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct MyDerivePrint -{ - field : - [u8 ; { match true { _ => { #! [rustc_dummy(third)] true } } ; 0 }] -} +{ field : [u8; { match true { _ => { #! [rustc_dummy(third)] true } }; 0 }] } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -718,8 +715,7 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); -PRINT-ATTR RE-COLLECTED (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ; -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): (3, 4, { #! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ; +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): (3, 4, { #! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Parenthesis, @@ -834,8 +830,7 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); -PRINT-ATTR RE-COLLECTED (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ; -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): (3, 4, { #! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ; +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): (3, 4, { #! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Parenthesis, diff --git a/tests/ui/proc-macro/input-interpolated.stdout b/tests/ui/proc-macro/input-interpolated.stdout index 6a8789b2c4197..f2a0bc3b1aaf9 100644 --- a/tests/ui/proc-macro/input-interpolated.stdout +++ b/tests/ui/proc-macro/input-interpolated.stdout @@ -5,7 +5,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ] -PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ; +PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "const", diff --git a/tests/ui/proc-macro/issue-118455-skip-err-builtin.rs b/tests/ui/proc-macro/issue-118455-skip-err-builtin.rs new file mode 100644 index 0000000000000..baef020612891 --- /dev/null +++ b/tests/ui/proc-macro/issue-118455-skip-err-builtin.rs @@ -0,0 +1,6 @@ +#![some_nonexistent_attribute] +//~^ ERROR cannot find attribute `some_nonexistent_attribute` in this scope +#[derive(Debug)] +pub struct SomeUserCode; + +fn main() {} diff --git a/tests/ui/proc-macro/issue-118455-skip-err-builtin.stderr b/tests/ui/proc-macro/issue-118455-skip-err-builtin.stderr new file mode 100644 index 0000000000000..fa8af87a3d019 --- /dev/null +++ b/tests/ui/proc-macro/issue-118455-skip-err-builtin.stderr @@ -0,0 +1,8 @@ +error: cannot find attribute `some_nonexistent_attribute` in this scope + --> $DIR/issue-118455-skip-err-builtin.rs:1:4 + | +LL | #![some_nonexistent_attribute] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/issue-75734-pp-paren.stdout b/tests/ui/proc-macro/issue-75734-pp-paren.stdout index ee135366fb68b..9919ab5625fa1 100644 --- a/tests/ui/proc-macro/issue-75734-pp-paren.stdout +++ b/tests/ui/proc-macro/issue-75734-pp-paren.stdout @@ -1,5 +1,5 @@ PRINT-ATTR INPUT (DISPLAY): fn main() { &|_: u8| {}; mul_2!(1 + 1); } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn main() { &| _ : u8 | {} ; mul_2! (1 + 1) ; } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn main() { &| _ : u8 | {}; mul_2! (1 + 1); } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout index 093e37f8a8d0e..cc712abf2a576 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -51,22 +51,22 @@ struct Foo <#[cfg(FALSE)] A, B > { #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : bool, third : - [u8 ; + [u8; { - #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; - #[cfg(FALSE)] let a = 25 ; match true + #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(FALSE)] let a = 25; match true { #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} - } ; #[print_helper(should_be_removed)] fn removed_fn() + }; #[print_helper(should_be_removed)] fn removed_fn() { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() - { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { #! [cfg(not(FALSE))] let my_val = true; } enum TupleEnum { Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, #[cfg(FALSE)] String, u8) } struct TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn() + #[cfg(FALSE)] bool, u8); fn plain_removed_fn() { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 }], #[print_helper(d)] fourth : B } @@ -1336,14 +1336,14 @@ PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_hel PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_helper(b)] struct Foo { second : bool, third : - [u8 ; + [u8; { - #[cfg(not(FALSE))] struct Inner ; match true - { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)] + #[cfg(not(FALSE))] struct Inner; match true + { #[allow(warnings)] false => {}, _ => {} }; #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() - { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { #! [cfg(not(FALSE))] let my_val = true; } enum TupleEnum { Foo(#[cfg(not(FALSE))] i32, u8) } struct - TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 + TupleStruct(#[cfg(not(FALSE))] i32, u8); 0 }], #[print_helper(d)] fourth : B } PRINT-DERIVE INPUT (DEBUG): TokenStream [ diff --git a/tests/ui/proc-macro/issue-76182-leading-vert-pat.stdout b/tests/ui/proc-macro/issue-76182-leading-vert-pat.stdout index 09eb33f7e31a1..fdbf9118cd32f 100644 --- a/tests/ui/proc-macro/issue-76182-leading-vert-pat.stdout +++ b/tests/ui/proc-macro/issue-76182-leading-vert-pat.stdout @@ -1,4 +1,4 @@ -PRINT-ATTR INPUT (DISPLAY): fn main() { match() { | () => () } } +PRINT-ATTR INPUT (DISPLAY): fn main() { match () { | () => () } } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed new file mode 100644 index 0000000000000..a61c868ed0a1a --- /dev/null +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed @@ -0,0 +1,7 @@ +// run-rustfix + +#[derive(Debug)] //~ ERROR `derive` attribute cannot be used at crate level +#[allow(dead_code)] +struct Test {} + +fn main() {} diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs new file mode 100644 index 0000000000000..403f4470de77b --- /dev/null +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs @@ -0,0 +1,7 @@ +// run-rustfix + +#![derive(Debug)] //~ ERROR `derive` attribute cannot be used at crate level +#[allow(dead_code)] +struct Test {} + +fn main() {} diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr new file mode 100644 index 0000000000000..09908160542d4 --- /dev/null +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr @@ -0,0 +1,17 @@ +error: `derive` attribute cannot be used at crate level + --> $DIR/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs:3:1 + | +LL | #![derive(Debug)] + | ^^^^^^^^^^^^^^^^^ +LL | #[allow(dead_code)] +LL | struct Test {} + | ---- the inner attribute doesn't annotate this struct + | +help: perhaps you meant to use an outer attribute + | +LL - #![derive(Debug)] +LL + #[derive(Debug)] + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/keep-expr-tokens.stdout b/tests/ui/proc-macro/keep-expr-tokens.stdout index 8e4d4785e2ee9..fdd191261095c 100644 --- a/tests/ui/proc-macro/keep-expr-tokens.stdout +++ b/tests/ui/proc-macro/keep-expr-tokens.stdout @@ -1,5 +1,5 @@ PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] { 1 +1; } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[rustc_dummy] { 1 + 1 ; } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[rustc_dummy] { 1 + 1; } PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout index 89817a1efdc5b..257d59974b88d 100644 --- a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -1,7 +1,7 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo { val : - [bool ; + [bool; { let a = #[rustc_dummy(first)] #[rustc_dummy(second)] { #![allow(unused)] 30 }; 0 @@ -10,10 +10,10 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct Foo { val : - [bool ; + [bool; { let a = #[rustc_dummy(first)] #[rustc_dummy(second)] - { #! [allow(unused)] 30 } ; 0 + { #! [allow(unused)] 30 }; 0 }] } PRINT-DERIVE INPUT (DEBUG): TokenStream [ diff --git a/tests/ui/proc-macro/nested-derive-cfg.stdout b/tests/ui/proc-macro/nested-derive-cfg.stdout index c94808c3c0f8a..a3046e4ab85cb 100644 --- a/tests/ui/proc-macro/nested-derive-cfg.stdout +++ b/tests/ui/proc-macro/nested-derive-cfg.stdout @@ -1,7 +1,7 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo { my_array: [bool; { struct Inner { non_removed_inner_field: usize } 0 }] } PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct Foo -{ my_array : [bool ; { struct Inner { non_removed_inner_field : usize } 0 }] } +{ my_array : [bool; { struct Inner { non_removed_inner_field : usize } 0 }] } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index d3c2c46ac75cf..cf9addb8a947d 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -1,5 +1,4 @@ PRINT-BANG INPUT (DISPLAY): struct S; -PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): struct S ; PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/tests/ui/proc-macro/pretty-print-tts.stdout b/tests/ui/proc-macro/pretty-print-tts.stdout index fbe8640a01a5f..ce40431350706 100644 --- a/tests/ui/proc-macro/pretty-print-tts.stdout +++ b/tests/ui/proc-macro/pretty-print-tts.stdout @@ -1,5 +1,5 @@ PRINT-BANG INPUT (DISPLAY): { #![rustc_dummy] let a = "hello".len(); matches!(a, 5); } -PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): { #! [rustc_dummy] let a = "hello".len() ; matches! (a, 5) ; } +PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): { #! [rustc_dummy] let a = "hello".len(); matches! (a, 5); } PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: Brace, diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 96c1ffb2f7e32..3d9b7a940b7c8 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -8,7 +8,7 @@ error[E0277]: the trait bound `bool: Step` is not satisfied --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool` + | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool`, which is required by `std::ops::Range: IntoIterator` | = help: the following other types implement trait `Step`: char @@ -30,7 +30,7 @@ LL | let range = *arr..; | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[{integer}]` -note: required by a bound in `RangeFrom` +note: required by an implicit `Sized` bound in `RangeFrom` --> $SRC_DIR/core/src/ops/range.rs:LL:COL error: aborting due to 3 previous errors diff --git a/tests/ui/recursion/recursive-requirements.stderr b/tests/ui/recursion/recursive-requirements.stderr index bb63f7cd0dce0..f5cbed0ce3475 100644 --- a/tests/ui/recursion/recursive-requirements.stderr +++ b/tests/ui/recursion/recursive-requirements.stderr @@ -4,7 +4,7 @@ error[E0277]: `*const Bar` cannot be shared between threads safely LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Bar` cannot be shared between threads safely | - = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar`, which is required by `Foo: Sync` note: required because it appears within the type `Foo` --> $DIR/recursive-requirements.rs:5:12 | @@ -22,7 +22,7 @@ error[E0277]: `*const Foo` cannot be shared between threads safely LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Foo` cannot be shared between threads safely | - = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo`, which is required by `Foo: Sync` note: required because it appears within the type `Bar` --> $DIR/recursive-requirements.rs:10:12 | diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index 570d203d07f7c..4fc3ee68ebc29 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; | ^^^ - = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + | + = note: ...which immediately requires const-evaluating + checking `FOO` again note: cycle used when linting top-level module --> $DIR/recursive-static-definition.rs:1:1 | diff --git a/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index 2ec2ca49b1142..b15d2affeea37 100644 --- a/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -21,11 +21,11 @@ note: but lifetime parameter must outlive the lifetime `'a` as defined here LL | struct Foo<'a,'b,'c> { | ^^ -error[E0392]: parameter `'c` is never used +error[E0392]: lifetime parameter `'c` is never used --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:18 | LL | struct Foo<'a,'b,'c> { - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/regions/regions-no-variance-from-fn-generics.rs b/tests/ui/regions/regions-no-variance-from-fn-generics.rs index 76706a8278197..a455d4efd71b5 100644 --- a/tests/ui/regions/regions-no-variance-from-fn-generics.rs +++ b/tests/ui/regions/regions-no-variance-from-fn-generics.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Issue #12856: a lifetime formal binding introduced by a generic fn // should not upset the variance inference for actual occurrences of diff --git a/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr b/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr index 2e3ede46eca5d..1f7487e68be8a 100644 --- a/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr +++ b/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr @@ -5,6 +5,8 @@ LL | let _ = [ a; 5 ]; | ^ the trait `Copy` is not implemented for `Foo` | = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information help: consider annotating `Foo` with `#[derive(Copy)]` | LL + #[derive(Copy)] diff --git a/tests/ui/reserved/reserved-attr-on-macro.rs b/tests/ui/reserved/reserved-attr-on-macro.rs index 2630db0d09785..5c4657e0ec2e1 100644 --- a/tests/ui/reserved/reserved-attr-on-macro.rs +++ b/tests/ui/reserved/reserved-attr-on-macro.rs @@ -7,5 +7,5 @@ macro_rules! foo { } fn main() { - foo!(); //~ ERROR cannot determine resolution for the macro `foo` + foo!(); } diff --git a/tests/ui/reserved/reserved-attr-on-macro.stderr b/tests/ui/reserved/reserved-attr-on-macro.stderr index e55b58bef2855..066f72367b1a5 100644 --- a/tests/ui/reserved/reserved-attr-on-macro.stderr +++ b/tests/ui/reserved/reserved-attr-on-macro.stderr @@ -4,19 +4,11 @@ error: attributes starting with `rustc` are reserved for use by the `rustc` comp LL | #[rustc_attribute_should_be_reserved] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot determine resolution for the macro `foo` - --> $DIR/reserved-attr-on-macro.rs:10:5 - | -LL | foo!(); - | ^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: cannot find attribute `rustc_attribute_should_be_reserved` in this scope --> $DIR/reserved-attr-on-macro.rs:1:3 | LL | #[rustc_attribute_should_be_reserved] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-0.rs b/tests/ui/resolve/change-ty-to-const-param-sugg-0.rs new file mode 100644 index 0000000000000..36fe16f64ebeb --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-0.rs @@ -0,0 +1,10 @@ +fn make() {} +//~^ ERROR expected trait, found builtin type `u32` +//~| HELP you might have meant to write a const parameter here + +struct Array([bool; N]); +//~^ ERROR expected trait, found builtin type `usize` +//~| HELP you might have meant to write a const parameter here +//~| ERROR expected value, found type parameter `N` + +fn main() {} diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr b/tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr new file mode 100644 index 0000000000000..4e411eae3cbbb --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr @@ -0,0 +1,34 @@ +error[E0404]: expected trait, found builtin type `u32` + --> $DIR/change-ty-to-const-param-sugg-0.rs:1:12 + | +LL | fn make() {} + | ^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | fn make() {} + | +++++ + +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/change-ty-to-const-param-sugg-0.rs:5:17 + | +LL | struct Array([bool; N]); + | ^^^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | struct Array([bool; N]); + | +++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/change-ty-to-const-param-sugg-0.rs:5:31 + | +LL | struct Array([bool; N]); + | - ^ not a value + | | + | found this type parameter + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0404, E0423. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-1.rs b/tests/ui/resolve/change-ty-to-const-param-sugg-1.rs new file mode 100644 index 0000000000000..b1d2595f3790f --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-1.rs @@ -0,0 +1,24 @@ +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +struct Tagged; +//~^ ERROR expected trait, found enum `Tag` +//~| HELP you might have meant to write a const parameter here +//~| ERROR expected trait, found struct `Options` +//~| HELP you might have meant to write a const parameter here + +#[derive(PartialEq, Eq, ConstParamTy)] +enum Tag { + One, + Two, +} + +#[derive(PartialEq, Eq, ConstParamTy)] +struct Options { + verbose: bool, + safe: bool, +} + +fn main() {} diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr b/tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr new file mode 100644 index 0000000000000..933fac27f8f4e --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr @@ -0,0 +1,25 @@ +error[E0404]: expected trait, found enum `Tag` + --> $DIR/change-ty-to-const-param-sugg-1.rs:6:18 + | +LL | struct Tagged; + | ^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | struct Tagged; + | +++++ + +error[E0404]: expected trait, found struct `Options` + --> $DIR/change-ty-to-const-param-sugg-1.rs:6:26 + | +LL | struct Tagged; + | ^^^^^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | struct Tagged; + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0404`. diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr index 4f8538292792c..fbb9ede8aa175 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr @@ -5,6 +5,8 @@ LL | fn outer() { // outer function | - type parameter from outer item LL | const K: u32 = T::C; | ^^^^ use of generic parameter from outer item + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 @@ -14,6 +16,8 @@ LL | impl Tr for T { // outer impl block LL | const C: u32 = { LL | const I: u32 = T::C; | ^^^^ use of generic parameter from outer item + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 @@ -22,6 +26,8 @@ LL | struct S(U32<{ // outer struct | - type parameter from outer item LL | const _: u32 = T::C; | ^^^^ use of generic parameter from outer item + | + = note: a `const` is a separate item from the item that contains it error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr index 1cb55842bc665..60aa94038c3ad 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr @@ -7,6 +7,8 @@ LL | const K: u32 = T::C; | - ^^^^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 @@ -18,6 +20,8 @@ LL | const I: u32 = T::C; | - ^^^^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 @@ -28,6 +32,8 @@ LL | const _: u32 = T::C; | - ^^^^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` + | + = note: a `const` is a separate item from the item that contains it error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed index e730f94660bbd..a7ab88fe99357 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![deny(unused_qualifications)] #![feature(unsized_fn_params)] diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs index 641c892e3de9a..05936b191ffea 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![deny(unused_qualifications)] #![feature(unsized_fn_params)] diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr index d9c7fd21871ba..bcda721071235 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr @@ -1,11 +1,11 @@ error: unnecessary qualification - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:12:6 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:13:6 | LL | impl ops::Index for A { | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:3:9 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:4:9 | LL | #![deny(unused_qualifications)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL + impl Index for A { | error: unnecessary qualification - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:28:6 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:29:6 | LL | impl inner::Trait for () {} | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs index de3e73437f080..e5dcf9643453b 100644 --- a/tests/ui/resolve/issue-12796.rs +++ b/tests/ui/resolve/issue-12796.rs @@ -1,7 +1,7 @@ trait Trait { fn outer(&self) { fn inner(_: &Self) { - //~^ ERROR can't use generic parameters from outer item + //~^ ERROR can't use `Self` from outer item } } } diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr index 6809fd50f7475..2305971303a71 100644 --- a/tests/ui/resolve/issue-12796.stderr +++ b/tests/ui/resolve/issue-12796.stderr @@ -1,10 +1,10 @@ -error[E0401]: can't use generic parameters from outer item +error[E0401]: can't use `Self` from outer item --> $DIR/issue-12796.rs:3:22 | LL | fn inner(_: &Self) { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | can't use `Self` here error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr index 363bb55647827..ca32147d19765 100644 --- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr +++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr @@ -6,6 +6,8 @@ LL | unsafe fn foo() { LL | extern "C" { LL | static baz: *const A; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr index f1fe1a6002c93..98ffb4567f164 100644 --- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr +++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr @@ -6,6 +6,8 @@ LL | fn f() { LL | extern "C" { LL | static a: *const T; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:9:22 @@ -14,6 +16,8 @@ LL | fn g() { | - type parameter from outer item LL | static a: *const T = Default::default(); | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:15:24 @@ -23,6 +27,8 @@ LL | fn h() { LL | extern "C" { LL | static a: [u8; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:21:20 @@ -31,6 +37,8 @@ LL | fn i() { | - const parameter from outer item LL | static a: [u8; N] = [0; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:21:29 @@ -39,6 +47,8 @@ LL | fn i() { | - const parameter from outer item LL | static a: [u8; N] = [0; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error: aborting due to 5 previous errors diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs index f4dfa4c40ab24..62f9dc5664ffe 100644 --- a/tests/ui/resolve/use-self-in-inner-fn.rs +++ b/tests/ui/resolve/use-self-in-inner-fn.rs @@ -4,8 +4,8 @@ impl A { //~^ NOTE `Self` type implicitly declared here, by this `impl` fn banana(&mut self) { fn peach(this: &Self) { - //~^ ERROR can't use generic parameters from outer item - //~| NOTE use of generic parameter from outer item + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item //~| NOTE refer to the type directly here instead } } diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr index 165e100bf2f5c..9c388df8bc20c 100644 --- a/tests/ui/resolve/use-self-in-inner-fn.stderr +++ b/tests/ui/resolve/use-self-in-inner-fn.stderr @@ -1,4 +1,4 @@ -error[E0401]: can't use generic parameters from outer item +error[E0401]: can't use `Self` from outer item --> $DIR/use-self-in-inner-fn.rs:6:25 | LL | impl A { @@ -7,7 +7,7 @@ LL | impl A { LL | fn peach(this: &Self) { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | refer to the type directly here instead error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs new file mode 100644 index 0000000000000..9150c831c8960 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs @@ -0,0 +1,16 @@ +// edition: 2018 +// known-bug: #120240 +#![feature(never_patterns)] +#![allow(incomplete_features)] + +fn main() {} + +enum Void {} + +// Divergence is not detected. +async fn async_never(!: Void) -> ! {} // gives an error + +// Divergence is detected +async fn async_let(x: Void) -> ! { + let ! = x; +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr new file mode 100644 index 0000000000000..fa71feee5f5aa --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/120240-async-fn-never-arg.rs:11:36 + | +LL | async fn async_never(!: Void) -> ! {} // gives an error + | ^^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs new file mode 100644 index 0000000000000..f7e4007b920d9 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs @@ -0,0 +1,36 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] +#![deny(unreachable_code)] + +fn main() {} + +enum Void {} + +fn never_arg(!: Void) -> u32 { + println!(); + //~^ ERROR unreachable statement +} + +fn ref_never_arg(&!: &Void) -> u32 { + println!(); + //~^ ERROR unreachable statement +} + +fn never_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + let ! = *ptr; + } + println!(); + //~^ ERROR unreachable statement +} + +fn never_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { ! }; + } + println!(); + //~^ ERROR unreachable statement +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr new file mode 100644 index 0000000000000..c33a5855d5068 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr @@ -0,0 +1,49 @@ +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:11:5 + | +LL | fn never_arg(!: Void) -> u32 { + | - any code following a never pattern is unreachable +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/diverge-causes-unreachable-code.rs:4:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:16:5 + | +LL | fn ref_never_arg(&!: &Void) -> u32 { + | -- any code following a never pattern is unreachable +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:25:5 + | +LL | let ! = *ptr; + | - any code following a never pattern is unreachable +LL | } +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:34:5 + | +LL | match *ptr { ! }; + | ---------------- any code following this `match` expression is unreachable, as all arms diverge +LL | } +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs new file mode 100644 index 0000000000000..6b85ada3aadee --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs @@ -0,0 +1,56 @@ +#![feature(never_patterns)] +#![feature(let_chains)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() {} + +enum Void {} + +// Contrast with `./diverges.rs`: merely having an empty type around isn't enough to diverge. + +fn wild_void(_: Void) -> u32 {} +//~^ ERROR: mismatched types + +fn wild_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + //~^ ERROR: mismatched types + let _ = *ptr; + } +} + +fn wild_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { + _ => {} //~ ERROR: mismatched types + } + } +} + +fn binding_void(_x: Void) -> u32 {} +//~^ ERROR: mismatched types + +fn binding_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + //~^ ERROR: mismatched types + let _x = *ptr; + } +} + +fn binding_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { + _x => {} //~ ERROR: mismatched types + } + } +} + +// Don't confuse this with a `let !` statement. +fn let_chain(x: Void) -> u32 { + if let true = true && let ! = x {} + //~^ ERROR: mismatched types +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr new file mode 100644 index 0000000000000..08a1bbe9bffac --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:12:26 + | +LL | fn wild_void(_: Void) -> u32 {} + | --------- ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:17:5 + | +LL | / unsafe { +LL | | +LL | | let _ = *ptr; +LL | | } + | |_____^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:27:18 + | +LL | _ => {} + | ^^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:32:30 + | +LL | fn binding_void(_x: Void) -> u32 {} + | ------------ ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:37:5 + | +LL | / unsafe { +LL | | +LL | | let _x = *ptr; +LL | | } + | |_____^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:47:19 + | +LL | _x => {} + | ^^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:54:37 + | +LL | if let true = true && let ! = x {} + | ^^ expected `u32`, found `()` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs new file mode 100644 index 0000000000000..3783100b50282 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs @@ -0,0 +1,38 @@ +// check-pass +// edition: 2018 +#![feature(never_patterns)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() {} + +enum Void {} + +// A never pattern alone diverges. + +fn never_arg(!: Void) -> ! {} + +fn never_arg_returns_anything(!: Void) -> T {} + +fn ref_never_arg(&!: &Void) -> ! {} + +fn never_let() -> ! { + let ptr: *const Void = std::ptr::null(); + unsafe { + let ! = *ptr; + } +} + +fn never_match() -> ! { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { ! }; + } + // Ensures this typechecks because of divergence and not the type of the match expression. + println!(); +} + +// Note: divergence is not detected for async fns when the `!` is in the argument (#120240). +async fn async_let(x: Void) -> ! { + let ! = x; +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr new file mode 100644 index 0000000000000..013a8b53a5509 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr @@ -0,0 +1,66 @@ +error: mismatched types + --> $DIR/typeck.rs:25:9 + | +LL | !, + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `()` + +error: mismatched types + --> $DIR/typeck.rs:29:9 + | +LL | !, + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `(i32, bool)` + +error: mismatched types + --> $DIR/typeck.rs:33:13 + | +LL | (_, !), + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `bool` + +error: mismatched types + --> $DIR/typeck.rs:38:14 + | +LL | Some(!), + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `i32` + +error: mismatched types + --> $DIR/typeck.rs:45:9 + | +LL | !, + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `()` + +error: mismatched types + --> $DIR/typeck.rs:52:9 + | +LL | !, + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `Option` + +error: mismatched types + --> $DIR/typeck.rs:57:9 + | +LL | !, + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `[Void]` + +error: mismatched types + --> $DIR/typeck.rs:63:9 + | +LL | !, + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `Option<&Void>` + +error: aborting due to 8 previous errors + diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs new file mode 100644 index 0000000000000..31a23fa002c30 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs @@ -0,0 +1,125 @@ +// revisions: pass fail +//[pass] check-pass +//[fail] check-fail +#![feature(never_patterns)] +#![feature(exhaustive_patterns)] +#![allow(incomplete_features)] + +#[derive(Copy, Clone)] +enum Void {} + +fn main() {} + +// The classic use for empty types. +fn safe_unwrap_result(res: Result) { + let Ok(_x) = res; + let (Ok(_x) | Err(!)) = &res; + let (Ok(_x) | Err(!)) = res.as_ref(); +} + +// Check we only accept `!` where we want to. +#[cfg(fail)] +fn never_pattern_typeck_fail(void: Void) { + // Don't accept on a non-empty type. + match () { + !, + //[fail]~^ ERROR: mismatched types + } + match (0, false) { + !, + //[fail]~^ ERROR: mismatched types + } + match (0, false) { + (_, !), + //[fail]~^ ERROR: mismatched types + } + match Some(0) { + None => {} + Some(!), + //[fail]~^ ERROR: mismatched types + } + + // Don't accept on an arbitrary type, even if there are no more branches. + match () { + () => {} + !, + //[fail]~^ ERROR: mismatched types + } + + // Don't accept even on an empty branch. + match None:: { + None => {} + !, + //[fail]~^ ERROR: mismatched types + } + match (&[] as &[Void]) { + [] => {} + !, + //[fail]~^ ERROR: mismatched types + } + // Let alone if the emptiness is behind a reference. + match None::<&Void> { + None => {} + !, + //[fail]~^ ERROR: mismatched types + } +} + +#[cfg(pass)] +fn never_pattern_typeck_pass(void: Void) { + // Participate in match ergonomics. + match &void { + !, + } + match &&void { + !, + } + match &&void { + &!, + } + match &None:: { + None => {} + Some(!), + } + match None::<&Void> { + None => {} + Some(!), + } + + // Accept on a directly empty type. + match void { + !, + } + match &void { + &!, + } + match None:: { + None => {} + Some(!), + } + match None::<&Void> { + None => {} + Some(&!), + } + match None::<&(u32, Void)> { + None => {} + Some(&(_, !)), + } + match (&[] as &[Void]) { + [] => {} + [!], + } + // Accept on a composite empty type. + match None::<&(u32, Void)> { + None => {} + Some(&!), + } + match None::<&(u32, Void)> { + None => {} + Some(!), + } + match None::<&Result> { + None => {} + Some(!), + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr new file mode 100644 index 0000000000000..fe2a72d2a3180 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr @@ -0,0 +1,44 @@ +error: unreachable pattern + --> $DIR/unreachable.rs:17:9 + | +LL | Err(!), + | ^^^^^^ + | +note: the lint level is defined here + --> $DIR/unreachable.rs:7:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable.rs:20:19 + | +LL | let (Ok(_x) | Err(!)) = res_void; + | ^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable.rs:22:12 + | +LL | if let Err(!) = res_void {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable.rs:24:24 + | +LL | if let (Ok(true) | Err(!)) = res_void {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable.rs:26:23 + | +LL | for (Ok(mut _x) | Err(!)) in [res_void] {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable.rs:30:18 + | +LL | fn foo((Ok(_x) | Err(!)): Result) {} + | ^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs new file mode 100644 index 0000000000000..df8e22abf6232 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs @@ -0,0 +1,31 @@ +// revisions: normal exh_pats +//[normal] check-pass +#![feature(never_patterns)] +#![allow(incomplete_features)] +#![cfg_attr(exh_pats, feature(exhaustive_patterns))] +#![allow(dead_code, unreachable_code)] +#![deny(unreachable_patterns)] + +#[derive(Copy, Clone)] +enum Void {} + +fn main() { + let res_void: Result = Ok(true); + + match res_void { + Ok(_x) => {} + Err(!), + //[exh_pats]~^ ERROR unreachable + } + let (Ok(_x) | Err(!)) = res_void; + //[exh_pats]~^ ERROR unreachable + if let Err(!) = res_void {} + //[exh_pats]~^ ERROR unreachable + if let (Ok(true) | Err(!)) = res_void {} + //[exh_pats]~^ ERROR unreachable + for (Ok(mut _x) | Err(!)) in [res_void] {} + //[exh_pats]~^ ERROR unreachable +} + +fn foo((Ok(_x) | Err(!)): Result) {} +//[exh_pats]~^ ERROR unreachable diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs index bb5e243d93433..65a85a5ed68f6 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs @@ -20,7 +20,7 @@ const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0)); fn main() { match WRAP_DIRECT_INLINE { WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr index 334bd7618ad84..cc5d4106331d2 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 | LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs index 93022a23dbfb8..112021c783fc6 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs @@ -20,7 +20,7 @@ const WRAP_DIRECT_PARAM: WrapParam = WrapParam(NoDerive(0)); fn main() { match WRAP_DIRECT_PARAM { WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr index 58bfcbb451d70..8bca7d9889cd5 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 | LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs index e3abb47cf7338..7a853631d43b5 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs @@ -22,7 +22,7 @@ const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0) fn main() { match WRAP_DOUBLY_INDIRECT_INLINE { WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr index 94ee2216e9e65..9945041113d79 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr @@ -1,13 +1,13 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 | LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 | @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs index 2d3788eea8a89..3093f227e6f78 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs @@ -22,7 +22,7 @@ const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam = & &WrapParam(& & NoDe fn main() { match WRAP_DOUBLY_INDIRECT_PARAM { WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr index 666b7b95ec97f..6ac261ae81437 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr @@ -1,13 +1,13 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 | LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 | @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs index 65df7788d907e..2b6ec850241c8 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs @@ -22,7 +22,7 @@ const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0)); fn main() { match WRAP_INDIRECT_INLINE { WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr index ecbe83f3dec0e..41616fb90fe96 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr @@ -1,13 +1,13 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9 | LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9 | @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9 + | +LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs index 88260fd10814d..5738d14d97bdf 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs @@ -22,7 +22,7 @@ const WRAP_INDIRECT_PARAM: & &WrapParam = & &WrapParam(NoDerive(0)); fn main() { match WRAP_INDIRECT_PARAM { WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr index 2119908013b79..99dea5171d1bc 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr @@ -1,13 +1,13 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9 | LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9 | @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9 + | +LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr index f047afa985d5f..af6d05c1f96ff 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr @@ -8,16 +8,6 @@ LL | impl std::marker::StructuralPartialEq for Foo { } = help: add `#![feature(structural_match)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: use of unstable library feature 'structural_match' - --> $DIR/feature-gate.rs:31:6 - | -LL | impl std::marker::StructuralEq for Foo { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #31434 for more information - = help: add `#![feature(structural_match)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs index ee6674097ce2d..024226a011678 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs @@ -28,8 +28,6 @@ fn main() { //[with_gate]~ ERROR fatal error triggered by #[rustc_error] impl std::marker::StructuralPartialEq for Foo { } //[no_gate]~^ ERROR use of unstable library feature 'structural_match' -impl std::marker::StructuralEq for Foo { } -//[no_gate]~^ ERROR use of unstable library feature 'structural_match' impl PartialEq for Foo { fn eq(&self, other: &Self) -> bool { diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr index 080bf5885ba75..11163ba70ec65 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr @@ -5,7 +5,7 @@ LL | Wrap(CFN1) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. @@ -15,7 +15,7 @@ LL | Wrap(CFN2) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14 @@ -24,7 +24,7 @@ LL | Wrap(CFN3) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14 @@ -33,7 +33,7 @@ LL | Wrap(CFN4) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14 @@ -42,7 +42,7 @@ LL | Wrap(CFN5) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14 @@ -51,7 +51,7 @@ LL | Wrap(CFN6) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14 @@ -60,7 +60,7 @@ LL | Wrap(CFN7) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14 @@ -69,7 +69,7 @@ LL | Wrap(CFN8) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14 @@ -78,7 +78,7 @@ LL | Wrap(CFN9) => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9 @@ -87,7 +87,117 @@ LL | CFOO => count += 1, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: 10 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:43:14 + | +LL | Wrap(CFN1) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:52:14 + | +LL | Wrap(CFN2) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14 + | +LL | Wrap(CFN3) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14 + | +LL | Wrap(CFN4) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14 + | +LL | Wrap(CFN5) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14 + | +LL | Wrap(CFN6) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14 + | +LL | Wrap(CFN7) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14 + | +LL | Wrap(CFN8) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14 + | +LL | Wrap(CFN9) => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9 + | +LL | CFOO => count += 1, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs index 2a915d61e3d90..c69fe145f77ba 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs @@ -13,7 +13,7 @@ const A: &[B] = &[]; pub fn main() { match &[][..] { A => (), - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` _ => (), } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr index 729e747def310..02e2bab4d0a29 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9 | LL | A => (), | ^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs index 46d8ee3b6be9c..374e5d5acd080 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -10,7 +10,7 @@ // Issue 62307 pointed out a case where the structural-match checking // was too shallow. -#![warn(indirect_structural_match, nontrivial_structural_match)] +#![warn(indirect_structural_match)] // run-pass #[derive(Debug)] @@ -29,14 +29,14 @@ fn main() { match RR_B0 { RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| WARN this was previously accepted _ => { } } match RR_B1 { RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~^ WARN must be annotated with `#[derive(PartialEq)]` //~| WARN this was previously accepted _ => { } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr index 435812306deee..d4ab1ce3ba2ad 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -1,29 +1,63 @@ -warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 | LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } | ^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 | -LL | #![warn(indirect_structural_match, nontrivial_structural_match)] +LL | #![warn(indirect_structural_match)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 | LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } | ^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 + | +LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 + | +LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr index 4fdfce60bb861..0edcf44c4d795 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr @@ -5,7 +5,7 @@ LL | B(TEST) => println!("matched"), | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-63479-match-fnptr.rs:8:9 | @@ -19,7 +19,37 @@ LL | TEST2 => println!("matched"), | ^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:36:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:42:5 + | +LL | TEST2 => println!("matched"), + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs new file mode 100644 index 0000000000000..d43db576b3848 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs @@ -0,0 +1,41 @@ +// Matching against NaN should result in an error +#![feature(exclusive_range_pattern)] +#![allow(unused)] + +const NAN: f64 = f64::NAN; + +#[derive(PartialEq, Eq)] +struct MyType(T); + +const C: MyType = MyType(f32::NAN); + +fn main() { + let x = NAN; + match x { + NAN => {}, //~ ERROR cannot use NaN in patterns + _ => {}, + }; + + match [x, 1.0] { + [NAN, _] => {}, //~ ERROR cannot use NaN in patterns + _ => {}, + }; + + match MyType(1.0f32) { + C => {}, //~ ERROR cannot use NaN in patterns + _ => {}, + } + + // Also cover range patterns + match x { + NAN..=1.0 => {}, //~ ERROR cannot use NaN in patterns + //~^ ERROR lower range bound must be less than or equal to upper + -1.0..=NAN => {}, //~ ERROR cannot use NaN in patterns + //~^ ERROR lower range bound must be less than or equal to upper + NAN.. => {}, //~ ERROR cannot use NaN in patterns + //~^ ERROR lower range bound must be less than or equal to upper + ..NAN => {}, //~ ERROR cannot use NaN in patterns + //~^ ERROR lower range bound must be less than upper + _ => {}, + }; +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr new file mode 100644 index 0000000000000..167ada783c24c --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr @@ -0,0 +1,91 @@ +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:15:9 + | +LL | NAN => {}, + | ^^^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:20:10 + | +LL | [NAN, _] => {}, + | ^^^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:25:9 + | +LL | C => {}, + | ^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:31:9 + | +LL | NAN..=1.0 => {}, + | ^^^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/issue-6804-nan-match.rs:31:9 + | +LL | NAN..=1.0 => {}, + | ^^^^^^^^^ lower bound larger than upper bound + +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:33:16 + | +LL | -1.0..=NAN => {}, + | ^^^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/issue-6804-nan-match.rs:33:9 + | +LL | -1.0..=NAN => {}, + | ^^^^^^^^^^ lower bound larger than upper bound + +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:35:9 + | +LL | NAN.. => {}, + | ^^^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/issue-6804-nan-match.rs:35:9 + | +LL | NAN.. => {}, + | ^^^^^ lower bound larger than upper bound + +error: cannot use NaN in patterns + --> $DIR/issue-6804-nan-match.rs:37:11 + | +LL | ..NAN => {}, + | ^^^ + | + = note: NaNs compare inequal to everything, even themselves, so this pattern would never match + = help: try using the `is_nan` method instead + +error[E0579]: lower range bound must be less than upper + --> $DIR/issue-6804-nan-match.rs:37:9 + | +LL | ..NAN => {}, + | ^^^^^ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0030, E0579. +For more information about an error, try `rustc --explain E0030`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs deleted file mode 100644 index 0260caa82cb1d..0000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Matching against NaN should result in a warning - -#![allow(unused)] -#![deny(illegal_floating_point_literal_pattern)] - -const NAN: f64 = f64::NAN; - -fn main() { - let x = NAN; - match x { - NAN => {}, //~ ERROR floating-point types cannot be used - //~| WARN this was previously accepted by the compiler but is being phased out - _ => {}, - }; - - match [x, 1.0] { - [NAN, _] => {}, //~ ERROR floating-point types cannot be used - //~| WARN this was previously accepted by the compiler but is being phased out - _ => {}, - }; -} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr deleted file mode 100644 index f37255d0828cd..0000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: floating-point types cannot be used in patterns - --> $DIR/issue-6804.rs:11:9 - | -LL | NAN => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 -note: the lint level is defined here - --> $DIR/issue-6804.rs:4:9 - | -LL | #![deny(illegal_floating_point_literal_pattern)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: floating-point types cannot be used in patterns - --> $DIR/issue-6804.rs:17:10 - | -LL | [NAN, _] => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: aborting due to 2 previous errors - diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs deleted file mode 100644 index 59a22c33778c5..0000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs +++ /dev/null @@ -1,23 +0,0 @@ -#[derive(PartialEq)] -struct Foo { - x: u32 -} - -const FOO: Foo = Foo { x: 0 }; - -fn main() { - let y = Foo { x: 1 }; - match y { - FOO => { } - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - _ => { } - } - - let x = 0.0; - match x { - f32::INFINITY => { } - //~^ WARNING floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler but is being phased out - _ => { } - } -} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr deleted file mode 100644 index c2000df88f6d0..0000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-forbidden-without-eq.rs:11:9 - | -LL | FOO => { } - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - -warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:18:9 - | -LL | f32::INFINITY => { } - | ^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs deleted file mode 100644 index 151a475c91906..0000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Issue 62307 pointed out a case where the structural-match checking -// was too shallow. -// -// Here we check similar behavior for non-empty arrays of types that -// do not derive `Eq`. -// -// (Current behavior for empty arrays differs and thus is not tested -// here; see rust-lang/rust#62336.) - -#[derive(PartialEq, Debug)] -struct B(i32); - -fn main() { - const FOO: [B; 1] = [B(0)]; - match [B(1)] { - FOO => { } - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - } -} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr deleted file mode 100644 index 477789f33df16..0000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 - | -LL | FOO => { } - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - -error: aborting due to 1 previous error - diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs index a8deb8a7550bc..9020eb291f5c5 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs @@ -15,7 +15,7 @@ fn main() { let y = Foo { x: 1 }; match y { FOO => { } - //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~^ ERROR must be annotated with `#[derive(PartialEq)]` _ => { } } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr index b806046db1422..efd9c8c45afa9 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr @@ -1,11 +1,11 @@ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]` --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 | LL | FOO => { } | ^^^ | = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index 0a703367d969d..4d23922892ea9 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `f32: Termination` is not satisfied LL | #[test] | ------- in this procedural macro expansion LL | fn can_parse_zero_as_f32() -> Result { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32`, which is required by `Result: Termination` | = note: required for `Result` to implement `Termination` note: required by a bound in `assert_test_result` diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr new file mode 100644 index 0000000000000..4a219ff8b5562 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr @@ -0,0 +1,15 @@ +warning: methods `good_virt` and `good_indirect` are never used + --> $DIR/manual-self-impl-for-unsafe-obj.rs:22:8 + | +LL | trait Good { + | ---- methods in this trait +LL | fn good_virt(&self) -> char { + | ^^^^^^^^^ +... +LL | fn good_indirect(&self) -> char { + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr new file mode 100644 index 0000000000000..4a219ff8b5562 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr @@ -0,0 +1,15 @@ +warning: methods `good_virt` and `good_indirect` are never used + --> $DIR/manual-self-impl-for-unsafe-obj.rs:22:8 + | +LL | trait Good { + | ---- methods in this trait +LL | fn good_virt(&self) -> char { + | ^^^^^^^^^ +... +LL | fn good_indirect(&self) -> char { + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs index c7665affb992b..c8eee9835fed3 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -19,7 +19,7 @@ trait Bad { } trait Good { - fn good_virt(&self) -> char { + fn good_virt(&self) -> char { //~ WARN methods `good_virt` and `good_indirect` are never used panic!() } fn good_indirect(&self) -> char { diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 7ec018a95cc72..eb6abbf80451c 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -4,7 +4,7 @@ error[E0277]: `NotDebug` doesn't implement `Debug` LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `NotDebug` + = help: the trait `Debug` is not implemented for `NotDebug`, which is required by `&NotDebug: Debug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index e17859eb40f27..d9d7e297f8e97 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -97,6 +97,7 @@ error: call to function `sse2` with `#[target_feature]` is unsafe and requires u LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | + = note: for more information, see issue #71668 = help: in order for the call to be safe, the context requires the following additional target feature: sse2 = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` note: an unsafe function restricts its caller, but its body is safe by default diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr index 6af1d4533b7c2..99d318a793364 100644 --- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/feature-gate-do_not_recommend.rs:19:11 | LL | stuff(1u8); - | ----- ^^^ the trait `Foo` is not implemented for `u8` + | ----- ^^^ the trait `Foo` is not implemented for `u8`, which is required by `u8: Bar` | | | required by a bound introduced by this call | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 84d9bcd7ac9f0..d6a82ca3a08b0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -507,9 +507,6 @@ trait Clone: Sized { #[lang = "structural_peq"] trait StructuralPartialEq {} -#[lang = "structural_teq"] -trait StructuralEq {} - const fn drop(_: T) {} extern "rust-intrinsic" { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr index e5b9493b3ce11..5210a6942010d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -7,16 +7,6 @@ LL | impl A for T { LL | impl const A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error[E0308]: mismatched types - --> $DIR/specializing-constness-2.rs:27:5 - | -LL | ::a(); - | ^^^^^^^^^^^^^ expected `host`, found `true` - | - = note: expected constant `host` - found constant `true` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0308. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr index d57f5702a6382..92a9c347a075e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr @@ -272,11 +272,11 @@ LL | type Type = (); = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/tilde-const-invalid-places.rs:11:19 | LL | struct UnitStruct; - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/rust-2018/issue-51008-1.rs b/tests/ui/rust-2018/issue-51008-1.rs index da7b8ef65c566..67dfbf6460133 100644 --- a/tests/ui/rust-2018/issue-51008-1.rs +++ b/tests/ui/rust-2018/issue-51008-1.rs @@ -2,7 +2,7 @@ // being incorrectly considered part of the "elided lifetimes" from // the impl. // -// run-pass +// check-pass trait A { diff --git a/tests/ui/rust-2018/issue-51008.rs b/tests/ui/rust-2018/issue-51008.rs index 56517b9adee65..f9e4bc14ec82c 100644 --- a/tests/ui/rust-2018/issue-51008.rs +++ b/tests/ui/rust-2018/issue-51008.rs @@ -2,7 +2,7 @@ // being incorrectly considered part of the "elided lifetimes" from // the impl. // -// run-pass +// check-pass trait A { diff --git a/tests/ui/rust-2018/issue-54006.rs b/tests/ui/rust-2018/issue-54006.rs index a7a4770fc02f9..6f929731c7674 100644 --- a/tests/ui/rust-2018/issue-54006.rs +++ b/tests/ui/rust-2018/issue-54006.rs @@ -8,6 +8,5 @@ use alloc::vec; pub fn foo() { let mut xs = vec![]; - //~^ ERROR cannot determine resolution for the macro `vec` xs.push(0); } diff --git a/tests/ui/rust-2018/issue-54006.stderr b/tests/ui/rust-2018/issue-54006.stderr index 1978138a68878..35d4c17d2c7f1 100644 --- a/tests/ui/rust-2018/issue-54006.stderr +++ b/tests/ui/rust-2018/issue-54006.stderr @@ -4,14 +4,6 @@ error[E0432]: unresolved import `alloc` LL | use alloc::vec; | ^^^^^ help: a similar path exists: `core::alloc` -error: cannot determine resolution for the macro `vec` - --> $DIR/issue-54006.rs:10:18 - | -LL | let mut xs = vec![]; - | ^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr index fed853a7e1fd8..4909a9cdc7f5c 100644 --- a/tests/ui/self/self_type_keyword.stderr +++ b/tests/ui/self/self_type_keyword.stderr @@ -72,11 +72,11 @@ note: unit struct `foo::Self` exists but is inaccessible LL | struct Self; | ^^^^^^^^^^^^ not accessible -error[E0392]: parameter `'Self` is never used +error[E0392]: lifetime parameter `'Self` is never used --> $DIR/self_type_keyword.rs:6:12 | LL | struct Bar<'Self>; - | ^^^^^ unused parameter + | ^^^^^ unused lifetime parameter | = help: consider removing `'Self`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/single-use-lifetime/issue-117965.rs b/tests/ui/single-use-lifetime/issue-117965.rs new file mode 100644 index 0000000000000..5eb2a03e13da4 --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-117965.rs @@ -0,0 +1,18 @@ +#![deny(single_use_lifetimes)] + +pub enum Data<'a> { + Borrowed(&'a str), + Owned(String), +} + +impl<'a> Data<'a> { + pub fn get<'b: 'a>(&'b self) -> &'a str { + //~^ ERROR lifetime parameter `'b` only used once + match &self { + Self::Borrowed(val) => val, + Self::Owned(val) => &val, + } + } +} + +fn main() {} diff --git a/tests/ui/single-use-lifetime/issue-117965.stderr b/tests/ui/single-use-lifetime/issue-117965.stderr new file mode 100644 index 0000000000000..ed14ab92f4d16 --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-117965.stderr @@ -0,0 +1,16 @@ +error: lifetime parameter `'b` only used once + --> $DIR/issue-117965.rs:9:16 + | +LL | pub fn get<'b: 'a>(&'b self) -> &'a str { + | ^^ -- ...is used only here + | | + | this lifetime... + | +note: the lint level is defined here + --> $DIR/issue-117965.rs:1:9 + | +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/sized/coinductive-2.rs b/tests/ui/sized/coinductive-2.rs index 212274d2e4b6c..43a5a28f710a7 100644 --- a/tests/ui/sized/coinductive-2.rs +++ b/tests/ui/sized/coinductive-2.rs @@ -11,7 +11,7 @@ impl CollectionFactory for Vec<()> { type Collection = Vec; } -trait Collection: Sized { +trait Collection: Sized { //~ WARN trait `Collection` is never used fn push(&mut self, v: T); } diff --git a/tests/ui/sized/coinductive-2.stderr b/tests/ui/sized/coinductive-2.stderr new file mode 100644 index 0000000000000..1390b1f8d7bf1 --- /dev/null +++ b/tests/ui/sized/coinductive-2.stderr @@ -0,0 +1,10 @@ +warning: trait `Collection` is never used + --> $DIR/coinductive-2.rs:14:7 + | +LL | trait Collection: Sized { + | ^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs index a9d678c1e6aff..66a432be35737 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs @@ -9,7 +9,7 @@ impl Numberer { //~^ ERROR `async fn` is not permitted in Rust 2015 interval: Duration, //~^ ERROR cannot find type `Duration` in this scope - ) -> Numberer { //~WARN: changes to closure capture in Rust 2021 + ) -> Numberer { Numberer {} } } diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 71e9e7602e8e7..60433e1c28467 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -18,32 +18,7 @@ help: consider importing this struct LL + use std::time::Duration; | -warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19 - | -LL | interval: Duration, - | -------- in Rust 2018, this causes the closure to capture `interval`, but in Rust 2021, it has no effect -LL | -LL | ) -> Numberer { - | _________________-_^ - | | | - | | in Rust 2018, `interval` is dropped here along with the closure, but in Rust 2021 `interval` is not part of the closure -LL | | Numberer {} -LL | | } - | |_____^ - | - = note: for more information, see -note: the lint level is defined here - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:1:9 - | -LL | #![warn(rust_2021_incompatible_closure_captures)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: add a dummy let to cause `interval` to be fully captured - | -LL | ) -> Numberer { let _ = &interval; - | ++++++++++++++++++ - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0412, E0670. For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/span/issue-43927-non-ADT-derive.rs b/tests/ui/span/issue-43927-non-ADT-derive.rs index 935bfa001bfc6..e50ee36d7de95 100644 --- a/tests/ui/span/issue-43927-non-ADT-derive.rs +++ b/tests/ui/span/issue-43927-non-ADT-derive.rs @@ -1,6 +1,5 @@ #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! -//~^ ERROR cannot determine resolution for the attribute macro `derive` -//~^^ ERROR `derive` attribute cannot be used at crate level +//~^ ERROR `derive` attribute cannot be used at crate level struct DerivedOn; fn main() {} diff --git a/tests/ui/span/issue-43927-non-ADT-derive.stderr b/tests/ui/span/issue-43927-non-ADT-derive.stderr index a22a4d2b40a8e..27ed561f5be8a 100644 --- a/tests/ui/span/issue-43927-non-ADT-derive.stderr +++ b/tests/ui/span/issue-43927-non-ADT-derive.stderr @@ -1,17 +1,9 @@ -error: cannot determine resolution for the attribute macro `derive` - --> $DIR/issue-43927-non-ADT-derive.rs:1:4 - | -LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! - | ^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - error: `derive` attribute cannot be used at crate level --> $DIR/issue-43927-non-ADT-derive.rs:1:1 | LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | struct DerivedOn; | --------- the inner attribute doesn't annotate this struct | @@ -21,5 +13,5 @@ LL - #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! LL + #[derive(Debug, PartialEq, Eq)] // should be an outer attribute! | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/specialization/assoc-ty-graph-cycle.rs b/tests/ui/specialization/assoc-ty-graph-cycle.rs index fc39b553a61ac..bec8cc187b4ab 100644 --- a/tests/ui/specialization/assoc-ty-graph-cycle.rs +++ b/tests/ui/specialization/assoc-ty-graph-cycle.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Make sure we don't crash with a cycle error during coherence. diff --git a/tests/ui/specialization/ctfe/default-assoc-const.rs b/tests/ui/specialization/ctfe/default-assoc-const.rs new file mode 100644 index 0000000000000..bb3b735caa312 --- /dev/null +++ b/tests/ui/specialization/ctfe/default-assoc-const.rs @@ -0,0 +1,18 @@ +//! Regression test for revealing associated types through specialization during const eval. +// check-pass +#![feature(specialization)] +//~^ WARNING the feature `specialization` is incomplete and may not be safe to use + +trait Foo { + const ASSOC: usize; +} + +impl Foo for u32 { + default const ASSOC: usize = 0; +} + +fn foo() -> [u8; 0] { + [0; ::ASSOC] +} + +fn main() {} diff --git a/tests/ui/specialization/ctfe/default-assoc-const.stderr b/tests/ui/specialization/ctfe/default-assoc-const.stderr new file mode 100644 index 0000000000000..933b6dcf8f998 --- /dev/null +++ b/tests/ui/specialization/ctfe/default-assoc-const.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-assoc-const.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/specialization/ctfe/default-assoc-type.rs b/tests/ui/specialization/ctfe/default-assoc-type.rs new file mode 100644 index 0000000000000..3624a0f160c5e --- /dev/null +++ b/tests/ui/specialization/ctfe/default-assoc-type.rs @@ -0,0 +1,27 @@ +//! Regression test showing that we can access associated types during const eval, +//! even if they rely on specialization. +// check-pass +#![feature(specialization)] +//~^ WARNING the feature `specialization` is incomplete and may not be safe to use + +trait Foo { + type Assoc: Trait; +} + +impl Foo for Vec { + default type Assoc = u32; +} + +trait Trait { + const ASSOC: usize; +} + +impl Trait for u32 { + const ASSOC: usize = 0; +} + +fn foo() -> [u8; 0] { + [0; < as Foo>::Assoc as Trait>::ASSOC] +} + +fn main() {} diff --git a/tests/ui/specialization/ctfe/default-assoc-type.stderr b/tests/ui/specialization/ctfe/default-assoc-type.stderr new file mode 100644 index 0000000000000..23fa213caffb3 --- /dev/null +++ b/tests/ui/specialization/ctfe/default-assoc-type.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-assoc-type.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/specialization/defaultimpl/out-of-order.rs b/tests/ui/specialization/defaultimpl/out-of-order.rs index 13258ac8c9fe6..94b3905178fa8 100644 --- a/tests/ui/specialization/defaultimpl/out-of-order.rs +++ b/tests/ui/specialization/defaultimpl/out-of-order.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that you can list the more specific impl before the more general one. diff --git a/tests/ui/specialization/defaultimpl/overlap-projection.rs b/tests/ui/specialization/defaultimpl/overlap-projection.rs index 0add4d5516c7b..46f54c466a831 100644 --- a/tests/ui/specialization/defaultimpl/overlap-projection.rs +++ b/tests/ui/specialization/defaultimpl/overlap-projection.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that impls on projected self types can resolve overlap, even when the // projections involve specialization, so long as the associated type is diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 75c91e4806f77..e9b0845ccf707 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -12,10 +12,7 @@ error[E0599]: the method `foo_one` exists for struct `MyStruct`, but its trait b --> $DIR/specialization-trait-not-implemented.rs:22:29 | LL | struct MyStruct; - | --------------- - | | - | method `foo_one` not found for this struct - | doesn't satisfy `MyStruct: Foo` + | --------------- method `foo_one` not found for this struct because it doesn't satisfy `MyStruct: Foo` ... LL | println!("{}", MyStruct.foo_one()); | ^^^^^^^ method cannot be called on `MyStruct` due to unsatisfied trait bounds diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index 5fd7c647c2531..a0ee771441772 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -6,7 +6,7 @@ struct S; impl Copy for S {} -//~^ ERROR the constant `N` is not of type `usize` impl Copy for S {} +//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>` fn main() {} diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index def4a413af111..2953bc95917c9 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,14 +1,11 @@ -error: the constant `N` is not of type `usize` - --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29 +error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` + --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 | LL | impl Copy for S {} - | ^^^^ expected `usize`, found `i32` - | -note: required by a bound in `S` - --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10 - | -LL | struct S; - | ^^^^^^^^^^^^^^ required by this bound in `S` + | -------------------------------- first implementation here +LL | impl Copy for S {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr index 37ced4cf267fe..da19ed44ce6f1 100644 --- a/tests/ui/specialization/min_specialization/issue-79224.stderr +++ b/tests/ui/specialization/min_specialization/issue-79224.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/issue-79224.rs:18:29 | LL | impl Display for Cow<'_, B> { - | ^^^^^^^^^^ the trait `Clone` is not implemented for `B` + | ^^^^^^^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound @@ -14,7 +14,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/issue-79224.rs:20:5 | LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound @@ -26,7 +26,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/issue-79224.rs:20:13 | LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - | ^^^^ the trait `Clone` is not implemented for `B` + | ^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound diff --git a/tests/ui/specialization/specialization-out-of-order.rs b/tests/ui/specialization/specialization-out-of-order.rs index cb7563e2760c2..66e6c3c9eab31 100644 --- a/tests/ui/specialization/specialization-out-of-order.rs +++ b/tests/ui/specialization/specialization-out-of-order.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that you can list the more specific impl before the more general one. diff --git a/tests/ui/specialization/specialization-overlap-projection.rs b/tests/ui/specialization/specialization-overlap-projection.rs index b07efb2a5c1cd..cd21eab24c0b7 100644 --- a/tests/ui/specialization/specialization-overlap-projection.rs +++ b/tests/ui/specialization/specialization-overlap-projection.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that impls on projected self types can resolve overlap, even when the // projections involve specialization, so long as the associated type is diff --git a/tests/ui/specialization/specialization-supertraits.rs b/tests/ui/specialization/specialization-supertraits.rs index fb85d8019218a..d0c9dbb1d4014 100644 --- a/tests/ui/specialization/specialization-supertraits.rs +++ b/tests/ui/specialization/specialization-supertraits.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(specialization)] //~ WARN the feature `specialization` is incomplete diff --git a/tests/ui/statics/static-impl.rs b/tests/ui/statics/static-impl.rs index e7bdb38ee62c9..9e2db7e0caf50 100644 --- a/tests/ui/statics/static-impl.rs +++ b/tests/ui/statics/static-impl.rs @@ -35,7 +35,7 @@ impl uint_utils for usize { trait vec_utils { fn length_(&self, ) -> usize; - fn iter_(&self, f: F) where F: FnMut(&T); + fn iter_(&self, f: F) where F: FnMut(&T); //~ WARN method `iter_` is never used fn map_(&self, f: F) -> Vec where F: FnMut(&T) -> U; } diff --git a/tests/ui/statics/static-impl.stderr b/tests/ui/statics/static-impl.stderr new file mode 100644 index 0000000000000..83c3ffbefe1f2 --- /dev/null +++ b/tests/ui/statics/static-impl.stderr @@ -0,0 +1,13 @@ +warning: method `iter_` is never used + --> $DIR/static-impl.rs:38:8 + | +LL | trait vec_utils { + | --------- method in this trait +LL | fn length_(&self, ) -> usize; +LL | fn iter_(&self, f: F) where F: FnMut(&T); + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 8b9ec30db63f4..2c21c25d7c77e 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -5,8 +5,8 @@ ast-stats-1 GenericArgs 40 ( 0.6%) 1 40 ast-stats-1 - AngleBracketed 40 ( 0.6%) 1 ast-stats-1 Crate 40 ( 0.6%) 1 40 ast-stats-1 ExprField 48 ( 0.7%) 1 48 -ast-stats-1 WherePredicate 56 ( 0.9%) 1 56 -ast-stats-1 - BoundPredicate 56 ( 0.9%) 1 +ast-stats-1 WherePredicate 56 ( 0.8%) 1 56 +ast-stats-1 - BoundPredicate 56 ( 0.8%) 1 ast-stats-1 Attribute 64 ( 1.0%) 2 32 ast-stats-1 - Normal 32 ( 0.5%) 1 ast-stats-1 - DocComment 32 ( 0.5%) 1 @@ -22,38 +22,38 @@ ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.5%) 3 ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Block 192 ( 2.9%) 6 32 -ast-stats-1 Variant 208 ( 3.2%) 2 104 -ast-stats-1 GenericBound 288 ( 4.4%) 4 72 -ast-stats-1 - Trait 288 ( 4.4%) 4 -ast-stats-1 AssocItem 352 ( 5.4%) 4 88 +ast-stats-1 Variant 208 ( 3.1%) 2 104 +ast-stats-1 GenericBound 352 ( 5.3%) 4 88 +ast-stats-1 - Trait 352 ( 5.3%) 4 +ast-stats-1 AssocItem 352 ( 5.3%) 4 88 ast-stats-1 - Type 176 ( 2.7%) 2 ast-stats-1 - Fn 176 ( 2.7%) 2 ast-stats-1 GenericParam 480 ( 7.3%) 5 96 -ast-stats-1 Pat 504 ( 7.7%) 7 72 +ast-stats-1 Pat 504 ( 7.6%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 -ast-stats-1 - Ident 360 ( 5.5%) 5 -ast-stats-1 Expr 576 ( 8.8%) 8 72 +ast-stats-1 - Ident 360 ( 5.4%) 5 +ast-stats-1 Expr 576 ( 8.7%) 8 72 ast-stats-1 - Path 72 ( 1.1%) 1 ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Lit 144 ( 2.2%) 2 ast-stats-1 - Block 216 ( 3.3%) 3 -ast-stats-1 PathSegment 720 (11.0%) 30 24 -ast-stats-1 Ty 896 (13.7%) 14 64 +ast-stats-1 PathSegment 720 (10.9%) 30 24 +ast-stats-1 Ty 896 (13.5%) 14 64 ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - Ref 64 ( 1.0%) 1 -ast-stats-1 - ImplicitSelf 128 ( 2.0%) 2 -ast-stats-1 - Path 640 ( 9.8%) 10 -ast-stats-1 Item 1_224 (18.7%) 9 136 +ast-stats-1 - ImplicitSelf 128 ( 1.9%) 2 +ast-stats-1 - Path 640 ( 9.7%) 10 +ast-stats-1 Item 1_224 (18.5%) 9 136 ast-stats-1 - Trait 136 ( 2.1%) 1 ast-stats-1 - Enum 136 ( 2.1%) 1 ast-stats-1 - ForeignMod 136 ( 2.1%) 1 ast-stats-1 - Impl 136 ( 2.1%) 1 -ast-stats-1 - Fn 272 ( 4.2%) 2 +ast-stats-1 - Fn 272 ( 4.1%) 2 ast-stats-1 - Use 408 ( 6.2%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_552 +ast-stats-1 Total 6_616 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -81,39 +81,39 @@ ast-stats-2 - Expr 96 ( 1.3%) 3 ast-stats-2 Param 160 ( 2.2%) 4 40 ast-stats-2 Block 192 ( 2.7%) 6 32 ast-stats-2 Variant 208 ( 2.9%) 2 104 -ast-stats-2 GenericBound 288 ( 4.0%) 4 72 -ast-stats-2 - Trait 288 ( 4.0%) 4 +ast-stats-2 GenericBound 352 ( 4.9%) 4 88 +ast-stats-2 - Trait 352 ( 4.9%) 4 ast-stats-2 AssocItem 352 ( 4.9%) 4 88 -ast-stats-2 - Type 176 ( 2.5%) 2 -ast-stats-2 - Fn 176 ( 2.5%) 2 +ast-stats-2 - Type 176 ( 2.4%) 2 +ast-stats-2 - Fn 176 ( 2.4%) 2 ast-stats-2 GenericParam 480 ( 6.7%) 5 96 ast-stats-2 Pat 504 ( 7.0%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 ast-stats-2 - Ident 360 ( 5.0%) 5 -ast-stats-2 Expr 648 ( 9.1%) 9 72 +ast-stats-2 Expr 648 ( 9.0%) 9 72 ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Lit 144 ( 2.0%) 2 ast-stats-2 - Block 216 ( 3.0%) 3 -ast-stats-2 PathSegment 792 (11.1%) 33 24 -ast-stats-2 Ty 896 (12.5%) 14 64 +ast-stats-2 PathSegment 792 (11.0%) 33 24 +ast-stats-2 Ty 896 (12.4%) 14 64 ast-stats-2 - Ptr 64 ( 0.9%) 1 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2 ast-stats-2 - Path 640 ( 8.9%) 10 -ast-stats-2 Item 1_496 (20.9%) 11 136 +ast-stats-2 Item 1_496 (20.7%) 11 136 ast-stats-2 - Trait 136 ( 1.9%) 1 ast-stats-2 - Enum 136 ( 1.9%) 1 ast-stats-2 - ExternCrate 136 ( 1.9%) 1 ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Impl 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.8%) 2 -ast-stats-2 - Use 544 ( 7.6%) 4 +ast-stats-2 - Use 544 ( 7.5%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_152 +ast-stats-2 Total 7_216 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs b/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs index 0f535523dcc06..4a8289cb24284 100644 --- a/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs +++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs @@ -32,7 +32,7 @@ fn assert_inorder(a: &[T]) { } } -trait Foo { fn foo(&self) -> usize; } +trait Foo { fn foo(&self) -> usize; } //~ WARN method `foo` is never used impl Foo for T { fn foo(&self) -> usize { mem::size_of::() diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr new file mode 100644 index 0000000000000..670fa5bb9224b --- /dev/null +++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/raw-fat-ptr.rs:35:16 + | +LL | trait Foo { fn foo(&self) -> usize; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/str/str-escape.rs b/tests/ui/str/str-escape.rs index 10a72421f24a7..89a8217106391 100644 --- a/tests/ui/str/str-escape.rs +++ b/tests/ui/str/str-escape.rs @@ -1,5 +1,6 @@ // check-pass // ignore-tidy-tab +// edition: 2021 fn main() { let s = "\ @@ -8,11 +9,11 @@ fn main() { //~^^^ WARNING multiple lines skipped by escaped newline assert_eq!(s, ""); - let s = "foo\ + let s = c"foo\   bar "; //~^^^ WARNING whitespace symbol '\u{a0}' is not skipped - assert_eq!(s, "foo  bar\n "); + assert_eq!(s, c"foo  bar\n "); let s = "a\ b"; @@ -22,10 +23,10 @@ fn main() { b"; assert_eq!(s, "ab"); - let s = "a\ + let s = b"a\ b"; //~^^ WARNING whitespace symbol '\u{c}' is not skipped // '\x0c' is ASCII whitespace, but it may not need skipped // discussion: https://github.com/rust-lang/rust/pull/108403 - assert_eq!(s, "a\x0cb"); + assert_eq!(s, b"a\x0cb"); } diff --git a/tests/ui/str/str-escape.stderr b/tests/ui/str/str-escape.stderr index 43b4f7e36f6ab..00fe5444e1a4e 100644 --- a/tests/ui/str/str-escape.stderr +++ b/tests/ui/str/str-escape.stderr @@ -1,5 +1,5 @@ warning: multiple lines skipped by escaped newline - --> $DIR/str-escape.rs:5:14 + --> $DIR/str-escape.rs:6:14 | LL | let s = "\ | ______________^ @@ -8,20 +8,20 @@ LL | | "; | |_____________^ skipping everything up to and including this point warning: whitespace symbol '\u{a0}' is not skipped - --> $DIR/str-escape.rs:11:17 + --> $DIR/str-escape.rs:12:18 | -LL | let s = "foo\ - | _________________^ +LL | let s = c"foo\ + | __________________^ LL | |   bar | | ^ whitespace symbol '\u{a0}' is not skipped | |___| | warning: whitespace symbol '\u{c}' is not skipped - --> $DIR/str-escape.rs:25:15 + --> $DIR/str-escape.rs:26:16 | -LL | let s = "a\ - | _______________^ +LL | let s = b"a\ + | ________________^ LL | | b"; | | ^- whitespace symbol '\u{c}' is not skipped | |____| diff --git a/tests/ui/str/str-idx.stderr b/tests/ui/str/str-idx.stderr index e8bbb8058faf3..84806cbea0dea 100644 --- a/tests/ui/str/str-idx.stderr +++ b/tests/ui/str/str-idx.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _: u8 = s[4]; | ^ string indices are ranges of `usize` | - = help: the trait `SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}`, which is required by `str: Index<_>` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: = help: the trait `SliceIndex<[_]>` is implemented for `usize` @@ -49,7 +49,7 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | let _: u8 = s['c']; | ^^^ string indices are ranges of `usize` | - = help: the trait `SliceIndex` is not implemented for `char` + = help: the trait `SliceIndex` is not implemented for `char`, which is required by `str: Index<_>` = note: required for `str` to implement `Index` error: aborting due to 4 previous errors diff --git a/tests/ui/str/str-mut-idx.stderr b/tests/ui/str/str-mut-idx.stderr index e6835bb54fb3d..679f783126ff4 100644 --- a/tests/ui/str/str-mut-idx.stderr +++ b/tests/ui/str/str-mut-idx.stderr @@ -2,14 +2,14 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/str-mut-idx.rs:4:15 | LL | s[1..2] = bot(); - | ^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` -note: required by a bound in `bot` +note: required by an implicit `Sized` bound in `bot` --> $DIR/str-mut-idx.rs:1:8 | LL | fn bot() -> T { loop {} } - | ^ required by this bound in `bot` + | ^ required by the implicit `Sized` requirement on this type parameter in `bot` help: consider relaxing the implicit `Sized` restriction | LL | fn bot() -> T { loop {} } @@ -30,7 +30,7 @@ error[E0277]: the type `str` cannot be indexed by `usize` LL | s[1usize] = bot(); | ^^^^^^ string indices are ranges of `usize` | - = help: the trait `SliceIndex` is not implemented for `usize` + = help: the trait `SliceIndex` is not implemented for `usize`, which is required by `str: Index<_>` = help: the trait `SliceIndex<[_]>` is implemented for `usize` = help: for that trait implementation, expected `[_]`, found `str` = note: required for `str` to implement `Index` @@ -73,7 +73,7 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | s['c']; | ^^^ string indices are ranges of `usize` | - = help: the trait `SliceIndex` is not implemented for `char` + = help: the trait `SliceIndex` is not implemented for `char`, which is required by `str: Index<_>` = note: required for `str` to implement `Index` error: aborting due to 6 previous errors diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.rs b/tests/ui/structs-enums/enum-null-pointer-opt.rs index 356f8a6dd36f6..21564eeec29e3 100644 --- a/tests/ui/structs-enums/enum-null-pointer-opt.rs +++ b/tests/ui/structs-enums/enum-null-pointer-opt.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; -trait Trait { fn dummy(&self) { } } +trait Trait { fn dummy(&self) { } } //~ WARN method `dummy` is never used trait Mirror { type Image; } impl Mirror for T { type Image = T; } struct ParamTypeStruct(#[allow(dead_code)] T); diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.stderr b/tests/ui/structs-enums/enum-null-pointer-opt.stderr new file mode 100644 index 0000000000000..64e93ffaffd60 --- /dev/null +++ b/tests/ui/structs-enums/enum-null-pointer-opt.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/enum-null-pointer-opt.rs:10:18 + | +LL | trait Trait { fn dummy(&self) { } } + | ----- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/tests/ui/suggestions/adt-param-with-implicit-sized-bound.stderr index d136f5ff6543f..6da6f8e23b4f4 100644 --- a/tests/ui/suggestions/adt-param-with-implicit-sized-bound.stderr +++ b/tests/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -6,11 +6,11 @@ LL | struct Struct5{ LL | _t: X, | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `X` +note: required by an implicit `Sized` bound in `X` --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 | LL | struct X(T); - | ^ required by this bound in `X` + | ^ required by the implicit `Sized` requirement on this type parameter in `X` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 | @@ -30,11 +30,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn func1() -> Struct1; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Struct1` +note: required by an implicit `Sized` bound in `Struct1` --> $DIR/adt-param-with-implicit-sized-bound.rs:8:16 | LL | struct Struct1{ - | ^ required by this bound in `Struct1` + | ^ required by the implicit `Sized` requirement on this type parameter in `Struct1` help: consider further restricting `Self` | LL | fn func1() -> Struct1 where Self: Sized; @@ -50,11 +50,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn func2<'a>() -> Struct2<'a, Self>; | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Struct2` +note: required by an implicit `Sized` bound in `Struct2` --> $DIR/adt-param-with-implicit-sized-bound.rs:11:20 | LL | struct Struct2<'a, T>{ - | ^ required by this bound in `Struct2` + | ^ required by the implicit `Sized` requirement on this type parameter in `Struct2` help: consider further restricting `Self` | LL | fn func2<'a>() -> Struct2<'a, Self> where Self: Sized; @@ -70,11 +70,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn func3() -> Struct3; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Struct3` +note: required by an implicit `Sized` bound in `Struct3` --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16 | LL | struct Struct3{ - | ^ required by this bound in `Struct3` + | ^ required by the implicit `Sized` requirement on this type parameter in `Struct3` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16 | @@ -93,11 +93,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn func4() -> Struct4; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Struct4` +note: required by an implicit `Sized` bound in `Struct4` --> $DIR/adt-param-with-implicit-sized-bound.rs:20:16 | LL | struct Struct4{ - | ^ required by this bound in `Struct4` + | ^ required by the implicit `Sized` requirement on this type parameter in `Struct4` help: consider further restricting `Self` | LL | fn func4() -> Struct4 where Self: Sized; diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 3065f83ea3d1b..dc4ec5d3ee28b 100644 --- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -18,25 +18,21 @@ help: use parentheses to call this function LL | bar(foo()); | ++ -error[E0277]: `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future +error[E0277]: `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9 | LL | bar(async_closure); - | --- ^^^^^^^^^^^^^ `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future + | --- ^^^^^^^^^^^^^ `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future | | | required by a bound introduced by this call | - = help: the trait `Future` is not implemented for closure `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` - = note: {closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited + = help: the trait `Future` is not implemented for `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` + = note: {coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited note: required by a bound in `bar` --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16 | LL | fn bar(f: impl Future) {} | ^^^^^^^^^^^^^^^^^ required by this bound in `bar` -help: use parentheses to call this closure - | -LL | bar(async_closure()); - | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/bound-suggestions.fixed b/tests/ui/suggestions/bound-suggestions.fixed index 17a019c69849f..ef61fb9ad325f 100644 --- a/tests/ui/suggestions/bound-suggestions.fixed +++ b/tests/ui/suggestions/bound-suggestions.fixed @@ -40,26 +40,31 @@ fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Sized { //~^ ERROR doesn't implement } +#[allow(dead_code)] trait Foo: Sized { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bar: std::fmt::Display + Sized { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Baz: Sized where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Qux: Sized where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bat: std::fmt::Display + Sized { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time diff --git a/tests/ui/suggestions/bound-suggestions.rs b/tests/ui/suggestions/bound-suggestions.rs index 86f708d42f5e7..6d17fae6a088e 100644 --- a/tests/ui/suggestions/bound-suggestions.rs +++ b/tests/ui/suggestions/bound-suggestions.rs @@ -40,26 +40,31 @@ fn test_many_bounds_where(x: X) where X: Sized, X: Sized { //~^ ERROR doesn't implement } +#[allow(dead_code)] trait Foo { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bar: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Baz where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Qux where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bat: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr index cd27947f02fad..4965e7439f849 100644 --- a/tests/ui/suggestions/bound-suggestions.stderr +++ b/tests/ui/suggestions/bound-suggestions.stderr @@ -71,12 +71,12 @@ LL | fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Siz | +++++++++++++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:44:46 + --> $DIR/bound-suggestions.rs:45:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider further restricting `Self` | @@ -84,12 +84,12 @@ LL | trait Foo: Sized { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:49:46 + --> $DIR/bound-suggestions.rs:51:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider further restricting `Self` | @@ -97,12 +97,12 @@ LL | trait Bar: std::fmt::Display + Sized { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:54:46 + --> $DIR/bound-suggestions.rs:57:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider further restricting `Self` | @@ -110,12 +110,12 @@ LL | trait Baz: Sized where Self: std::fmt::Display { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:59:46 + --> $DIR/bound-suggestions.rs:63:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider further restricting `Self` | @@ -123,12 +123,12 @@ LL | trait Qux: Sized where Self: std::fmt::Display { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:64:46 + --> $DIR/bound-suggestions.rs:69:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider further restricting `Self` | diff --git a/tests/ui/suggestions/constrain-trait.fixed b/tests/ui/suggestions/constrain-trait.fixed index f292f27f0f342..f7360efe4c527 100644 --- a/tests/ui/suggestions/constrain-trait.fixed +++ b/tests/ui/suggestions/constrain-trait.fixed @@ -1,5 +1,6 @@ // run-rustfix // check-only +#![allow(dead_code)] #[derive(Debug)] struct Demo { diff --git a/tests/ui/suggestions/constrain-trait.rs b/tests/ui/suggestions/constrain-trait.rs index 99ccf7a7f3bdf..799100669b654 100644 --- a/tests/ui/suggestions/constrain-trait.rs +++ b/tests/ui/suggestions/constrain-trait.rs @@ -1,5 +1,6 @@ // run-rustfix // check-only +#![allow(dead_code)] #[derive(Debug)] struct Demo { diff --git a/tests/ui/suggestions/constrain-trait.stderr b/tests/ui/suggestions/constrain-trait.stderr index a26f86917bc1f..b28972ecde041 100644 --- a/tests/ui/suggestions/constrain-trait.stderr +++ b/tests/ui/suggestions/constrain-trait.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `get_a` found for reference `&Self` in the current scope - --> $DIR/constrain-trait.rs:15:31 + --> $DIR/constrain-trait.rs:16:31 | LL | println!("{:?}", self.get_a()); | ^^^^^ method not found in `&Self` @@ -11,7 +11,7 @@ LL | trait UseString: std::fmt::Debug + GetString { | +++++++++++ error[E0599]: no method named `get_a` found for reference `&Self` in the current scope - --> $DIR/constrain-trait.rs:21:31 + --> $DIR/constrain-trait.rs:22:31 | LL | println!("{:?}", self.get_a()); | ^^^^^ method not found in `&Self` diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr index 680890e880ca6..6fae6e1316df0 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.stderr +++ b/tests/ui/suggestions/derive-clone-for-eq.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/derive-clone-for-eq.rs:4:17 | LL | #[derive(Clone, Eq)] - | ^^ the trait `Clone` is not implemented for `T` + | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct: PartialEq` | note: required for `Struct` to implement `PartialEq` --> $DIR/derive-clone-for-eq.rs:7:19 diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index bffcb1af487e9..5da85a9d0619c 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -6,7 +6,7 @@ LL | #[derive(Debug)] LL | struct Outer(Inner); | ^^^^^^^^ `a::Inner` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `a::Inner` + = help: the trait `Debug` is not implemented for `a::Inner`, which is required by `&a::Inner: Debug` = note: add `#[derive(Debug)]` to `a::Inner` or manually `impl Debug for a::Inner` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `a::Inner` with `#[derive(Debug)]` @@ -25,7 +25,7 @@ error[E0277]: the trait bound `T: c::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer(Inner); - | ^^^^^^^^ the trait `c::Trait` is not implemented for `T` + | ^^^^^^^^ the trait `c::Trait` is not implemented for `T`, which is required by `&c::Inner: Debug` | note: required for `c::Inner` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:34:28 @@ -49,7 +49,7 @@ error[E0277]: the trait bound `T: d::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer(Inner); - | ^^^^^^^^ the trait `d::Trait` is not implemented for `T` + | ^^^^^^^^ the trait `d::Trait` is not implemented for `T`, which is required by `&d::Inner: Debug` | note: required for `d::Inner` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:49:13 @@ -71,7 +71,7 @@ error[E0277]: the trait bound `T: e::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer(Inner); - | ^^^^^^^^ the trait `e::Trait` is not implemented for `T` + | ^^^^^^^^ the trait `e::Trait` is not implemented for `T`, which is required by `&e::Inner: Debug` | note: required for `e::Inner` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:64:13 @@ -93,7 +93,7 @@ error[E0277]: the trait bound `T: f::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer(Inner); - | ^^^^^^^^ the trait `f::Trait` is not implemented for `T` + | ^^^^^^^^ the trait `f::Trait` is not implemented for `T`, which is required by `&f::Inner: Debug` | note: required for `f::Inner` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:79:20 diff --git a/tests/ui/suggestions/derive-trait-for-method-call.stderr b/tests/ui/suggestions/derive-trait-for-method-call.stderr index e2db0da74f022..9d6d29ec74eec 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.stderr +++ b/tests/ui/suggestions/derive-trait-for-method-call.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `test` exists for struct `Foo`, but it --> $DIR/derive-trait-for-method-call.rs:28:15 | LL | enum Enum { - | --------- - | | - | doesn't satisfy `Enum: Clone` - | doesn't satisfy `Enum: Default` + | --------- doesn't satisfy `Enum: Clone` or `Enum: Default` ... LL | enum CloneEnum { | -------------- doesn't satisfy `CloneEnum: Default` @@ -40,10 +37,7 @@ error[E0599]: the method `test` exists for struct `Foo`, bu --> $DIR/derive-trait-for-method-call.rs:34:15 | LL | struct Struct { - | ------------- - | | - | doesn't satisfy `Struct: Clone` - | doesn't satisfy `Struct: Default` + | ------------- doesn't satisfy `Struct: Clone` or `Struct: Default` ... LL | struct CloneStruct { | ------------------ doesn't satisfy `CloneStruct: Default` @@ -85,12 +79,6 @@ LL | struct Foo (X, Y); ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo, Instant>` due to unsatisfied trait bounds - --> $SRC_DIR/std/src/time.rs:LL:COL - | - = note: doesn't satisfy `Instant: Default` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - | - = note: doesn't satisfy `Vec: Clone` | note: the following trait bounds were not satisfied: `Instant: Default` diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index d6efc8173cb7c..d10a294c7d2dd 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&str: From` is not satisfied --> $DIR/into-str.rs:4:9 | LL | foo(String::new()); - | --- ^^^^^^^^^^^^^ the trait `From` is not implemented for `&str` + | --- ^^^^^^^^^^^^^ the trait `From` is not implemented for `&str`, which is required by `String: Into<&str>` | | | required by a bound introduced by this call | diff --git a/tests/ui/suggestions/issue-104327.stderr b/tests/ui/suggestions/issue-104327.stderr index 325b6b6eb4b63..1bad82d471e04 100644 --- a/tests/ui/suggestions/issue-104327.stderr +++ b/tests/ui/suggestions/issue-104327.stderr @@ -5,7 +5,7 @@ LL | fn f() {} | --------- `Foo::f` defined here ... LL | Foo::f(); - | ^^^^^^ cannot call associated function of trait + | ^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | diff --git a/tests/ui/suggestions/issue-104328.stderr b/tests/ui/suggestions/issue-104328.stderr index a592621834127..3c5e6f16289e0 100644 --- a/tests/ui/suggestions/issue-104328.stderr +++ b/tests/ui/suggestions/issue-104328.stderr @@ -5,7 +5,7 @@ LL | fn f() {} | --------- `Foo::f` defined here ... LL | Foo::f(); - | ^^^^^^ cannot call associated function of trait + | ^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs new file mode 100644 index 0000000000000..cc499b0d77618 --- /dev/null +++ b/tests/ui/suggestions/issue-109195.rs @@ -0,0 +1,20 @@ +fn main() { + String::from::utf8; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `from_utf8` + String::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `from_utf8` + String::from::utf16(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `from_utf16` + String::from::method_that_doesnt_exist(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `from` + str::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `from` + str::from::utf8_mut(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `from` +} diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr new file mode 100644 index 0000000000000..10cf9cfd28ca7 --- /dev/null +++ b/tests/ui/suggestions/issue-109195.stderr @@ -0,0 +1,69 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:2:5 + | +LL | String::from::utf8; + | ^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `from_utf8` + | +LL | String::from_utf8; + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:5:5 + | +LL | String::from::utf8(); + | ^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `from_utf8` + | +LL | String::from_utf8(); + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:8:5 + | +LL | String::from::utf16(); + | ^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `from_utf16` + | +LL | String::from_utf16(); + | ~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:11:5 + | +LL | String::from::method_that_doesnt_exist(); + | ^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path + | +LL | ::from::method_that_doesnt_exist(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:14:5 + | +LL | str::from::utf8(); + | ^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path + | +LL | ::from::utf8(); + | ~~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:17:5 + | +LL | str::from::utf8_mut(); + | ^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path + | +LL | ::from::utf8_mut(); + | ~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index b9b72e0e63f14..0f6bfbeec45f3 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied --> $DIR/issue-71394-no-from-impl.rs:8:25 | LL | let _: &[i8] = data.into(); - | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` + | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`, which is required by `&[u8]: Into<_>` | = help: the following other types implement trait `From`: <[bool; N] as From>> diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index e0bdb6949a9c9..8e980997089e6 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -57,10 +57,10 @@ LL | f_sized(*ref_cl); | = help: the trait `Sized` is not implemented for `dyn Fn()` note: required by a bound in `f_sized` - --> $DIR/issue-84973-blacklist.rs:9:12 + --> $DIR/issue-84973-blacklist.rs:9:15 | LL | fn f_sized(t: T) {} - | ^ required by this bound in `f_sized` + | ^^^^^ required by this bound in `f_sized` error[E0277]: `Rc<{integer}>` cannot be sent between threads safely --> $DIR/issue-84973-blacklist.rs:27:12 diff --git a/tests/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr b/tests/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr index 21b568b02ad25..7dcb2deb06a04 100644 --- a/tests/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr +++ b/tests/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr @@ -5,11 +5,11 @@ LL | struct B(A<[u8]>); | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `A` +note: required by an implicit `Sized` bound in `A` --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:4:10 | LL | struct A(T) where T: Send; - | ^ required by this bound in `A` + | ^ required by the implicit `Sized` requirement on this type parameter in `A` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:4:10 | diff --git a/tests/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr b/tests/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr index 77e5dcd91a1ea..1cbcfbf84bcf4 100644 --- a/tests/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr +++ b/tests/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr @@ -8,10 +8,10 @@ LL | fn bar() { foo(""); } | = help: the trait `Sized` is not implemented for `str` note: required by a bound in `foo` - --> $DIR/issue-85945-check-where-clause-before-suggesting-unsized.rs:3:8 + --> $DIR/issue-85945-check-where-clause-before-suggesting-unsized.rs:3:27 | LL | fn foo(_: &T) where T: Sized {} - | ^ required by this bound in `foo` + | ^^^^^ required by this bound in `foo` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-88696.stderr b/tests/ui/suggestions/issue-88696.stderr index b4f0793c225ff..a8bc970e055b8 100644 --- a/tests/ui/suggestions/issue-88696.stderr +++ b/tests/ui/suggestions/issue-88696.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Result: From>` is not --> $DIR/issue-88696.rs:9:9 | LL | a().into() - | ^^^^ the trait `From>` is not implemented for `Result` + | ^^^^ the trait `From>` is not implemented for `Result`, which is required by `Result: Into<_>` | = note: required for `Result` to implement `Into>` diff --git a/tests/ui/suggestions/issue-89333.stderr b/tests/ui/suggestions/issue-89333.stderr index 761de7f252184..9df850ec9de08 100644 --- a/tests/ui/suggestions/issue-89333.stderr +++ b/tests/ui/suggestions/issue-89333.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a _: Trait` is not satisfied --> $DIR/issue-89333.rs:6:5 | LL | test(&|| 0); - | ^^^^ the trait `for<'a> Trait` is not implemented for `&'a _` + | ^^^^^^^^^^^ the trait `for<'a> Trait` is not implemented for `&'a _` | help: this trait has no implementations, consider adding one --> $DIR/issue-89333.rs:9:1 diff --git a/tests/ui/suggestions/issue-96223.stderr b/tests/ui/suggestions/issue-96223.stderr index a54a4e7b3be4d..4a77b240f3e54 100644 --- a/tests/ui/suggestions/issue-96223.stderr +++ b/tests/ui/suggestions/issue-96223.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'de> EmptyBis<'de>: Foo<'_>` is not satisfied --> $DIR/issue-96223.rs:49:17 | LL | icey_bounds(&p); - | ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>` + | ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>`, which is required by `Empty: Dummy` | | | required by a bound introduced by this call | diff --git a/tests/ui/suggestions/issue-96555.stderr b/tests/ui/suggestions/issue-96555.stderr index 1a1e069f09eb4..f77681ae80faa 100644 --- a/tests/ui/suggestions/issue-96555.stderr +++ b/tests/ui/suggestions/issue-96555.stderr @@ -6,7 +6,7 @@ LL | m::f1().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` @@ -27,7 +27,7 @@ LL | m::f2().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` @@ -48,7 +48,7 @@ LL | m::f3().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed index 3257ea04c6900..d4a8381fcb146 100644 --- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed +++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed @@ -1,6 +1,7 @@ // Make sure we suggest the bound `T: 'a` in the correct scope: // trait, impl or associated fn. // run-rustfix +#![allow(dead_code)] struct Inv<'a>(#[allow(dead_code)] Option<*mut &'a u8>); diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs index fcc13aad9965e..dc43e2df6ddb0 100644 --- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs +++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs @@ -1,6 +1,7 @@ // Make sure we suggest the bound `T: 'a` in the correct scope: // trait, impl or associated fn. // run-rustfix +#![allow(dead_code)] struct Inv<'a>(#[allow(dead_code)] Option<*mut &'a u8>); diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr index d3ca2cc116228..91054472c04d4 100644 --- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr +++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr @@ -1,5 +1,5 @@ error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/type-param-bound-scope.rs:11:9 + --> $DIR/type-param-bound-scope.rs:12:9 | LL | trait Trait1<'a>: Sized { | -- the parameter type `Self` must be valid for the lifetime `'a` as defined here... @@ -13,7 +13,7 @@ LL | trait Trait1<'a>: Sized where Self: 'a { | ++++++++++++++ error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/type-param-bound-scope.rs:18:9 + --> $DIR/type-param-bound-scope.rs:19:9 | LL | fn foo<'a>(self, lt: Inv<'a>) { | -- the parameter type `Self` must be valid for the lifetime `'a` as defined here... @@ -26,7 +26,7 @@ LL | fn foo<'a>(self, lt: Inv<'a>) where Self: 'a { | ++++++++++++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/type-param-bound-scope.rs:25:9 + --> $DIR/type-param-bound-scope.rs:26:9 | LL | fn foo<'a>(arg: T, lt: Inv<'a>) { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... @@ -39,7 +39,7 @@ LL | fn foo<'a>(arg: T, lt: Inv<'a>) where T: 'a { | +++++++++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/type-param-bound-scope.rs:32:9 + --> $DIR/type-param-bound-scope.rs:33:9 | LL | trait Trait4<'a> { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... @@ -53,7 +53,7 @@ LL | fn foo(arg: T, lt: Inv<'a>) { | ++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/type-param-bound-scope.rs:42:9 + --> $DIR/type-param-bound-scope.rs:43:9 | LL | impl<'a, T> Trait5<'a> for T { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed index f32c61a99bb8c..90bc10d34c611 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs index d7725f4a3743d..34673852a9b53 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr index 6dc512223d1b0..23a75154f2008 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:18 + --> $DIR/missing-bound-in-manual-copy-impl-2.rs:17:18 | LL | struct Wrapper(T); | - this field does not implement `Copy` @@ -8,7 +8,7 @@ LL | impl Copy for Wrapper> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the `Copy` impl for `OnlyCopyIfDisplay` requires that `S: std::fmt::Display` - --> $DIR/missing-bound-in-manual-copy-impl-2.rs:4:19 + --> $DIR/missing-bound-in-manual-copy-impl-2.rs:5:19 | LL | struct Wrapper(T); | ^ diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed index 1139b315313fc..ff84e42c9470b 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs index 19549248efc23..35d0a9dda7914 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr index fd38d4c64b44c..c9f277fb3501a 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/missing-bound-in-manual-copy-impl.rs:6:18 + --> $DIR/missing-bound-in-manual-copy-impl.rs:7:18 | LL | struct Wrapper(T); | - this field does not implement `Copy` diff --git a/tests/ui/suggestions/missing-trait-item.fixed b/tests/ui/suggestions/missing-trait-item.fixed index a1cf359ec9124..ded4ec1976067 100644 --- a/tests/ui/suggestions/missing-trait-item.fixed +++ b/tests/ui/suggestions/missing-trait-item.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait T { unsafe fn foo(a: &usize, b: &usize) -> usize; diff --git a/tests/ui/suggestions/missing-trait-item.rs b/tests/ui/suggestions/missing-trait-item.rs index b4fca25ba2f11..de8974037ac99 100644 --- a/tests/ui/suggestions/missing-trait-item.rs +++ b/tests/ui/suggestions/missing-trait-item.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait T { unsafe fn foo(a: &usize, b: &usize) -> usize; diff --git a/tests/ui/suggestions/missing-trait-item.stderr b/tests/ui/suggestions/missing-trait-item.stderr index 4a9d7b472c93a..298d0d16438be 100644 --- a/tests/ui/suggestions/missing-trait-item.stderr +++ b/tests/ui/suggestions/missing-trait-item.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo`, `bar` - --> $DIR/missing-trait-item.rs:10:5 + --> $DIR/missing-trait-item.rs:11:5 | LL | unsafe fn foo(a: &usize, b: &usize) -> usize; | --------------------------------------------- `foo` from trait @@ -10,7 +10,7 @@ LL | impl T for () {} | ^^^^^^^^^^^^^ missing `foo`, `bar` in implementation error[E0046]: not all trait items implemented, missing: `foo`, `bar` - --> $DIR/missing-trait-item.rs:12:5 + --> $DIR/missing-trait-item.rs:13:5 | LL | unsafe fn foo(a: &usize, b: &usize) -> usize; | --------------------------------------------- `foo` from trait diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index 94710f4503f56..09a9b1d3b3482 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -25,9 +25,6 @@ error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, | LL | writeln!(fp, "hello world").unwrap(); | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds - --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL - | - = note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` | note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method --> $DIR/mut-borrow-needed-by-trait.rs:21:14 diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs new file mode 100644 index 0000000000000..dbdfde6dd5061 --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs @@ -0,0 +1,25 @@ +// edition:2021 +#![allow(bare_trait_objects)] +trait A: Sized { + fn f(a: A) -> A; + //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR trait objects must include the `dyn` keyword + //~| ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `A` cannot be made into an object +} +trait B { + fn f(b: B) -> B; + //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR trait objects must include the `dyn` keyword + //~| ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `B` cannot be made into an object +} +trait C { + fn f(&self, c: C) -> C; + //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR trait objects must include the `dyn` keyword + //~| ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `C` cannot be made into an object +} + +fn main() {} diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr new file mode 100644 index 0000000000000..60eb72ab4f768 --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr @@ -0,0 +1,176 @@ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | trait A: Sized { + | - in this trait +LL | fn f(a: A) -> A; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | fn f(a: A) -> A; + | ^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:3:10 + | +LL | trait A: Sized { + | - ^^^^^ ...because it requires `Self: Sized` + | | + | this trait cannot be made into an object... + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 + | +LL | trait B { + | - in this trait +LL | fn f(b: B) -> B; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(b: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 + | +LL | fn f(b: B) -> B; + | ^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:8 + | +LL | trait B { + | - this trait cannot be made into an object... +LL | fn f(b: B) -> B; + | ^ ...because associated function `f` has no `self` parameter +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | fn f(&self, b: B) -> B; + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | fn f(b: B) -> B where Self: Sized; + | +++++++++++++++++ + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 + | +LL | trait C { + | - in this trait +LL | fn f(&self, c: C) -> C; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(&self, c: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `C` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 + | +LL | fn f(&self, c: C) -> C; + | ----- ^ `C` cannot be made into an object + | | + | help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self` + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10 + | +LL | trait C { + | - this trait cannot be made into an object... +LL | fn f(&self, c: C) -> C; + | ^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | fn f(a: A) -> A; + | ^ + | + = note: `A` it is not object safe, so it can't be `dyn` +help: use a new generic type parameter, constrained by `A` + | +LL | fn f(a: T) -> A; + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn f(a: impl A) -> A; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19 + | +LL | fn f(a: A) -> A; + | ^ + | +help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(a: A) -> impl A; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 + | +LL | fn f(b: B) -> B; + | ^ + | + = note: `B` it is not object safe, so it can't be `dyn` +help: use a new generic type parameter, constrained by `B` + | +LL | fn f(b: T) -> B; + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn f(b: impl B) -> B; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19 + | +LL | fn f(b: B) -> B; + | ^ + | +help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(b: B) -> impl B; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 + | +LL | fn f(&self, c: C) -> C; + | ^ + | + = note: `C` it is not object safe, so it can't be `dyn` +help: use a new generic type parameter, constrained by `C` + | +LL | fn f(&self, c: T) -> C; + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn f(&self, c: impl C) -> C; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26 + | +LL | fn f(&self, c: C) -> C; + | ^ + | +help: `C` is not object safe, use `impl C` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(&self, c: C) -> impl C; + | ++++ + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0038, E0782. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs new file mode 100644 index 0000000000000..a598e883f3fdd --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs @@ -0,0 +1,17 @@ +// edition:2021 +#![allow(bare_trait_objects)] +trait A: Sized { + fn f(a: dyn A) -> dyn A; + //~^ ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `A` cannot be made into an object +} +trait B { + fn f(a: dyn B) -> dyn B; + //~^ ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `B` cannot be made into an object +} +trait C { + fn f(&self, a: dyn C) -> dyn C; +} + +fn main() {} diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr new file mode 100644 index 0000000000000..d6376be9c046c --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr @@ -0,0 +1,65 @@ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13 + | +LL | trait A: Sized { + | - in this trait +LL | fn f(a: dyn A) -> dyn A; + | ^^^^^ ^^^^^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13 + | +LL | fn f(a: dyn A) -> dyn A; + | ^^^^^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10 + | +LL | trait A: Sized { + | - ^^^^^ ...because it requires `Self: Sized` + | | + | this trait cannot be made into an object... + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13 + | +LL | trait B { + | - in this trait +LL | fn f(a: dyn B) -> dyn B; + | ^^^^^ ^^^^^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13 + | +LL | fn f(a: dyn B) -> dyn B; + | ^^^^^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8 + | +LL | trait B { + | - this trait cannot be made into an object... +LL | fn f(a: dyn B) -> dyn B; + | ^ ...because associated function `f` has no `self` parameter +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | fn f(&self, a: dyn B) -> dyn B; + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | fn f(a: dyn B) -> dyn B where Self: Sized; + | +++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.fixed b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.fixed new file mode 100644 index 0000000000000..570d91d949bfc --- /dev/null +++ b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.fixed @@ -0,0 +1,16 @@ +// run-rustfix +use std::io::stdin; + +fn get_name() -> String { + let mut your_name = String::new(); + stdin() + .read_line(&mut your_name) + .expect("Failed to read the line for some reason"); + your_name.trim().to_string() //~ ERROR E0308 +} + +fn main() { + println!("Hello, What is your name? "); + let your_name = get_name(); + println!("Hello, {}", your_name) +} diff --git a/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.rs b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.rs new file mode 100644 index 0000000000000..93e8c0af0323e --- /dev/null +++ b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.rs @@ -0,0 +1,16 @@ +// run-rustfix +use std::io::stdin; + +fn get_name() -> String { + let mut your_name = String::new(); + stdin() + .read_line(&mut your_name) + .expect("Failed to read the line for some reason"); + your_name.trim() //~ ERROR E0308 +} + +fn main() { + println!("Hello, What is your name? "); + let your_name = get_name(); + println!("Hello, {}", your_name) +} diff --git a/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr new file mode 100644 index 0000000000000..c721ceb11463f --- /dev/null +++ b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/only-suggest-removal-of-conversion-method-calls.rs:9:5 + | +LL | fn get_name() -> String { + | ------ expected `String` because of return type +... +LL | your_name.trim() + | ^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | expected `String`, found `&str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/path-by-value.stderr b/tests/ui/suggestions/path-by-value.stderr index 567d9d5b9e7a4..46002d4e257e6 100644 --- a/tests/ui/suggestions/path-by-value.stderr +++ b/tests/ui/suggestions/path-by-value.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | - = help: within `Path`, the trait `Sized` is not implemented for `[u8]` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized` note: required because it appears within the type `Path` --> $SRC_DIR/std/src/path.rs:LL:COL = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr index 46d0b35825bca..f9159c450301b 100644 --- a/tests/ui/suggestions/path-display.stderr +++ b/tests/ui/suggestions/path-display.stderr @@ -4,7 +4,7 @@ error[E0277]: `Path` doesn't implement `std::fmt::Display` LL | println!("{}", path); | ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it | - = help: the trait `std::fmt::Display` is not implemented for `Path` + = help: the trait `std::fmt::Display` is not implemented for `Path`, which is required by `&Path: std::fmt::Display` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr b/tests/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr index eb74679d66049..dcab4d7c4fcb3 100644 --- a/tests/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr +++ b/tests/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr @@ -6,11 +6,11 @@ LL | fn foo(foo: Wrapper) | | | this type parameter needs to be `Sized` | -note: required by a bound in `Wrapper` +note: required by an implicit `Sized` bound in `Wrapper` --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16 | LL | struct Wrapper(T); - | ^ required by this bound in `Wrapper` + | ^ required by the implicit `Sized` requirement on this type parameter in `Wrapper` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16 | @@ -35,11 +35,11 @@ LL | fn bar(foo: Wrapper) | | | this type parameter needs to be `Sized` | -note: required by a bound in `Wrapper` +note: required by an implicit `Sized` bound in `Wrapper` --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16 | LL | struct Wrapper(T); - | ^ required by this bound in `Wrapper` + | ^ required by the implicit `Sized` requirement on this type parameter in `Wrapper` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16 | @@ -60,11 +60,11 @@ LL | fn qux(foo: Wrapper) | | | this type parameter needs to be `Sized` | -note: required by a bound in `Wrapper` +note: required by an implicit `Sized` bound in `Wrapper` --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16 | LL | struct Wrapper(T); - | ^ required by this bound in `Wrapper` + | ^ required by the implicit `Sized` requirement on this type parameter in `Wrapper` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16 | diff --git a/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr b/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr index 125a8b44f2f0a..485015a98f2a7 100644 --- a/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr +++ b/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&mut usize: Default` is not satisfied --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:13:9 | LL | foo(Default::default()); - | ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&mut usize` + | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&mut usize` | help: consider mutably borrowing here | @@ -13,7 +13,7 @@ error[E0277]: the trait bound `&usize: Default` is not satisfied --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:14:9 | LL | bar(Default::default()); - | ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&usize` + | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&usize` | help: consider borrowing here | diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed new file mode 100644 index 0000000000000..86ac07a93a367 --- /dev/null +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +struct A { + +} + +trait M { + fn foo(_a: Self); + fn bar(_a: Self); + fn baz(_a: i32); +} + +impl M for A { + fn foo(_a: Self) {} + fn bar(_a: A) {} + fn baz(_a: i32) {} +} + +fn main() { + let _a = A {}; + A::foo(_a); + //~^ ERROR no method named `foo` found + A::baz(0); + //~^ ERROR no method named `baz` found + + let _b = A {}; + A::bar(_b); + //~^ ERROR no method named `bar` found +} diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs new file mode 100644 index 0000000000000..9a57ffb77405a --- /dev/null +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs @@ -0,0 +1,29 @@ +// run-rustfix + +struct A { + +} + +trait M { + fn foo(_a: Self); + fn bar(_a: Self); + fn baz(_a: i32); +} + +impl M for A { + fn foo(_a: Self) {} + fn bar(_a: A) {} + fn baz(_a: i32) {} +} + +fn main() { + let _a = A {}; + _a.foo(); + //~^ ERROR no method named `foo` found + _a.baz(0); + //~^ ERROR no method named `baz` found + + let _b = A {}; + _b.bar(); + //~^ ERROR no method named `bar` found +} diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr new file mode 100644 index 0000000000000..0df2b08d3be82 --- /dev/null +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr @@ -0,0 +1,60 @@ +error[E0599]: no method named `foo` found for struct `A` in the current scope + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:21:8 + | +LL | struct A { + | -------- method `foo` not found for this struct +... +LL | _a.foo(); + | ---^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `A::foo(_a)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `M` + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:8:5 + | +LL | fn foo(_a: Self); + | ^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `baz` found for struct `A` in the current scope + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:23:8 + | +LL | struct A { + | -------- method `baz` not found for this struct +... +LL | _a.baz(0); + | ---^^^--- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `A::baz(0)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `M` + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:10:5 + | +LL | fn baz(_a: i32); + | ^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `bar` found for struct `A` in the current scope + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:27:8 + | +LL | struct A { + | -------- method `bar` not found for this struct +... +LL | _b.bar(); + | ---^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `A::bar(_b)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `M` + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:9:5 + | +LL | fn bar(_a: Self); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/suggest-change-mut.stderr b/tests/ui/suggestions/suggest-change-mut.stderr index d194afeaf931d..216d1e810fd72 100644 --- a/tests/ui/suggestions/suggest-change-mut.stderr +++ b/tests/ui/suggestions/suggest-change-mut.stderr @@ -27,9 +27,6 @@ error[E0599]: the method `read_until` exists for struct `BufReader<&T>`, but its | LL | stream_reader.read_until(b'\n', &mut buffer).expect("Reading into buffer failed"); | ^^^^^^^^^^ method cannot be called on `BufReader<&T>` due to unsatisfied trait bounds - --> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL - | - = note: doesn't satisfy `BufReader<&T>: BufRead` | = note: the following trait bounds were not satisfied: `&T: std::io::Read` diff --git a/tests/ui/suggestions/suggest-dereferencing-index.stderr b/tests/ui/suggestions/suggest-dereferencing-index.stderr index 2316acbe9da28..86487cdcc444a 100644 --- a/tests/ui/suggestions/suggest-dereferencing-index.stderr +++ b/tests/ui/suggestions/suggest-dereferencing-index.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `&usize` LL | let one_item_please: i32 = [1, 2, 3][i]; | ^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize`, which is required by `[{integer}; 3]: Index<_>` = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `&usize` = note: required for `[{integer}]` to implement `Index<&usize>` diff --git a/tests/ui/suggestions/suggest-pin-macro.stderr b/tests/ui/suggestions/suggest-pin-macro.stderr index a761a454ad5a3..68f4099a976d0 100644 --- a/tests/ui/suggestions/suggest-pin-macro.stderr +++ b/tests/ui/suggestions/suggest-pin-macro.stderr @@ -2,7 +2,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned --> $DIR/suggest-pin-macro.rs:22:17 | LL | dummy(test1.get_mut()); - | ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned` + | ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned`, which is required by `Test: Unpin` | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope diff --git a/tests/ui/suggestions/suggest-remove-refs-1.stderr b/tests/ui/suggestions/suggest-remove-refs-1.stderr index 523f78dffcc67..171184bf77d30 100644 --- a/tests/ui/suggestions/suggest-remove-refs-1.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-1.stderr @@ -4,7 +4,7 @@ error[E0277]: `&Enumerate>` is not an iterator LL | for (i, _) in &v.iter().enumerate() { | ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&Enumerate>` + = help: the trait `Iterator` is not implemented for `&Enumerate>`, which is required by `&Enumerate>: IntoIterator` = note: required for `&Enumerate>` to implement `IntoIterator` help: consider removing the leading `&`-reference | diff --git a/tests/ui/suggestions/suggest-remove-refs-2.stderr b/tests/ui/suggestions/suggest-remove-refs-2.stderr index bbe3261e14869..4e1994523dc2b 100644 --- a/tests/ui/suggestions/suggest-remove-refs-2.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-2.stderr @@ -4,7 +4,7 @@ error[E0277]: `&&&&&Enumerate>` is not an iterat LL | for (i, _) in & & & & &v.iter().enumerate() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>`, which is required by `&&&&&Enumerate>: IntoIterator` = note: required for `&&&&&Enumerate>` to implement `IntoIterator` help: consider removing 5 leading `&`-references | diff --git a/tests/ui/suggestions/suggest-remove-refs-3.stderr b/tests/ui/suggestions/suggest-remove-refs-3.stderr index a3e142563ff84..1d180f9d8be24 100644 --- a/tests/ui/suggestions/suggest-remove-refs-3.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-3.stderr @@ -8,7 +8,7 @@ LL | | .iter() LL | | .enumerate() { | |____________________^ `&&&&&Enumerate>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>`, which is required by `&&&&&Enumerate>: IntoIterator` = note: required for `&&&&&Enumerate>` to implement `IntoIterator` help: consider removing 5 leading `&`-references | diff --git a/tests/ui/suggestions/suggest-remove-refs-4.stderr b/tests/ui/suggestions/suggest-remove-refs-4.stderr index ed9fc2dd2568b..7ab34c4af511c 100644 --- a/tests/ui/suggestions/suggest-remove-refs-4.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-4.stderr @@ -4,7 +4,7 @@ error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator LL | for _i in &foo {} | ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>` + = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`, which is required by `&&std::slice::Iter<'_, {integer}>: IntoIterator` = note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` help: consider removing 2 leading `&`-references | diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr index 7de84d6122b58..6b2f330e1a36d 100644 --- a/tests/ui/suggestions/suggest-remove-refs-5.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr @@ -4,7 +4,7 @@ error[E0277]: `Vec` is not an iterator LL | for _ in &mut &mut v {} | ^^^^^^^^^^^ `Vec` is not an iterator; try calling `.into_iter()` or `.iter()` | - = help: the trait `Iterator` is not implemented for `Vec` + = help: the trait `Iterator` is not implemented for `Vec`, which is required by `&mut &mut &mut &mut Vec: IntoIterator` = note: required for `&mut Vec` to implement `Iterator` = note: 3 redundant requirements hidden = note: required for `&mut &mut &mut &mut Vec` to implement `Iterator` @@ -21,7 +21,7 @@ error[E0277]: `[u8; 1]` is not an iterator LL | for _ in &mut v {} | ^^^^^^ `[u8; 1]` is not an iterator; try calling `.into_iter()` or `.iter()` | - = help: the trait `Iterator` is not implemented for `[u8; 1]` + = help: the trait `Iterator` is not implemented for `[u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator` = note: required for `&mut [u8; 1]` to implement `Iterator` = note: 2 redundant requirements hidden = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator` diff --git a/tests/ui/suggestions/suggest-slice-swap.fixed b/tests/ui/suggestions/suggest-slice-swap.fixed new file mode 100644 index 0000000000000..05b7ec2637985 --- /dev/null +++ b/tests/ui/suggestions/suggest-slice-swap.fixed @@ -0,0 +1,9 @@ +// run-rustfix +#![allow(dead_code)] + +fn swap(arr: &mut [u32; 2]) { + arr.swap(1, 0); + //~^ ERROR cannot borrow `arr[_]` as mutable more than once at a time +} + +fn main() {} diff --git a/tests/ui/suggestions/suggest-slice-swap.rs b/tests/ui/suggestions/suggest-slice-swap.rs new file mode 100644 index 0000000000000..9f3659aac1637 --- /dev/null +++ b/tests/ui/suggestions/suggest-slice-swap.rs @@ -0,0 +1,9 @@ +// run-rustfix +#![allow(dead_code)] + +fn swap(arr: &mut [u32; 2]) { + std::mem::swap(&mut arr[0], &mut arr[1]); + //~^ ERROR cannot borrow `arr[_]` as mutable more than once at a time +} + +fn main() {} diff --git a/tests/ui/suggestions/suggest-slice-swap.stderr b/tests/ui/suggestions/suggest-slice-swap.stderr new file mode 100644 index 0000000000000..2840fc0a76116 --- /dev/null +++ b/tests/ui/suggestions/suggest-slice-swap.stderr @@ -0,0 +1,17 @@ +error[E0499]: cannot borrow `arr[_]` as mutable more than once at a time + --> $DIR/suggest-slice-swap.rs:5:33 + | +LL | std::mem::swap(&mut arr[0], &mut arr[1]); + | -------------- ----------- ^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + | +help: use `.swap()` to swap elements at the specified indices instead + | +LL | arr.swap(1, 0); + | ~~~~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/symbol-mangling-version/bad-value.bad.stderr b/tests/ui/symbol-mangling-version/bad-value.bad.stderr index c36c73c6069f1..a12e5e241c022 100644 --- a/tests/ui/symbol-mangling-version/bad-value.bad.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected +error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - one of: `legacy`, `v0` (RFC 2603), or `hashed` was expected diff --git a/tests/ui/symbol-mangling-version/bad-value.blank.stderr b/tests/ui/symbol-mangling-version/bad-value.blank.stderr index 0e70af5b8ffbe..95456587781e6 100644 --- a/tests/ui/symbol-mangling-version/bad-value.blank.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.blank.stderr @@ -1,2 +1,2 @@ -error: incorrect value `` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected +error: incorrect value `` for codegen option `symbol-mangling-version` - one of: `legacy`, `v0` (RFC 2603), or `hashed` was expected diff --git a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr index 77013b72b6c1d..325e47a281fae 100644 --- a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr @@ -1,2 +1,2 @@ -error: codegen option `symbol-mangling-version` requires either `legacy` or `v0` (RFC 2603) (C symbol-mangling-version=) +error: codegen option `symbol-mangling-version` requires one of: `legacy`, `v0` (RFC 2603), or `hashed` (C symbol-mangling-version=) diff --git a/tests/ui/symbol-mangling-version/unstable.hashed.stderr b/tests/ui/symbol-mangling-version/unstable.hashed.stderr new file mode 100644 index 0000000000000..f2ae18290f261 --- /dev/null +++ b/tests/ui/symbol-mangling-version/unstable.hashed.stderr @@ -0,0 +1,2 @@ +error: `-C symbol-mangling-version=hashed` requires `-Z unstable-options` + diff --git a/tests/ui/symbol-mangling-version/unstable.rs b/tests/ui/symbol-mangling-version/unstable.rs index df87a39cdfbd1..42750a64574dc 100644 --- a/tests/ui/symbol-mangling-version/unstable.rs +++ b/tests/ui/symbol-mangling-version/unstable.rs @@ -1,6 +1,9 @@ -// revisions: legacy legacy-ok +// revisions: legacy legacy-ok hashed hashed-ok // [legacy] compile-flags: -Csymbol-mangling-version=legacy // [legacy-ok] check-pass // [legacy-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=legacy +// [hashed] compile-flags: -Csymbol-mangling-version=hashed +// [hashed-ok] check-pass +// [hashed-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=hashed fn main() {} diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index 61d27ec69f4d2..c1cbefac828d6 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h9308686d0228fa1dE) +error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h9308686d0228fa1d) +error: demangling(basic::main::h6fc0c8d27b1a289f) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.stderr b/tests/ui/symbol-names/const-generics-structural-demangling.stderr index 96dea154d05c0..270c126e3f553 100644 --- a/tests/ui/symbol-names/const-generics-structural-demangling.stderr +++ b/tests/ui/symbol-names/const-generics-structural-demangling.stderr @@ -124,7 +124,7 @@ error: demangling-alt(_4Bar_KVNtB_3BarS1xh7b_s_1xt1000_EE) +error: symbol-name(_RMsd_CsCRATE_HASH_1cINtB_4Bar_KVNtB_3BarS1xh7b_s_1xt1000_EE) --> $DIR/const-generics-structural-demangling.rs:93:5 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index eb65f3b58fff8..7dd68e6e3a8e2 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h84ab5dafbd2a1508E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::h84ab5dafbd2a1508) +error: demangling(issue_60925::foo::Foo::foo::hab58a402db4ebf3a) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/sync/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr index 1501a793d5e8b..6b686741d1f82 100644 --- a/tests/ui/sync/mutexguard-sync.stderr +++ b/tests/ui/sync/mutexguard-sync.stderr @@ -6,7 +6,7 @@ LL | test_sync(guard); | | | required by a bound introduced by this call | - = help: the trait `Sync` is not implemented for `Cell` + = help: the trait `Sync` is not implemented for `Cell`, which is required by `MutexGuard<'_, Cell>: Sync` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `MutexGuard<'_, Cell>` to implement `Sync` note: required by a bound in `test_sync` diff --git a/tests/ui/tag-type-args.stderr b/tests/ui/tag-type-args.stderr index 80ffd3a2f0500..a1136f61cc52f 100644 --- a/tests/ui/tag-type-args.stderr +++ b/tests/ui/tag-type-args.stderr @@ -14,14 +14,14 @@ help: add missing generic argument LL | fn foo(c: Quux) { assert!((false)); } | +++ -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/tag-type-args.rs:1:11 | LL | enum Quux { Bar } - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead error: aborting due to 2 previous errors diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index af530cc1a0b8f..c7415818e10f5 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -6,6 +6,7 @@ // exec-env:RUST_BACKTRACE=0 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// ignore-android #120567 // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support // ignore-sgx no subprocess support diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 6997833834df6..16001b3eecd4d 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:33:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:27:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 08e5242af66f9..d80e2435614dc 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -6,6 +6,7 @@ // exec-env:RUST_BACKTRACE=0 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// ignore-android #120567 // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support // ignore-sgx no subprocess support diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 0e27f6fb655b0..f5d14e77da963 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -17,7 +17,7 @@ hello, world testing123 ---- it_fails stderr ---- testing321 -thread 'main' panicked at $DIR/test-panic-abort.rs:38:5: +thread 'main' panicked at $DIR/test-panic-abort.rs:39:5: assertion `left == right` failed left: 2 right: 5 diff --git a/tests/ui/threads-sendsync/sync-send-atomics.rs b/tests/ui/threads-sendsync/sync-send-atomics.rs index 0466f4f0e9ddc..6b260311a50a7 100644 --- a/tests/ui/threads-sendsync/sync-send-atomics.rs +++ b/tests/ui/threads-sendsync/sync-send-atomics.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 diff --git a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr index 84c2ab68da958..397e80197b952 100644 --- a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr +++ b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its tra --> $DIR/impl-derived-implicit-sized-bound-2.rs:28:19 | LL | struct Victim<'a, T: Perpetrator + ?Sized> { - | ------------------------------------------ - | | - | method `get` not found for this struct - | doesn't satisfy `Victim<'_, Self>: VictimTrait` + | ------------------------------------------ method `get` not found for this struct because it doesn't satisfy `Victim<'_, Self>: VictimTrait` ... LL | self.getter().get(); | ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds diff --git a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr index c597ad0b572ee..abcd915c699c4 100644 --- a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr +++ b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its tra --> $DIR/impl-derived-implicit-sized-bound.rs:31:19 | LL | struct Victim<'a, T: Perpetrator + ?Sized> - | ------------------------------------------ - | | - | method `get` not found for this struct - | doesn't satisfy `Victim<'_, Self>: VictimTrait` + | ------------------------------------------ method `get` not found for this struct because it doesn't satisfy `Victim<'_, Self>: VictimTrait` ... LL | self.getter().get(); | ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds diff --git a/tests/ui/trait-bounds/issue-119530-sugg-from-fn.rs b/tests/ui/trait-bounds/issue-119530-sugg-from-fn.rs new file mode 100644 index 0000000000000..cfe378f55b1ee --- /dev/null +++ b/tests/ui/trait-bounds/issue-119530-sugg-from-fn.rs @@ -0,0 +1,5 @@ +fn foo() -> String { String::new() } + +fn main() { + let string_arr = [foo(); 64]; //~ ERROR the trait bound `String: Copy` is not satisfied +} diff --git a/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr b/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr new file mode 100644 index 0000000000000..9217637901b85 --- /dev/null +++ b/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/issue-119530-sugg-from-fn.rs:4:23 + | +LL | let string_arr = [foo(); 64]; + | ^^^^^ the trait `Copy` is not implemented for `String` + | + = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider using `core::array::from_fn` to initialize the array + = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trait-bounds/unsized-bound.stderr b/tests/ui/trait-bounds/unsized-bound.stderr index 4d45bffabce5e..c8049ebee1173 100644 --- a/tests/ui/trait-bounds/unsized-bound.stderr +++ b/tests/ui/trait-bounds/unsized-bound.stderr @@ -7,11 +7,11 @@ LL | impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} | this type parameter needs to be `Sized` | = note: required because it appears within the type `(A, B)` -note: required by a bound in `Trait` +note: required by an implicit `Sized` bound in `Trait` --> $DIR/unsized-bound.rs:1:13 | LL | trait Trait {} - | ^ required by this bound in `Trait` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} @@ -46,11 +46,11 @@ LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Size | this type parameter needs to be `Sized` | = note: required because it appears within the type `(A, B, C)` -note: required by a bound in `Trait` +note: required by an implicit `Sized` bound in `Trait` --> $DIR/unsized-bound.rs:1:13 | LL | trait Trait {} - | ^ required by this bound in `Trait` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} @@ -96,11 +96,11 @@ LL | impl Trait2<(A, B)> for (A, B) {} | this type parameter needs to be `Sized` | = note: required because it appears within the type `(A, B)` -note: required by a bound in `Trait2` +note: required by an implicit `Sized` bound in `Trait2` --> $DIR/unsized-bound.rs:9:14 | LL | trait Trait2 {} - | ^ required by this bound in `Trait2` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait2` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait2<(A, B)> for (A, B) {} @@ -134,11 +134,11 @@ LL | impl Trait3 for A where A: ?Sized {} | | | this type parameter needs to be `Sized` | -note: required by a bound in `Trait3` +note: required by an implicit `Sized` bound in `Trait3` --> $DIR/unsized-bound.rs:13:14 | LL | trait Trait3 {} - | ^ required by this bound in `Trait3` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait3` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait3 for A where A: ?Sized {} @@ -157,11 +157,11 @@ LL | impl Trait4 for A {} | | | this type parameter needs to be `Sized` | -note: required by a bound in `Trait4` +note: required by an implicit `Sized` bound in `Trait4` --> $DIR/unsized-bound.rs:16:14 | LL | trait Trait4 {} - | ^ required by this bound in `Trait4` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait4` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait4 for A {} @@ -180,11 +180,11 @@ LL | impl Trait5 for X where X: ?Sized {} | | | this type parameter needs to be `Sized` | -note: required by a bound in `Trait5` +note: required by an implicit `Sized` bound in `Trait5` --> $DIR/unsized-bound.rs:19:14 | LL | trait Trait5 {} - | ^ required by this bound in `Trait5` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait5` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait5 for X where X: ?Sized {} @@ -203,11 +203,11 @@ LL | impl Trait6 for X {} | | | this type parameter needs to be `Sized` | -note: required by a bound in `Trait6` +note: required by an implicit `Sized` bound in `Trait6` --> $DIR/unsized-bound.rs:22:14 | LL | trait Trait6 {} - | ^ required by this bound in `Trait6` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait6` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait6 for X {} @@ -226,11 +226,11 @@ LL | impl Trait7 for X where Y: ?Sized {} | | | this type parameter needs to be `Sized` | -note: required by a bound in `Trait7` +note: required by an implicit `Sized` bound in `Trait7` --> $DIR/unsized-bound.rs:25:17 | LL | trait Trait7 {} - | ^ required by this bound in `Trait7` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait7` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait7 for X where Y: ?Sized {} @@ -249,11 +249,11 @@ LL | impl Trait8 for X {} | | | this type parameter needs to be `Sized` | -note: required by a bound in `Trait8` +note: required by an implicit `Sized` bound in `Trait8` --> $DIR/unsized-bound.rs:28:17 | LL | trait Trait8 {} - | ^ required by this bound in `Trait8` + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait8` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Trait8 for X {} diff --git a/tests/ui/traits/alias/bounds.rs b/tests/ui/traits/alias/bounds.rs index b97eb38c5af8d..7b1920bc8f27c 100644 --- a/tests/ui/traits/alias/bounds.rs +++ b/tests/ui/traits/alias/bounds.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; -trait Empty {} +trait Empty {} //~ WARN trait `Empty` is never used trait EmptyAlias = Empty; trait CloneDefault = Clone + Default; trait SendSyncAlias = Send + Sync; diff --git a/tests/ui/traits/alias/bounds.stderr b/tests/ui/traits/alias/bounds.stderr new file mode 100644 index 0000000000000..7fb8e918da36d --- /dev/null +++ b/tests/ui/traits/alias/bounds.stderr @@ -0,0 +1,10 @@ +warning: trait `Empty` is never used + --> $DIR/bounds.rs:7:7 + | +LL | trait Empty {} + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/alias/cross-crate.stderr b/tests/ui/traits/alias/cross-crate.stderr index ae9d7d0a9b4a4..fd614b4bcd58a 100644 --- a/tests/ui/traits/alias/cross-crate.stderr +++ b/tests/ui/traits/alias/cross-crate.stderr @@ -4,7 +4,7 @@ error[E0277]: `Rc` cannot be sent between threads safely LL | use_alias::>(); | ^^^^^^^ `Rc` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `Rc` + = help: the trait `Send` is not implemented for `Rc`, which is required by `Rc: SendSync` = note: required for `Rc` to implement `SendSync` note: required by a bound in `use_alias` --> $DIR/cross-crate.rs:10:17 @@ -18,7 +18,7 @@ error[E0277]: `Rc` cannot be shared between threads safely LL | use_alias::>(); | ^^^^^^^ `Rc` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `Rc` + = help: the trait `Sync` is not implemented for `Rc`, which is required by `Rc: SendSync` = note: required for `Rc` to implement `SendSync` note: required by a bound in `use_alias` --> $DIR/cross-crate.rs:10:17 diff --git a/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr b/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr index 968ad2667a210..1e4f4cb70463c 100644 --- a/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr +++ b/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr @@ -6,7 +6,7 @@ LL | f(()) | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()`, which is required by `(): IteratorAlias` = note: required for `()` to implement `IteratorAlias` note: required by a bound in `f` --> $DIR/issue-108072-unmet-trait-alias-bound.rs:7:14 diff --git a/tests/ui/traits/alias/syntax.rs b/tests/ui/traits/alias/syntax.rs index 17557a51aa723..50c77d33c6bce 100644 --- a/tests/ui/traits/alias/syntax.rs +++ b/tests/ui/traits/alias/syntax.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(trait_alias)] diff --git a/tests/ui/traits/bad-sized.stderr b/tests/ui/traits/bad-sized.stderr index fb9900bc57bbc..4c1835dfed085 100644 --- a/tests/ui/traits/bad-sized.stderr +++ b/tests/ui/traits/bad-sized.stderr @@ -16,14 +16,14 @@ LL | let x: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn Trait` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 | LL | let x: Vec = Vec::new(); - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn Trait` note: required by a bound in `Vec::::new` @@ -36,7 +36,7 @@ LL | let x: Vec = Vec::new(); | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn Trait` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error: aborting due to 4 previous errors diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index c8631ed3677e8..bd9838bc62354 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -4,7 +4,7 @@ error[E0277]: expected a `FnMut(char)` closure, found `u8` LL | s.strip_suffix(b'\n').unwrap_or(s) | ^^^^^^^^^^^^ expected an `FnMut(char)` closure, found `u8` | - = help: the trait `FnMut<(char,)>` is not implemented for `u8` + = help: the trait `FnMut<(char,)>` is not implemented for `u8`, which is required by `u8: Pattern<'_>` = help: the following other types implement trait `Pattern<'a>`: char [char; N] diff --git a/tests/ui/traits/bound/impl-comparison-duplicates.rs b/tests/ui/traits/bound/impl-comparison-duplicates.rs index de6c2afa2bbe1..a59662c2797ff 100644 --- a/tests/ui/traits/bound/impl-comparison-duplicates.rs +++ b/tests/ui/traits/bound/impl-comparison-duplicates.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Tests that type parameter bounds on an implementation need not match the // trait exactly, as long as the implementation doesn't demand *more* bounds // than the trait. diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr index 8d0e40be788c1..6d56851bf3495 100644 --- a/tests/ui/traits/bound/not-on-bare-trait.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait.stderr @@ -7,18 +7,10 @@ LL | fn foo(_x: Foo + Send) { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: use a new generic type parameter, constrained by `Foo + Send` +help: use `dyn` | -LL | fn foo(_x: T) { - | +++++++++++++++ ~ -help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference - | -LL | fn foo(_x: impl Foo + Send) { - | ++++ -help: alternatively, use a trait object to accept any type that implements `Foo + Send`, accessing its methods at runtime using dynamic dispatch - | -LL | fn foo(_x: &(dyn Foo + Send)) { - | +++++ + +LL | fn foo(_x: dyn Foo + Send) { + | +++ error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time --> $DIR/not-on-bare-trait.rs:7:8 diff --git a/tests/ui/traits/bound/recursion.rs b/tests/ui/traits/bound/recursion.rs index 0023ff654e84c..767040dff3f73 100644 --- a/tests/ui/traits/bound/recursion.rs +++ b/tests/ui/traits/bound/recursion.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait I { fn i(&self) -> Self; } diff --git a/tests/ui/traits/composition-trivial.rs b/tests/ui/traits/composition-trivial.rs index 90e5dcd68e8c4..41e6a55607449 100644 --- a/tests/ui/traits/composition-trivial.rs +++ b/tests/ui/traits/composition-trivial.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/traits/copy-impl-cannot-normalize.stderr b/tests/ui/traits/copy-impl-cannot-normalize.stderr index 3bdb8b70172c4..a98bb47f54fc1 100644 --- a/tests/ui/traits/copy-impl-cannot-normalize.stderr +++ b/tests/ui/traits/copy-impl-cannot-normalize.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: TraitFoo` is not satisfied --> $DIR/copy-impl-cannot-normalize.rs:22:18 | LL | impl Copy for Foo {} - | ^^^^^^ the trait `TraitFoo` is not implemented for `T` + | ^^^^^^ the trait `TraitFoo` is not implemented for `T`, which is required by `Foo: Clone` | note: required for `Foo` to implement `Clone` --> $DIR/copy-impl-cannot-normalize.rs:12:9 diff --git a/tests/ui/traits/cycle-generic-bound.rs b/tests/ui/traits/cycle-generic-bound.rs index 9241f3789d72a..77685c26da242 100644 --- a/tests/ui/traits/cycle-generic-bound.rs +++ b/tests/ui/traits/cycle-generic-bound.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Regression test for #15477. This test just needs to compile. // pretty-expanded FIXME #23616 diff --git a/tests/ui/traits/default-method/bound-subst4.rs b/tests/ui/traits/default-method/bound-subst4.rs index ef13306458255..6bc4cf0ef805c 100644 --- a/tests/ui/traits/default-method/bound-subst4.rs +++ b/tests/ui/traits/default-method/bound-subst4.rs @@ -4,7 +4,7 @@ trait A { fn g(&self, x: usize) -> usize { x } - fn h(&self, x: T) { } + fn h(&self, x: T) { } //~ WARN method `h` is never used } impl A for isize { } diff --git a/tests/ui/traits/default-method/bound-subst4.stderr b/tests/ui/traits/default-method/bound-subst4.stderr new file mode 100644 index 0000000000000..548c46f123322 --- /dev/null +++ b/tests/ui/traits/default-method/bound-subst4.stderr @@ -0,0 +1,13 @@ +warning: method `h` is never used + --> $DIR/bound-subst4.rs:7:8 + | +LL | trait A { + | - method in this trait +LL | fn g(&self, x: usize) -> usize { x } +LL | fn h(&self, x: T) { } + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/default-method/mut.rs b/tests/ui/traits/default-method/mut.rs index 5f8e983b09cfb..3294b96561fd1 100644 --- a/tests/ui/traits/default-method/mut.rs +++ b/tests/ui/traits/default-method/mut.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_assignments)] // pretty-expanded FIXME #23616 diff --git a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr index a5d0e6ab09569..fecb05cade758 100644 --- a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr +++ b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr @@ -8,7 +8,7 @@ error[E0277]: the trait bound `for<'a> &'a mut Vec<&'a u32>: Foo<'static, i32>` --> $DIR/dont-autoderef-ty-with-escaping-var.rs:17:6 | LL | >::ref_foo(unknown); - | ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>` + | ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>`, which is required by `i32: RefFoo` | help: this trait has no implementations, consider adding one --> $DIR/dont-autoderef-ty-with-escaping-var.rs:3:1 diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.rs b/tests/ui/traits/impl-inherent-prefer-over-trait.rs index 82760788897a5..f03e730d091eb 100644 --- a/tests/ui/traits/impl-inherent-prefer-over-trait.rs +++ b/tests/ui/traits/impl-inherent-prefer-over-trait.rs @@ -3,7 +3,7 @@ struct Foo; trait Trait { - fn bar(&self); + fn bar(&self); //~ WARN method `bar` is never used } // Inherent impls should be preferred over trait ones. diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.stderr b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr new file mode 100644 index 0000000000000..f0bb21402d873 --- /dev/null +++ b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr @@ -0,0 +1,12 @@ +warning: method `bar` is never used + --> $DIR/impl-inherent-prefer-over-trait.rs:6:8 + | +LL | trait Trait { + | ----- method in this trait +LL | fn bar(&self); + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.rs b/tests/ui/traits/impl-object-overlap-issue-23853.rs index e490967b69047..c0d3af11443d4 100644 --- a/tests/ui/traits/impl-object-overlap-issue-23853.rs +++ b/tests/ui/traits/impl-object-overlap-issue-23853.rs @@ -5,7 +5,7 @@ // including `Bar`, but the object type `Bar` also implicitly supplies // this context. -trait Foo { fn dummy(&self) { } } +trait Foo { fn dummy(&self) { } } //~ WARN method `dummy` is never used trait Bar: Foo { } diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.stderr b/tests/ui/traits/impl-object-overlap-issue-23853.stderr new file mode 100644 index 0000000000000..9fa7a36816e4d --- /dev/null +++ b/tests/ui/traits/impl-object-overlap-issue-23853.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/impl-object-overlap-issue-23853.rs:8:16 + | +LL | trait Foo { fn dummy(&self) { } } + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/impl.rs b/tests/ui/traits/impl.rs index f512d91ebeb4a..7bec1b6c9ff4f 100644 --- a/tests/ui/traits/impl.rs +++ b/tests/ui/traits/impl.rs @@ -9,7 +9,7 @@ use traitimpl::Bar; static mut COUNT: usize = 1; trait T { - fn t(&self) {} + fn t(&self) {} //~ WARN method `t` is never used } impl<'a> dyn T+'a { diff --git a/tests/ui/traits/impl.stderr b/tests/ui/traits/impl.stderr new file mode 100644 index 0000000000000..98b6fb03d836f --- /dev/null +++ b/tests/ui/traits/impl.stderr @@ -0,0 +1,12 @@ +warning: method `t` is never used + --> $DIR/impl.rs:12:8 + | +LL | trait T { + | - method in this trait +LL | fn t(&self) {} + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/inductive-overflow/lifetime.stderr b/tests/ui/traits/inductive-overflow/lifetime.stderr index b34bb0361f1e4..406f4d25dce3f 100644 --- a/tests/ui/traits/inductive-overflow/lifetime.stderr +++ b/tests/ui/traits/inductive-overflow/lifetime.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow evaluating the requirement `Box>>: NotAuto` --> $DIR/lifetime.rs:29:5 | LL | is_send::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required for `X>` to implement `NotAuto` --> $DIR/lifetime.rs:19:12 diff --git a/tests/ui/traits/inductive-overflow/simultaneous.stderr b/tests/ui/traits/inductive-overflow/simultaneous.stderr index b9a746e44ba01..29456d88b1bfc 100644 --- a/tests/ui/traits/inductive-overflow/simultaneous.stderr +++ b/tests/ui/traits/inductive-overflow/simultaneous.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow evaluating the requirement `{integer}: Tweedledum` --> $DIR/simultaneous.rs:18:5 | LL | is_ee(4); - | ^^^^^ + | ^^^^^^^^ | note: required for `{integer}` to implement `Combo` --> $DIR/simultaneous.rs:11:34 diff --git a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr index e723c7c51814a..629ccac49c56a 100644 --- a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr +++ b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr @@ -10,7 +10,7 @@ error[E0277]: the trait bound `NoClone: Copy` is not satisfied --> $DIR/supertrait-auto-trait.rs:16:23 | LL | let (a, b) = copy(NoClone); - | ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone` + | ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone`, which is required by `NoClone: Magic` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/inductive-overflow/supertrait.stderr b/tests/ui/traits/inductive-overflow/supertrait.stderr index f2dccbbbb2cb6..99e9c8f93b8a4 100644 --- a/tests/ui/traits/inductive-overflow/supertrait.stderr +++ b/tests/ui/traits/inductive-overflow/supertrait.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow evaluating the requirement `NoClone: Magic` --> $DIR/supertrait.rs:13:18 | LL | let (a, b) = copy(NoClone); - | ^^^^ + | ^^^^^^^^^^^^^ | note: required for `NoClone` to implement `Magic` --> $DIR/supertrait.rs:5:16 diff --git a/tests/ui/traits/inductive-overflow/two-traits.stderr b/tests/ui/traits/inductive-overflow/two-traits.stderr index 0d0bf88616c86..6092c194a8757 100644 --- a/tests/ui/traits/inductive-overflow/two-traits.stderr +++ b/tests/ui/traits/inductive-overflow/two-traits.stderr @@ -18,7 +18,7 @@ error[E0275]: overflow evaluating the requirement `*mut (): Magic` --> $DIR/two-traits.rs:20:5 | LL | wizard::<*mut ()>(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `wizard` --> $DIR/two-traits.rs:17:14 diff --git a/tests/ui/traits/invalid_operator_trait.rs b/tests/ui/traits/invalid_operator_trait.rs deleted file mode 100644 index 7ea3b0d5bac76..0000000000000 --- a/tests/ui/traits/invalid_operator_trait.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![crate_type = "lib"] -#![feature(lang_items)] -#![feature(no_core)] -#![no_core] - -#[lang="sized"] -pub trait Sized { - // Empty. -} - -#[lang = "add"] -trait Add { - type Output; - - fn add(self, _: RHS) -> Self::Output; - //~^ ERROR `add` must not have any generic parameters -} - -#[allow(unreachable_code)] -fn ice(a: usize) { - let r = loop {}; - r = r + a; -} diff --git a/tests/ui/traits/invalid_operator_trait.stderr b/tests/ui/traits/invalid_operator_trait.stderr deleted file mode 100644 index f2e5e9080b16e..0000000000000 --- a/tests/ui/traits/invalid_operator_trait.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `add` must not have any generic parameters - --> $DIR/invalid_operator_trait.rs:15:5 - | -LL | fn add(self, _: RHS) -> Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/traits/issue-102989.rs b/tests/ui/traits/issue-102989.rs deleted file mode 100644 index f1ecee0a552a7..0000000000000 --- a/tests/ui/traits/issue-102989.rs +++ /dev/null @@ -1,15 +0,0 @@ -// normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" - -#![feature(lang_items)] -#[lang="sized"] -trait Sized { } //~ ERROR found duplicate lang item `sized` - -fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - //~^ ERROR `self` parameter is only allowed in associated functions - //~| ERROR cannot find type `Struct` in this scope - //~| ERROR mismatched types - let x = x << 1; - //~^ ERROR cannot find value `x` in this scope -} - -fn main() {} diff --git a/tests/ui/traits/issue-102989.stderr b/tests/ui/traits/issue-102989.stderr deleted file mode 100644 index 40e49df2b2d96..0000000000000 --- a/tests/ui/traits/issue-102989.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: `self` parameter is only allowed in associated functions - --> $DIR/issue-102989.rs:7:15 - | -LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ^^^^ not semantically valid as function parameter - | - = note: associated functions are those in `impl` or `trait` definitions - -error[E0412]: cannot find type `Struct` in this scope - --> $DIR/issue-102989.rs:7:22 - | -LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ^^^^^^ not found in this scope - -error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-102989.rs:11:13 - | -LL | let x = x << 1; - | ^ help: a local variable with a similar name exists: `f` - -error[E0152]: found duplicate lang item `sized` - --> $DIR/issue-102989.rs:5:1 - | -LL | trait Sized { } - | ^^^^^^^^^^^^^^^ - | - = note: the lang item is first defined in crate `core` (which `std` depends on) - = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib - = note: second definition in the local crate (`issue_102989`) - -error[E0308]: mismatched types - --> $DIR/issue-102989.rs:7:42 - | -LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ---------- ^^^^ expected `&u32`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - | -help: consider returning the local binding `f` - | -LL ~ let x = x << 1; -LL + f - | - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0152, E0308, E0412, E0425. -For more information about an error, try `rustc --explain E0152`. diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr index 96e8aaee23d56..adba5830b10e1 100644 --- a/tests/ui/traits/issue-28576.stderr +++ b/tests/ui/traits/issue-28576.stderr @@ -25,11 +25,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | pub trait Bar: Foo { | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Foo` +note: required by an implicit `Sized` bound in `Foo` --> $DIR/issue-28576.rs:1:15 | LL | pub trait Foo { - | ^^^^^^^^ required by this bound in `Foo` + | ^^^^^^^^ required by the implicit `Sized` requirement on this type parameter in `Foo` help: consider further restricting `Self` | LL | pub trait Bar: Foo + Sized { @@ -45,11 +45,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | pub trait Bar: Foo { | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Foo` +note: required by an implicit `Sized` bound in `Foo` --> $DIR/issue-28576.rs:1:15 | LL | pub trait Foo { - | ^^^^^^^^ required by this bound in `Foo` + | ^^^^^^^^ required by the implicit `Sized` requirement on this type parameter in `Foo` help: consider further restricting `Self` | LL | ) where Self: Sized; diff --git a/tests/ui/traits/issue-38033.rs b/tests/ui/traits/issue-38033.rs index 16b867ec88f17..4d76df1e8d5bc 100644 --- a/tests/ui/traits/issue-38033.rs +++ b/tests/ui/traits/issue-38033.rs @@ -19,7 +19,7 @@ trait IntoFuture { type Item; type Error; - fn into_future(self) -> Self::Future; + fn into_future(self) -> Self::Future; //~ WARN method `into_future` is never used } impl IntoFuture for F { diff --git a/tests/ui/traits/issue-38033.stderr b/tests/ui/traits/issue-38033.stderr new file mode 100644 index 0000000000000..05385e8cf4d9d --- /dev/null +++ b/tests/ui/traits/issue-38033.stderr @@ -0,0 +1,13 @@ +warning: method `into_future` is never used + --> $DIR/issue-38033.rs:22:8 + | +LL | trait IntoFuture { + | ---------- method in this trait +... +LL | fn into_future(self) -> Self::Future; + | ^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr index 2bf365745a6bd..4c565c3fa1db5 100644 --- a/tests/ui/traits/issue-43784-supertrait.stderr +++ b/tests/ui/traits/issue-43784-supertrait.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-supertrait.rs:8:22 | LL | impl Complete for T {} - | ^ the trait `Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T`, which is required by `T: Partial` | note: required for `T` to implement `Partial` --> $DIR/issue-43784-supertrait.rs:1:11 diff --git a/tests/ui/traits/issue-56488.rs b/tests/ui/traits/issue-56488.rs index e2f3996927b7f..8b68f314c04dd 100644 --- a/tests/ui/traits/issue-56488.rs +++ b/tests/ui/traits/issue-56488.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(trait_alias)] diff --git a/tests/ui/traits/issue-59029-2.rs b/tests/ui/traits/issue-59029-2.rs index 2bdb128d8c4c8..fca9f1f13c9de 100644 --- a/tests/ui/traits/issue-59029-2.rs +++ b/tests/ui/traits/issue-59029-2.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(trait_alias)] trait Svc { type Res; } diff --git a/tests/ui/traits/issue-6128.rs b/tests/ui/traits/issue-6128.rs index 07d92f8f8a016..f5fa0de809a19 100644 --- a/tests/ui/traits/issue-6128.rs +++ b/tests/ui/traits/issue-6128.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; trait Graph { - fn f(&self, _: Edge); + fn f(&self, _: Edge); //~ WARN methods `f` and `g` are never used fn g(&self, _: Node); } diff --git a/tests/ui/traits/issue-6128.stderr b/tests/ui/traits/issue-6128.stderr new file mode 100644 index 0000000000000..c9518ea41ea70 --- /dev/null +++ b/tests/ui/traits/issue-6128.stderr @@ -0,0 +1,14 @@ +warning: methods `f` and `g` are never used + --> $DIR/issue-6128.rs:6:8 + | +LL | trait Graph { + | ----- methods in this trait +LL | fn f(&self, _: Edge); + | ^ +LL | fn g(&self, _: Node); + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/issue-7013.stderr b/tests/ui/traits/issue-7013.stderr index 1749366317286..5067c7d7dd7d7 100644 --- a/tests/ui/traits/issue-7013.stderr +++ b/tests/ui/traits/issue-7013.stderr @@ -4,7 +4,7 @@ error[E0277]: `Rc>` cannot be sent between threads safely LL | let a = A {v: Box::new(B{v: None}) as Box}; | ^^^^^^^^^^^^^^^^^^^^ `Rc>` cannot be sent between threads safely | - = help: within `B`, the trait `Send` is not implemented for `Rc>` + = help: within `B`, the trait `Send` is not implemented for `Rc>`, which is required by `B: Send` note: required because it appears within the type `Option>>` --> $SRC_DIR/core/src/option.rs:LL:COL note: required because it appears within the type `B` diff --git a/tests/ui/traits/issue-71036.stderr b/tests/ui/traits/issue-71036.stderr index 2452731f19f16..35d543eb0177a 100644 --- a/tests/ui/traits/issue-71036.stderr +++ b/tests/ui/traits/issue-71036.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied --> $DIR/issue-71036.rs:11:1 | LL | impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`, which is required by `&'a &'a T: DispatchFromDyn<&'a &'a U>` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information = note: required for `&'a &'a T` to implement `DispatchFromDyn<&'a &'a U>` diff --git a/tests/ui/traits/issue-71136.stderr b/tests/ui/traits/issue-71136.stderr index 2c03c6bf08ed8..d37ad8ae34d0d 100644 --- a/tests/ui/traits/issue-71136.stderr +++ b/tests/ui/traits/issue-71136.stderr @@ -5,7 +5,7 @@ LL | #[derive(Clone)] | ----- in this derive macro expansion LL | struct FooHolster { LL | the_foos: Vec, - | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`, which is required by `Vec: Clone` | = note: required for `Vec` to implement `Clone` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index 592cfd970c64a..bffad037fba05 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -44,8 +44,9 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect( | type must be known at this point | = note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate: + - impl From for u32; - impl From for u32; - - impl From for u32; + - impl From> for u32; - impl From for u32; - impl From for u32; - impl From for u32; diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.rs b/tests/ui/traits/issue-85360-eval-obligation-ice.rs index ac8bda9c01042..75483a810949d 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.rs +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.rs @@ -8,11 +8,9 @@ use core::marker::PhantomData; fn main() { test::>>(make()); //~^ ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) test::>>(make()); //~^ ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) - //~| ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) } #[rustc_evaluate_where_clauses] diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.stderr b/tests/ui/traits/issue-85360-eval-obligation-ice.stderr index 9590ea12c05e4..d2b00a45a4f15 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.stderr +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.stderr @@ -1,12 +1,3 @@ -error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) - --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 - | -LL | test::>>(make()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn test(_: T) {} - | - predicate - error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | @@ -17,16 +8,7 @@ LL | fn test(_: T) {} | ----- predicate error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) - --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 - | -LL | test::>>(make()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn test(_: T) {} - | - predicate - -error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) - --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 + --> $DIR/issue-85360-eval-obligation-ice.rs:12:5 | LL | test::>>(make()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,5 +16,5 @@ LL | test::>>(make()); LL | fn test(_: T) {} | ----- predicate -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-91594.stderr b/tests/ui/traits/issue-91594.stderr index 13568179e81f4..726ee5b61461b 100644 --- a/tests/ui/traits/issue-91594.stderr +++ b/tests/ui/traits/issue-91594.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied --> $DIR/issue-91594.rs:10:19 | LL | impl HasComponent<>::Interface> for Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`, which is required by `Foo: Component` | = help: the trait `HasComponent<>::Interface>` is implemented for `Foo` note: required for `Foo` to implement `Component` diff --git a/tests/ui/traits/issue-97576.stderr b/tests/ui/traits/issue-97576.stderr index 2c6cfd83b9571..bee254461f1bd 100644 --- a/tests/ui/traits/issue-97576.stderr +++ b/tests/ui/traits/issue-97576.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: From` is not satisfied --> $DIR/issue-97576.rs:8:22 | LL | bar: bar.into(), - | ^^^^ the trait `From` is not implemented for `String` + | ^^^^ the trait `From` is not implemented for `String`, which is required by `impl ToString: Into<_>` | = note: required for `impl ToString` to implement `Into` diff --git a/tests/ui/traits/method-on-unbounded-type-param.rs b/tests/ui/traits/method-on-unbounded-type-param.rs new file mode 100644 index 0000000000000..8505eb41e98bb --- /dev/null +++ b/tests/ui/traits/method-on-unbounded-type-param.rs @@ -0,0 +1,15 @@ +fn f(a: T, b: T) -> std::cmp::Ordering { + a.cmp(&b) //~ ERROR E0599 +} +fn g(a: T, b: T) -> std::cmp::Ordering { + (&a).cmp(&b) //~ ERROR E0599 +} +fn h(a: &T, b: T) -> std::cmp::Ordering { + a.cmp(&b) //~ ERROR E0599 +} +trait T {} +impl T for X {} +fn main() { + let x: Box = Box::new(0); + x.cmp(&x); //~ ERROR E0599 +} diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr new file mode 100644 index 0000000000000..0d8bd8ee964e7 --- /dev/null +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -0,0 +1,84 @@ +error[E0599]: no method named `cmp` found for type parameter `T` in the current scope + --> $DIR/method-on-unbounded-type-param.rs:2:7 + | +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | - method `cmp` not found for this type parameter +LL | a.cmp(&b) + | ^^^ method cannot be called on `T` due to unsatisfied trait bounds + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: + | +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | ++++++++++ + +error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied + --> $DIR/method-on-unbounded-type-param.rs:5:10 + | +LL | (&a).cmp(&b) + | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Ord` + which is required by `&T: Ord` + `&T: Iterator` + which is required by `&mut &T: Iterator` + `T: Iterator` + which is required by `&mut T: Iterator` + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: + | +LL | fn g(a: T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn g(a: T, b: T) -> std::cmp::Ordering { + | ++++++++++ + +error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied + --> $DIR/method-on-unbounded-type-param.rs:8:7 + | +LL | a.cmp(&b) + | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Ord` + which is required by `&T: Ord` + `&T: Iterator` + which is required by `&mut &T: Iterator` + `T: Iterator` + which is required by `&mut T: Iterator` + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: + | +LL | fn h(a: &T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn h(a: &T, b: T) -> std::cmp::Ordering { + | ++++++++++ + +error[E0599]: the method `cmp` exists for struct `Box`, but its trait bounds were not satisfied + --> $DIR/method-on-unbounded-type-param.rs:14:7 + | +LL | trait T {} + | ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord` +... +LL | x.cmp(&x); + | ^^^ method cannot be called on `Box` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `dyn T: Iterator` + which is required by `Box: Iterator` + `dyn T: Ord` + which is required by `Box: Ord` + `Box: Iterator` + which is required by `&mut Box: Iterator` + `dyn T: Iterator` + which is required by `&mut dyn T: Iterator` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `cmp`, perhaps you need to implement one of them: + candidate #1: `Ord` + candidate #2: `Iterator` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs b/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs index f845e198aa574..e9ae8ab012a09 100644 --- a/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs +++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs @@ -6,7 +6,7 @@ use std::cell::RefCell; -trait Foo { +trait Foo { //~ WARN trait `Foo` is never used fn foo(&self) {} } diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr new file mode 100644 index 0000000000000..25313a477f7af --- /dev/null +++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/multidispatch-conditional-impl-not-considered.rs:9:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/multidispatch-infer-convert-target.rs b/tests/ui/traits/multidispatch-infer-convert-target.rs index 626e1ae71bc2f..a3653dea2cbdf 100644 --- a/tests/ui/traits/multidispatch-infer-convert-target.rs +++ b/tests/ui/traits/multidispatch-infer-convert-target.rs @@ -5,7 +5,7 @@ use std::mem; trait Convert { - fn convert(&self) -> Target; + fn convert(&self) -> Target; //~ WARN method `convert` is never used } impl Convert for i16 { diff --git a/tests/ui/traits/multidispatch-infer-convert-target.stderr b/tests/ui/traits/multidispatch-infer-convert-target.stderr new file mode 100644 index 0000000000000..c8c1b64271950 --- /dev/null +++ b/tests/ui/traits/multidispatch-infer-convert-target.stderr @@ -0,0 +1,12 @@ +warning: method `convert` is never used + --> $DIR/multidispatch-infer-convert-target.rs:8:8 + | +LL | trait Convert { + | ------- method in this trait +LL | fn convert(&self) -> Target; + | ^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/mutual-recursion-issue-75860.stderr b/tests/ui/traits/mutual-recursion-issue-75860.stderr index 420ed2dcd2f09..8f83bab003db3 100644 --- a/tests/ui/traits/mutual-recursion-issue-75860.stderr +++ b/tests/ui/traits/mutual-recursion-issue-75860.stderr @@ -5,7 +5,7 @@ LL | iso(left, right) | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`) -note: required by a bound in `Option` +note: required by an implicit `Sized` bound in `Option` --> $SRC_DIR/core/src/option.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr index 8f5b937e586ae..2a3833beb26b3 100644 --- a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -49,7 +49,7 @@ LL | is_send((8, TestType)); | | | required by a bound introduced by this call | - = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` + = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`, which is required by `({integer}, dummy1c::TestType): Send` = note: required because it appears within the type `({integer}, dummy1c::TestType)` note: required by a bound in `is_send` --> $DIR/negated-auto-traits-error.rs:16:15 @@ -87,7 +87,7 @@ LL | is_send(Box::new(Outer2(TestType))); | | | required by a bound introduced by this call | - = help: within `Outer2`, the trait `Send` is not implemented for `dummy3::TestType` + = help: within `Outer2`, the trait `Send` is not implemented for `dummy3::TestType`, which is required by `Box>: Send` note: required because it appears within the type `Outer2` --> $DIR/negated-auto-traits-error.rs:12:8 | @@ -110,7 +110,7 @@ LL | is_sync(Outer2(TestType)); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `main::TestType` + = help: the trait `Send` is not implemented for `main::TestType`, which is required by `Outer2: Sync` note: required for `Outer2` to implement `Sync` --> $DIR/negated-auto-traits-error.rs:14:22 | diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.rs b/tests/ui/traits/negative-impls/negative-specializes-negative.rs index 35297ab124ed0..01829e4130115 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-negative.rs +++ b/tests/ui/traits/negative-impls/negative-specializes-negative.rs @@ -3,7 +3,7 @@ // Test a negative impl that "specializes" another negative impl. // -// run-pass +// check-pass trait MyTrait {} diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.rs b/tests/ui/traits/next-solver/alias-bound-unsound.rs index 8fddbd7ecdcc8..a520bf6c25b04 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/next-solver/alias-bound-unsound.rs @@ -16,14 +16,13 @@ trait Foo { impl Foo for () { type Item = String where String: Copy; - //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy` + //~^ ERROR overflow evaluating the requirement `String: Copy` } fn main() { let x = String::from("hello, world"); drop(<() as Foo>::copy_me(&x)); - //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized` - //~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item` + //~^ ERROR overflow evaluating the requirement `String <: <() as Foo>::Item` //~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed` //~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed` //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr index 874644317ebd3..2408e05728a84 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr @@ -1,15 +1,17 @@ -error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy` - --> $DIR/alias-bound-unsound.rs:18:17 +error[E0275]: overflow evaluating the requirement `String: Copy` + --> $DIR/alias-bound-unsound.rs:18:38 | LL | type Item = String where String: Copy; - | ^^^^^^ + | ^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) -note: required by a bound in `Foo::Item` - --> $DIR/alias-bound-unsound.rs:8:16 +note: the requirement `String: Copy` appears on the `impl`'s associated type `Item` but not on the corresponding trait's associated type + --> $DIR/alias-bound-unsound.rs:8:10 | +LL | trait Foo { + | --- in this trait LL | type Item: Copy - | ^^^^ required by this bound in `Foo::Item` + | ^^^^ this trait's associated type doesn't have the requirement `String: Copy` error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item` --> $DIR/alias-bound-unsound.rs:24:31 @@ -27,15 +29,6 @@ LL | drop(<() as Foo>::copy_me(&x)); | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) -error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Sized` - --> $DIR/alias-bound-unsound.rs:24:10 - | -LL | drop(<() as Foo>::copy_me(&x)); - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) - = note: the return type of a function must have a statically known size - error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed` --> $DIR/alias-bound-unsound.rs:24:31 | @@ -61,6 +54,6 @@ LL | drop(<() as Foo>::copy_me(&x)); = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_cant_be_furthur_normalized.rs similarity index 100% rename from tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs rename to tests/ui/traits/next-solver/alias-relate/alias_eq_cant_be_furthur_normalized.rs diff --git a/tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_dont_use_normalizes_to_if_substs_eq.rs similarity index 100% rename from tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs rename to tests/ui/traits/next-solver/alias-relate/alias_eq_dont_use_normalizes_to_if_substs_eq.rs diff --git a/tests/ui/traits/next-solver/alias_eq_simple.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_simple.rs similarity index 100% rename from tests/ui/traits/next-solver/alias_eq_simple.rs rename to tests/ui/traits/next-solver/alias-relate/alias_eq_simple.rs diff --git a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.rs similarity index 100% rename from tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs rename to tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.rs diff --git a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.stderr similarity index 100% rename from tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr rename to tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.stderr diff --git a/tests/ui/traits/next-solver/tait-eq-proj-2.rs b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj-2.rs similarity index 84% rename from tests/ui/traits/next-solver/tait-eq-proj-2.rs rename to tests/ui/traits/next-solver/alias-relate/tait-eq-proj-2.rs index a3df053dd8325..915643f1d2a89 100644 --- a/tests/ui/traits/next-solver/tait-eq-proj-2.rs +++ b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj-2.rs @@ -3,7 +3,7 @@ #![feature(type_alias_impl_trait)] -// Similar to tests/ui/traits/next-solver/tait-eq-proj.rs +// Similar to tests/ui/traits/next-solver/alias-relate/tait-eq-proj.rs // but check the alias-sub relation in the other direction. type Tait = impl Iterator; diff --git a/tests/ui/traits/next-solver/tait-eq-proj.rs b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj.rs similarity index 100% rename from tests/ui/traits/next-solver/tait-eq-proj.rs rename to tests/ui/traits/next-solver/alias-relate/tait-eq-proj.rs diff --git a/tests/ui/traits/next-solver/tait-eq-tait.rs b/tests/ui/traits/next-solver/alias-relate/tait-eq-tait.rs similarity index 100% rename from tests/ui/traits/next-solver/tait-eq-tait.rs rename to tests/ui/traits/next-solver/alias-relate/tait-eq-tait.rs diff --git a/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs b/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs new file mode 100644 index 0000000000000..99a368a746f77 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs @@ -0,0 +1,19 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Reader: Default { + fn read_u8_array(&self) -> Result { + todo!() + } + + fn read_u8(&self) -> Result { + let a: [u8; 1] = self.read_u8_array::<_>()?; + // This results in a nested ` as Try>::Residual: Sized` goal. + // The self type normalizes to `?0`. We previously did not force that to be + // ambiguous but instead incompletely applied the `Self: Sized` candidate + // from the `ParamEnv`, resulting in a type error. + Ok(a[0]) + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr new file mode 100644 index 0000000000000..bafc4ba18a7a3 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 + | +LL | needs_send::(); + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 + | +LL | fn needs_send() {} + | ^^^^ required by this bound in `needs_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr index 076dab29d890b..bafc4ba18a7a3 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -1,12 +1,12 @@ error[E0283]: type annotations needed: cannot satisfy `Foo: Send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 + --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 | LL | needs_send::(); | ^^^ | = note: cannot satisfy `Foo: Send` note: required by a bound in `needs_send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:13:18 + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 | LL | fn needs_send() {} | ^^^^ required by this bound in `needs_send` diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs index a1f38e69e53ef..ef0360248b59a 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs @@ -1,6 +1,5 @@ // revisions: is_send not_send // compile-flags: -Znext-solver -//[is_send] check-pass #![feature(type_alias_impl_trait)] @@ -14,7 +13,7 @@ fn needs_send() {} fn test(_: Foo) { needs_send::(); - //[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send` + //~^ ERROR type annotations needed: cannot satisfy `Foo: Send` } fn defines(_: Foo) { diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr index e3be2931e1232..1b776d7198ea4 100644 --- a/tests/ui/traits/next-solver/more-object-bound.stderr +++ b/tests/ui/traits/next-solver/more-object-bound.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `dyn Trait: Trait` is not satisfied --> $DIR/more-object-bound.rs:12:5 | LL | foo::>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait` | note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8 diff --git a/tests/ui/traits/next-solver/normalize-path-for-method.rs b/tests/ui/traits/next-solver/normalize-path-for-method.rs new file mode 100644 index 0000000000000..b95454306cd69 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-path-for-method.rs @@ -0,0 +1,18 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +struct Foo; +impl Foo { + fn new() -> Self { Foo } +} + +fn main() { + ::Assoc::new(); +} diff --git a/tests/ui/traits/next-solver/normalize-region-obligations.rs b/tests/ui/traits/next-solver/normalize-region-obligations.rs new file mode 100644 index 0000000000000..d189e4893a320 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-region-obligations.rs @@ -0,0 +1,29 @@ +// revisions: normalize_param_env normalize_obligation hrtb +// check-pass +// compile-flags: -Znext-solver + +trait Foo { + #[cfg(normalize_param_env)] + type Gat<'a> where ::Assoc: 'a; + #[cfg(normalize_obligation)] + type Gat<'a> where Self: 'a; + #[cfg(hrtb)] + type Gat<'b> where for<'a> >::Assoc: 'b; +} + +trait Mirror { type Assoc: ?Sized; } +impl Mirror for T { type Assoc = T; } + +trait MirrorRegion<'a> { type Assoc: ?Sized; } +impl<'a, T> MirrorRegion<'a> for T { type Assoc = T; } + +impl Foo for T { + #[cfg(normalize_param_env)] + type Gat<'a> = i32 where T: 'a; + #[cfg(normalize_obligation)] + type Gat<'a> = i32 where ::Assoc: 'a; + #[cfg(hrtb)] + type Gat<'b> = i32 where Self: 'b; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs new file mode 100644 index 0000000000000..7477c56cd5487 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Mirror { + type Assoc; +} + +impl Mirror for T { + type Assoc = T; +} + +fn is_static() {} + +fn test() where ::Assoc: 'static { + is_static::(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-type-outlives.rs b/tests/ui/traits/next-solver/normalize-type-outlives.rs new file mode 100644 index 0000000000000..f50eb6326e239 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-type-outlives.rs @@ -0,0 +1,13 @@ +// check-pass + +trait Tr<'a> { + type Assoc; +} + +fn outlives<'o, T: 'o>() {} + +fn foo<'a, 'b, T: Tr<'a, Assoc = ()>>() { + outlives::<'b, T::Assoc>(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs index 6ca82d1b872c7..08bb0cf42e805 100644 --- a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs +++ b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs @@ -1,5 +1,6 @@ // compile-flags: -Znext-solver // check-pass +#![feature(trait_upcasting)] trait A {} trait B: A {} diff --git a/tests/ui/traits/next-solver/object-unsafety.stderr b/tests/ui/traits/next-solver/object-unsafety.stderr index ee38c256e5f64..eedca879b0c8a 100644 --- a/tests/ui/traits/next-solver/object-unsafety.stderr +++ b/tests/ui/traits/next-solver/object-unsafety.stderr @@ -46,10 +46,7 @@ error[E0277]: the size for values of type ` as Setup>::From` --> $DIR/object-unsafety.rs:12:5 | LL | copy::>(t) - | ^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | doesn't have a size known at compile-time - | this returned value is of type ` as Setup>::From` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for ` as Setup>::From` = note: the return type of a function must have a statically known size diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index 71b1502d775fc..983a0fec65349 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -16,6 +16,8 @@ fn test::Assoc2> + Foo2::Assoc //~^ ERROR overflow evaluating the requirement `::Assoc1 == _` //~| ERROR overflow evaluating the requirement `::Assoc1 == _` //~| ERROR overflow evaluating the requirement `::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `::Assoc1: Sized` //~| ERROR overflow evaluating the requirement `::Assoc1: Bar` } diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index bad6820f7389d..09622bb9b6c28 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -1,3 +1,11 @@ +error[E0275]: overflow evaluating the requirement `::Assoc1 == _` + --> $DIR/recursive-self-normalization-2.rs:15:17 + | +LL | needs_bar::(); + | ^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + error[E0275]: overflow evaluating the requirement `::Assoc1: Bar` --> $DIR/recursive-self-normalization-2.rs:15:17 | @@ -11,6 +19,23 @@ note: required by a bound in `needs_bar` LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` +error[E0275]: overflow evaluating the requirement `::Assoc1: Sized` + --> $DIR/recursive-self-normalization-2.rs:15:17 + | +LL | needs_bar::(); + | ^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) +note: required by an implicit `Sized` bound in `needs_bar` + --> $DIR/recursive-self-normalization-2.rs:12:14 + | +LL | fn needs_bar() {} + | ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn needs_bar() {} + | ++++++++ + error[E0275]: overflow evaluating the requirement `::Assoc1 == _` --> $DIR/recursive-self-normalization-2.rs:15:5 | @@ -35,7 +60,8 @@ LL | needs_bar::(); | ^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs index 809a6a59ca6aa..40e2aa9e63f31 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs @@ -12,6 +12,8 @@ fn test::Assoc>>() { //~^ ERROR overflow evaluating the requirement `::Assoc == _` //~| ERROR overflow evaluating the requirement `::Assoc == _` //~| ERROR overflow evaluating the requirement `::Assoc == _` + //~| ERROR overflow evaluating the requirement `::Assoc == _` + //~| ERROR overflow evaluating the requirement `::Assoc: Sized` //~| ERROR overflow evaluating the requirement `::Assoc: Bar` } diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr index 80005d344ba39..7c058909df7c5 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr @@ -1,3 +1,11 @@ +error[E0275]: overflow evaluating the requirement `::Assoc == _` + --> $DIR/recursive-self-normalization.rs:11:17 + | +LL | needs_bar::(); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + error[E0275]: overflow evaluating the requirement `::Assoc: Bar` --> $DIR/recursive-self-normalization.rs:11:17 | @@ -11,6 +19,23 @@ note: required by a bound in `needs_bar` LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` +error[E0275]: overflow evaluating the requirement `::Assoc: Sized` + --> $DIR/recursive-self-normalization.rs:11:17 + | +LL | needs_bar::(); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) +note: required by an implicit `Sized` bound in `needs_bar` + --> $DIR/recursive-self-normalization.rs:8:14 + | +LL | fn needs_bar() {} + | ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn needs_bar() {} + | ++++++++ + error[E0275]: overflow evaluating the requirement `::Assoc == _` --> $DIR/recursive-self-normalization.rs:11:5 | @@ -35,7 +60,8 @@ LL | needs_bar::(); | ^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index ff25656a7ff59..d96936f60f7a9 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -1,4 +1,5 @@ // compile-flags: -Znext-solver +//~^ ERROR cannot normalize `::Id: '_` #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete @@ -13,6 +14,7 @@ impl Default for T { default type Id = T; //~ ERROR type annotations needed // This will be fixed by #111994 fn intu(&self) -> &Self::Id { + //~^ ERROR type annotations needed self } } diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index a5459165587ca..ea1ae387f56a6 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-transmute.rs:3:12 + --> $DIR/specialization-transmute.rs:4:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -8,12 +8,21 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default +error: cannot normalize `::Id: '_` + +error[E0284]: type annotations needed: cannot satisfy `::Id == _` + --> $DIR/specialization-transmute.rs:16:23 + | +LL | fn intu(&self) -> &Self::Id { + | ^^^^^^^^^ cannot satisfy `::Id == _` + error[E0282]: type annotations needed - --> $DIR/specialization-transmute.rs:13:23 + --> $DIR/specialization-transmute.rs:14:23 | LL | default type Id = T; | ^ cannot infer type for associated type `::Id` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr index ed4dafa1484c2..68232aacc0c5f 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr @@ -12,7 +12,7 @@ error[E0284]: type annotations needed: cannot satisfy `::Id == ( --> $DIR/specialization-unconstrained.rs:20:5 | LL | test::(); - | ^^^^^^^^^^^^^^^ cannot satisfy `::Id == ()` + | ^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == ()` | note: required by a bound in `test` --> $DIR/specialization-unconstrained.rs:17:20 diff --git a/tests/ui/traits/next-solver/temporary-ambiguity.rs b/tests/ui/traits/next-solver/temporary-ambiguity.rs deleted file mode 100644 index 6102de7e446d6..0000000000000 --- a/tests/ui/traits/next-solver/temporary-ambiguity.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Znext-solver -// check-pass - -// Checks that we don't explode when we assemble >1 candidate for a goal. - -struct Wrapper(T); - -trait Foo {} - -impl Foo for Wrapper {} - -impl Foo for Wrapper<()> {} - -fn needs_foo(_: impl Foo) {} - -fn main() { - let mut x = Default::default(); - let w = Wrapper(x); - needs_foo(w); - x = 1; - let _ = x; -} diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs index 2a482f7466865..8e0378e94f043 100644 --- a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs +++ b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs @@ -1,5 +1,6 @@ // check-pass // compile-flags: -Znext-solver +#![feature(trait_upcasting)] pub trait A {} pub trait B: A {} diff --git a/tests/ui/traits/next-solver/unsound-region-obligation.rs b/tests/ui/traits/next-solver/unsound-region-obligation.rs new file mode 100644 index 0000000000000..b8bfa03538887 --- /dev/null +++ b/tests/ui/traits/next-solver/unsound-region-obligation.rs @@ -0,0 +1,13 @@ +//~ ERROR the type `<() as StaticTy>::Item<'a>` does not fulfill the required lifetime +// compile-flags: -Znext-solver +// Regression test for rust-lang/trait-system-refactor-initiative#59 + +trait StaticTy { + type Item<'a>: 'static; +} + +impl StaticTy for () { + type Item<'a> = &'a (); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/unsound-region-obligation.stderr b/tests/ui/traits/next-solver/unsound-region-obligation.stderr new file mode 100644 index 0000000000000..518de7ea3e025 --- /dev/null +++ b/tests/ui/traits/next-solver/unsound-region-obligation.stderr @@ -0,0 +1,7 @@ +error[E0477]: the type `<() as StaticTy>::Item<'a>` does not fulfill the required lifetime + | + = note: type must satisfy the static lifetime + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0477`. diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/upcast-right-substs.rs index 5e4d958c89591..5b4f6d4be0ca8 100644 --- a/tests/ui/traits/next-solver/upcast-right-substs.rs +++ b/tests/ui/traits/next-solver/upcast-right-substs.rs @@ -1,5 +1,6 @@ // compile-flags: -Znext-solver // check-pass +#![feature(trait_upcasting)] trait Foo: Bar + Bar {} diff --git a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr index d5f2bfef19260..4694e7da500f3 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr @@ -11,7 +11,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/bad-copy-cond.rs:7:5 | LL | foo(); - | ^^^ the trait `Copy` is not implemented for `T` + | ^^^^^ the trait `Copy` is not implemented for `T` | note: required by a bound in `foo` --> $DIR/bad-copy-cond.rs:4:26 diff --git a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr index d8db07277c500..f7d5d6fcee4db 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr @@ -11,7 +11,7 @@ error[E0277]: the size for values of type `V` cannot be known at compilation tim --> $DIR/bad-sized-cond.rs:17:5 | LL | foo(); - | ^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `V` note: required by a bound in `foo` @@ -27,9 +27,9 @@ error[E0277]: `V` is not an iterator --> $DIR/bad-sized-cond.rs:20:5 | LL | bar(); - | ^^^ `V` is not an iterator + | ^^^^^ `V` is not an iterator | - = help: the trait `Iterator` is not implemented for `V` + = help: the trait `Iterator` is not implemented for `V`, which is required by `V: IntoIterator` = note: required for `V` to implement `IntoIterator` note: required by a bound in `bar` --> $DIR/bad-sized-cond.rs:12:15 @@ -44,9 +44,9 @@ error[E0277]: the size for values of type `V` cannot be known at compilation tim --> $DIR/bad-sized-cond.rs:20:5 | LL | bar(); - | ^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `V` + = help: the trait `Sized` is not implemented for `V`, which is required by `V: IntoIterator` = note: required for `V` to implement `IntoIterator` note: required by a bound in `bar` --> $DIR/bad-sized-cond.rs:12:15 diff --git a/tests/ui/traits/non_lifetime_binders/fail.stderr b/tests/ui/traits/non_lifetime_binders/fail.stderr index 240bcef7df504..9a324c952931e 100644 --- a/tests/ui/traits/non_lifetime_binders/fail.stderr +++ b/tests/ui/traits/non_lifetime_binders/fail.stderr @@ -11,7 +11,7 @@ error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/fail.rs:19:5 | LL | fail(); - | ^^^^ the trait `Trait` is not implemented for `T` + | ^^^^^^ the trait `Trait` is not implemented for `T` | help: this trait has no implementations, consider adding one --> $DIR/fail.rs:6:1 @@ -31,7 +31,7 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/fail.rs:21:5 | LL | auto_trait(); - | ^^^^^^^^^^ `T` cannot be sent between threads safely + | ^^^^^^^^^^^^ `T` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `T` note: required by a bound in `auto_trait` diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr index 8cf32c89416a7..abbdecf2fe1db 100644 --- a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr @@ -11,7 +11,7 @@ error[E0277]: can't compare `T` with `T` --> $DIR/foreach-partial-eq.rs:10:5 | LL | auto_trait(); - | ^^^^^^^^^^ no implementation for `T < T` and `T > T` + | ^^^^^^^^^^^^ no implementation for `T < T` and `T > T` | = help: the trait `PartialOrd` is not implemented for `T` note: required by a bound in `auto_trait` diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 3059e0beca3e4..79f270fd1bbd6 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -11,7 +11,7 @@ LL | | e; LL | | }) | |__________- this can't be annotated with `?` because it has type `Result<_, ()>` LL | .map(|()| "")?; - | ^ the trait `From<()>` is not implemented for `String` + | ^ the trait `From<()>` is not implemented for `String`, which is required by `Result: FromResidual>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: required for `Result` to implement `FromResidual>` @@ -25,7 +25,7 @@ LL | let x = foo(); | ----- this has type `Result<_, String>` ... LL | .map_err(|_| ())?; - | ---------------^ the trait `From<()>` is not implemented for `String` + | ---------------^ the trait `From<()>` is not implemented for `String`, which is required by `Result<(), String>: FromResidual>` | | | this can't be annotated with `?` because it has type `Result<_, ()>` | @@ -50,7 +50,7 @@ LL | .ok_or_else(|| { LL | | "Couldn't split the test string"; | | - help: remove this semicolon LL | | })?; - | | -^ the trait `From<()>` is not implemented for `String` + | | -^ the trait `From<()>` is not implemented for `String`, which is required by `Result: FromResidual>` | |__________| | this can't be annotated with `?` because it has type `Result<_, ()>` | diff --git a/tests/ui/traits/static-method-generic-inference.stderr b/tests/ui/traits/static-method-generic-inference.stderr index 44c7c099832b5..80bdbbf350dfd 100644 --- a/tests/ui/traits/static-method-generic-inference.stderr +++ b/tests/ui/traits/static-method-generic-inference.stderr @@ -5,7 +5,7 @@ LL | fn new() -> T; | -------------- `HasNew::new` defined here ... LL | let _f: base::Foo = base::HasNew::new(); - | ^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr index 8024ad28d5ae6..28a0646a86bfc 100644 --- a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr +++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr @@ -6,7 +6,7 @@ LL | use_iterator(i); | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `&dyn IntoIterator` + = help: the trait `Iterator` is not implemented for `&dyn IntoIterator`, which is required by `&dyn IntoIterator: IntoIterator` = note: required for `&dyn IntoIterator` to implement `IntoIterator` note: required by a bound in `use_iterator` --> $DIR/dont-suggest-unsize-deref.rs:3:8 diff --git a/tests/ui/traits/suggest-dereferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr index fd45fa3cf74d0..0eea6cbcc5a62 100644 --- a/tests/ui/traits/suggest-dereferences/issue-39029.stderr +++ b/tests/ui/traits/suggest-dereferences/issue-39029.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied --> $DIR/issue-39029.rs:16:38 | LL | let _errors = TcpListener::bind(&bad); - | ----------------- ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | ----------------- ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`, which is required by `&NoToSocketAddrs: ToSocketAddrs` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index 62500866c49b9..a41330373be1a 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -6,7 +6,7 @@ LL | .filter(|c| "aeiou".contains(c)) | | | required by a bound introduced by this call | - = help: the trait `Fn<(char,)>` is not implemented for `char` + = help: the trait `Fn<(char,)>` is not implemented for `char`, which is required by `&char: Pattern<'_>` = note: required for `&char` to implement `FnOnce<(char,)>` = note: required for `&char` to implement `Pattern<'_>` note: required by a bound in `core::str::::contains` diff --git a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr index d6033bc6baa0f..d1d75625abaaa 100644 --- a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr +++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `TargetStruct: From<&{integer}>` is not satisfied --> $DIR/suggest-dereferencing-receiver-argument.rs:13:30 | LL | let _b: TargetStruct = a.into(); - | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct` + | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct`, which is required by `&{integer}: Into<_>` | = note: required for `&{integer}` to implement `Into` help: consider dereferencing here diff --git a/tests/ui/traits/suggest-where-clause.stderr b/tests/ui/traits/suggest-where-clause.stderr index e3bbf768c6e73..08f3a8dc23dd1 100644 --- a/tests/ui/traits/suggest-where-clause.stderr +++ b/tests/ui/traits/suggest-where-clause.stderr @@ -7,7 +7,7 @@ LL | // suggest a where-clause, if needed LL | mem::size_of::(); | ^ doesn't have a size known at compile-time | -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider removing the `?Sized` bound to make the type parameter `Sized` | @@ -29,7 +29,7 @@ note: required because it appears within the type `Misc` | LL | struct Misc(T); | ^^^^ -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL help: consider removing the `?Sized` bound to make the type parameter `Sized` | @@ -72,7 +72,7 @@ LL | mem::size_of::<[T]>(); | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[T]` -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error[E0277]: the size for values of type `[&U]` cannot be known at compilation time @@ -82,7 +82,7 @@ LL | mem::size_of::<[&U]>(); | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[&U]` -note: required by a bound in `std::mem::size_of` +note: required by an implicit `Sized` bound in `std::mem::size_of` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: aborting due to 7 previous errors diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr index 89477475970f4..822fc91e43fea 100644 --- a/tests/ui/traits/track-obligations.stderr +++ b/tests/ui/traits/track-obligations.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b --> $DIR/track-obligations.rs:83:16 | LL | struct ALayer(C); - | ---------------- - | | - | doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` - | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` + | ---------------- doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` or `ALayer<()>: ParticularServiceLayer<()>` ... LL | struct Client(C); | ---------------- method `check` not found for this struct diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs index 927a9d6b94f8a..4a5e445d1efbe 100644 --- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs @@ -1,3 +1,4 @@ +#![feature(trait_upcasting)] #![feature(trait_alias)] // Although we *elaborate* `T: Alias` to `i32: B`, we should diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr index 1a410519a4edc..99c82b88d9c38 100644 --- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/alias-where-clause-isnt-supertrait.rs:26:5 + --> $DIR/alias-where-clause-isnt-supertrait.rs:27:5 | LL | fn test(x: &dyn C) -> &dyn B { | ------ expected `&dyn B` because of return type diff --git a/tests/ui/traits/trait-upcasting/basic.rs b/tests/ui/traits/trait-upcasting/basic.rs index 538cd8329cc64..570ec5160bfe9 100644 --- a/tests/ui/traits/trait-upcasting/basic.rs +++ b/tests/ui/traits/trait-upcasting/basic.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs index 4a379d9f875b8..eae5cf8d58d01 100644 --- a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs +++ b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs @@ -1,4 +1,5 @@ // run-pass +#![feature(trait_upcasting)] trait Foo: Bar + Bar {} trait Bar { diff --git a/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr b/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr deleted file mode 100644 index 557a4420a3dbf..0000000000000 --- a/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: this `Deref` implementation is covered by an implicit supertrait coercion - --> $DIR/deref-lint-regions.rs:8:1 - | -LL | impl<'a> Deref for dyn Foo<'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref>` which conflicts with supertrait `Bar<'_>` -LL | -LL | type Target = dyn Bar<'a>; - | -------------------------- target type is a supertrait of `dyn Foo<'_>` - | - = help: consider removing this implementation or replacing it with a method instead - = note: `#[warn(deref_into_dyn_supertrait)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/trait-upcasting/deref-lint.stderr b/tests/ui/traits/trait-upcasting/deref-lint.stderr deleted file mode 100644 index 5a13659edf568..0000000000000 --- a/tests/ui/traits/trait-upcasting/deref-lint.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: this `Deref` implementation is covered by an implicit supertrait coercion - --> $DIR/deref-lint.rs:9:1 - | -LL | impl<'a> Deref for dyn 'a + B { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref` which conflicts with supertrait `A` -... -LL | type Target = dyn A; - | -------------------- target type is a supertrait of `dyn B` - | - = help: consider removing this implementation or replacing it with a method instead - = note: `#[warn(deref_into_dyn_supertrait)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs index 366eae1a58a34..e4784fa41011b 100644 --- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs +++ b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs @@ -15,6 +15,8 @@ impl Foo for () { } impl<'a> Deref for dyn Foo + 'a { + //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn Bar + 'a; fn deref(&self) -> &Self::Target { @@ -30,5 +32,4 @@ fn main() { let x: &dyn Foo = &(); let y = take_dyn(x); let z: u32 = y; - //~^ ERROR mismatched types } diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr index 193d09e350111..fa93e28c73bce 100644 --- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr +++ b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr @@ -1,16 +1,19 @@ -error[E0308]: mismatched types - --> $DIR/deref-upcast-behavioral-change.rs:32:18 +error: this `Deref` implementation is covered by an implicit supertrait coercion + --> $DIR/deref-upcast-behavioral-change.rs:17:1 | -LL | let z: u32 = y; - | --- ^ expected `u32`, found `i32` - | | - | expected due to this +LL | impl<'a> Deref for dyn Foo + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref>` which conflicts with supertrait `Bar` +... +LL | type Target = dyn Bar + 'a; + | -------------------------------- target type is a supertrait of `dyn Foo` | -help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 +note: the lint level is defined here + --> $DIR/deref-upcast-behavioral-change.rs:1:9 | -LL | let z: u32 = y.try_into().unwrap(); - | ++++++++++++++++++++ +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/diamond.rs b/tests/ui/traits/trait-upcasting/diamond.rs index 9a78339a4ec84..a4f81c464b402 100644 --- a/tests/ui/traits/trait-upcasting/diamond.rs +++ b/tests/ui/traits/trait-upcasting/diamond.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/fewer-associated.rs b/tests/ui/traits/trait-upcasting/fewer-associated.rs index e7ca6fa5208ec..58e72d9d7ef57 100644 --- a/tests/ui/traits/trait-upcasting/fewer-associated.rs +++ b/tests/ui/traits/trait-upcasting/fewer-associated.rs @@ -3,6 +3,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait A: B { type Assoc; } diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr index 119b3109c6323..1538e2f3fd71a 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl.rs:14:66 + --> $DIR/illegal-upcast-from-impl.rs:16:66 | LL | fn illegal(x: &dyn Sub) -> &dyn Super { x } | ----------------------- ^ expected trait `Super`, found trait `Sub` diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr index 119b3109c6323..1538e2f3fd71a 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl.rs:14:66 + --> $DIR/illegal-upcast-from-impl.rs:16:66 | LL | fn illegal(x: &dyn Sub) -> &dyn Super { x } | ----------------------- ^ expected trait `Super`, found trait `Sub` diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs index 5a493fd48b3f9..ffed8beb44845 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs @@ -1,6 +1,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait Super { type Assoc; } diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs index 999f3b16f50d8..79fb643eacd01 100644 --- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs +++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs @@ -1,4 +1,5 @@ #![deny(deref_into_dyn_supertrait)] +#![feature(trait_upcasting)] // remove this and the test compiles use std::ops::Deref; diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr index fcc80c6148f7d..6b6a26d1593fb 100644 --- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr +++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/inference-behavior-change-deref.rs:33:18 + --> $DIR/inference-behavior-change-deref.rs:34:18 | LL | let z: u32 = y; | --- ^ expected `u32`, found `i32` diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.rs b/tests/ui/traits/trait-upcasting/invalid-upcast.rs index 9269a5e3e9ff6..e634bbd5ac6f5 100644 --- a/tests/ui/traits/trait-upcasting/invalid-upcast.rs +++ b/tests/ui/traits/trait-upcasting/invalid-upcast.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr index e70b99d28c7e4..3aa21ee3dddfb 100644 --- a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr +++ b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:51:35 + --> $DIR/invalid-upcast.rs:53:35 | LL | let _: &dyn std::fmt::Debug = baz; | -------------------- ^^^ expected trait `Debug`, found trait `Baz` @@ -10,7 +10,7 @@ LL | let _: &dyn std::fmt::Debug = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:53:24 + --> $DIR/invalid-upcast.rs:55:24 | LL | let _: &dyn Send = baz; | --------- ^^^ expected trait `Send`, found trait `Baz` @@ -21,7 +21,7 @@ LL | let _: &dyn Send = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:55:24 + --> $DIR/invalid-upcast.rs:57:24 | LL | let _: &dyn Sync = baz; | --------- ^^^ expected trait `Sync`, found trait `Baz` @@ -32,7 +32,7 @@ LL | let _: &dyn Sync = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:58:25 + --> $DIR/invalid-upcast.rs:60:25 | LL | let bar: &dyn Bar = baz; | -------- ^^^ expected trait `Bar`, found trait `Baz` @@ -43,7 +43,7 @@ LL | let bar: &dyn Bar = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:60:35 + --> $DIR/invalid-upcast.rs:62:35 | LL | let _: &dyn std::fmt::Debug = bar; | -------------------- ^^^ expected trait `Debug`, found trait `Bar` @@ -54,7 +54,7 @@ LL | let _: &dyn std::fmt::Debug = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:62:24 + --> $DIR/invalid-upcast.rs:64:24 | LL | let _: &dyn Send = bar; | --------- ^^^ expected trait `Send`, found trait `Bar` @@ -65,7 +65,7 @@ LL | let _: &dyn Send = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:64:24 + --> $DIR/invalid-upcast.rs:66:24 | LL | let _: &dyn Sync = bar; | --------- ^^^ expected trait `Sync`, found trait `Bar` @@ -76,7 +76,7 @@ LL | let _: &dyn Sync = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:67:25 + --> $DIR/invalid-upcast.rs:69:25 | LL | let foo: &dyn Foo = baz; | -------- ^^^ expected trait `Foo`, found trait `Baz` @@ -87,7 +87,7 @@ LL | let foo: &dyn Foo = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:69:35 + --> $DIR/invalid-upcast.rs:71:35 | LL | let _: &dyn std::fmt::Debug = foo; | -------------------- ^^^ expected trait `Debug`, found trait `Foo` @@ -98,7 +98,7 @@ LL | let _: &dyn std::fmt::Debug = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:71:24 + --> $DIR/invalid-upcast.rs:73:24 | LL | let _: &dyn Send = foo; | --------- ^^^ expected trait `Send`, found trait `Foo` @@ -109,7 +109,7 @@ LL | let _: &dyn Send = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:73:24 + --> $DIR/invalid-upcast.rs:75:24 | LL | let _: &dyn Sync = foo; | --------- ^^^ expected trait `Sync`, found trait `Foo` @@ -120,7 +120,7 @@ LL | let _: &dyn Sync = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:76:25 + --> $DIR/invalid-upcast.rs:78:25 | LL | let foo: &dyn Foo = bar; | -------- ^^^ expected trait `Foo`, found trait `Bar` @@ -131,7 +131,7 @@ LL | let foo: &dyn Foo = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:78:35 + --> $DIR/invalid-upcast.rs:80:35 | LL | let _: &dyn std::fmt::Debug = foo; | -------------------- ^^^ expected trait `Debug`, found trait `Foo` @@ -142,7 +142,7 @@ LL | let _: &dyn std::fmt::Debug = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:80:24 + --> $DIR/invalid-upcast.rs:82:24 | LL | let _: &dyn Send = foo; | --------- ^^^ expected trait `Send`, found trait `Foo` @@ -153,7 +153,7 @@ LL | let _: &dyn Send = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:82:24 + --> $DIR/invalid-upcast.rs:84:24 | LL | let _: &dyn Sync = foo; | --------- ^^^ expected trait `Sync`, found trait `Foo` diff --git a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs index 77ce627078f90..b672963ae9887 100644 --- a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs +++ b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs @@ -1,4 +1,5 @@ // run-pass +#![feature(trait_upcasting)] struct Test { func: Box, diff --git a/tests/ui/traits/trait-upcasting/issue-11515.current.stderr b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr new file mode 100644 index 0000000000000..ce799dcb7ef65 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr @@ -0,0 +1,14 @@ +error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental + --> $DIR/issue-11515.rs:10:38 + | +LL | let test = Box::new(Test { func: closure }); + | ^^^^^^^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/issue-11515.next.stderr b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr new file mode 100644 index 0000000000000..ce799dcb7ef65 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr @@ -0,0 +1,14 @@ +error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental + --> $DIR/issue-11515.rs:10:38 + | +LL | let test = Box::new(Test { func: closure }); + | ^^^^^^^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/issue-11515.rs b/tests/ui/traits/trait-upcasting/issue-11515.rs index a1edb53ec37b5..31ea2fb353cd2 100644 --- a/tests/ui/traits/trait-upcasting/issue-11515.rs +++ b/tests/ui/traits/trait-upcasting/issue-11515.rs @@ -1,4 +1,3 @@ -// check-pass // revisions: current next //[next] compile-flags: -Znext-solver @@ -8,5 +7,5 @@ struct Test { fn main() { let closure: Box = Box::new(|| ()); - let test = Box::new(Test { func: closure }); + let test = Box::new(Test { func: closure }); //~ ERROR trait upcasting coercion is experimental [E0658] } diff --git a/tests/ui/traits/trait-upcasting/lifetime.rs b/tests/ui/traits/trait-upcasting/lifetime.rs index 6c65c38870f24..6486ec3891c68 100644 --- a/tests/ui/traits/trait-upcasting/lifetime.rs +++ b/tests/ui/traits/trait-upcasting/lifetime.rs @@ -1,11 +1,13 @@ // run-pass +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } - fn z(&self) -> i32 { + fn z(&self) -> i32 { //~ WARN methods `z` and `y` are never used 11 } @@ -19,7 +21,7 @@ trait Bar: Foo { 20 } - fn w(&self) -> i32 { + fn w(&self) -> i32 { //~ WARN method `w` is never used 21 } } diff --git a/tests/ui/traits/trait-upcasting/lifetime.stderr b/tests/ui/traits/trait-upcasting/lifetime.stderr new file mode 100644 index 0000000000000..ca8f9cf63f3e7 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/lifetime.stderr @@ -0,0 +1,25 @@ +warning: methods `z` and `y` are never used + --> $DIR/lifetime.rs:10:8 + | +LL | trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + | --- methods in this trait +... +LL | fn z(&self) -> i32 { + | ^ +... +LL | fn y(&self) -> i32 { + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: method `w` is never used + --> $DIR/lifetime.rs:24:8 + | +LL | trait Bar: Foo { + | --- method in this trait +... +LL | fn w(&self) -> i32 { + | ^ + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/trait-upcasting/deref-lint-regions.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs similarity index 52% rename from tests/ui/traits/trait-upcasting/deref-lint-regions.rs rename to tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs index 946305cbb2b4b..da1a9cc2775d0 100644 --- a/tests/ui/traits/trait-upcasting/deref-lint-regions.rs +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs @@ -1,4 +1,4 @@ -// check-pass +#![deny(deref_into_dyn_supertrait)] use std::ops::Deref; @@ -6,7 +6,8 @@ trait Bar<'a> {} trait Foo<'a>: Bar<'a> {} impl<'a> Deref for dyn Foo<'a> { - //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion + //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn Bar<'a>; fn deref(&self) -> &Self::Target { diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr new file mode 100644 index 0000000000000..a5f3660d4bcb0 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr @@ -0,0 +1,19 @@ +error: this `Deref` implementation is covered by an implicit supertrait coercion + --> $DIR/migrate-lint-deny-regions.rs:8:1 + | +LL | impl<'a> Deref for dyn Foo<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref>` which conflicts with supertrait `Bar<'_>` +... +LL | type Target = dyn Bar<'a>; + | -------------------------- target type is a supertrait of `dyn Foo<'_>` + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 +note: the lint level is defined here + --> $DIR/migrate-lint-deny-regions.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/trait-upcasting/deref-lint.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs similarity index 58% rename from tests/ui/traits/trait-upcasting/deref-lint.rs rename to tests/ui/traits/trait-upcasting/migrate-lint-deny.rs index 68838d2ae20dd..926b3649e01b3 100644 --- a/tests/ui/traits/trait-upcasting/deref-lint.rs +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs @@ -1,4 +1,4 @@ -// check-pass +#![deny(deref_into_dyn_supertrait)] use std::ops::Deref; @@ -7,7 +7,8 @@ trait A {} trait B: A {} impl<'a> Deref for dyn 'a + B { - //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion + //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn A; fn deref(&self) -> &Self::Target { diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr new file mode 100644 index 0000000000000..29997a9b3d9c3 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr @@ -0,0 +1,19 @@ +error: this `Deref` implementation is covered by an implicit supertrait coercion + --> $DIR/migrate-lint-deny.rs:9:1 + | +LL | impl<'a> Deref for dyn 'a + B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref` which conflicts with supertrait `A` +... +LL | type Target = dyn A; + | -------------------- target type is a supertrait of `dyn B` + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 +note: the lint level is defined here + --> $DIR/migrate-lint-deny.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs index 2c9126c863d52..8a90a09ff0411 100644 --- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs +++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs @@ -10,6 +10,7 @@ trait Foo: Bar { impl<'a> Deref for dyn Foo + 'a { //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn Bar + 'a; fn deref(&self) -> &Self::Target { diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr index a447f9cf83b7a..6245da5a17604 100644 --- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr +++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr @@ -3,11 +3,12 @@ warning: this `Deref` implementation is covered by an implicit supertrait coerci | LL | impl<'a> Deref for dyn Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref>` which conflicts with supertrait `Bar` -LL | +... LL | type Target = dyn Bar + 'a; | -------------------------------- target type is a supertrait of `dyn Foo` | - = help: consider removing this implementation or replacing it with a method instead + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 = note: `#[warn(deref_into_dyn_supertrait)]` on by default warning: 1 warning emitted diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs index 0e17c27671770..2e53a00a90e9c 100644 --- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs +++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs @@ -1,4 +1,5 @@ // check-fail +#![feature(trait_upcasting)] trait Bar { fn bar(&self, _: T) {} diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr index c888ccc1ebb0d..70ba1fcaf3838 100644 --- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr +++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/multiple-occurrence-ambiguousity.rs:19:26 + --> $DIR/multiple-occurrence-ambiguousity.rs:20:26 | LL | let t: &dyn Bar<_> = s; | ----------- ^ expected trait `Bar`, found trait `Foo` diff --git a/tests/ui/traits/trait-upcasting/normalization.rs b/tests/ui/traits/trait-upcasting/normalization.rs index b594969483a8c..24da1ec5dfb58 100644 --- a/tests/ui/traits/trait-upcasting/normalization.rs +++ b/tests/ui/traits/trait-upcasting/normalization.rs @@ -3,6 +3,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait Mirror { type Assoc; } diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.rs b/tests/ui/traits/trait-upcasting/replace-vptr.rs index 4a7304ec2d716..5ef65786bb705 100644 --- a/tests/ui/traits/trait-upcasting/replace-vptr.rs +++ b/tests/ui/traits/trait-upcasting/replace-vptr.rs @@ -1,7 +1,9 @@ // run-pass +#![feature(trait_upcasting)] + trait A { - fn foo_a(&self); + fn foo_a(&self); //~ WARN method `foo_a` is never used } trait B { @@ -9,7 +11,7 @@ trait B { } trait C: A + B { - fn foo_c(&self); + fn foo_c(&self); //~ WARN method `foo_c` is never used } struct S(i32); diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.stderr b/tests/ui/traits/trait-upcasting/replace-vptr.stderr new file mode 100644 index 0000000000000..823094761b385 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/replace-vptr.stderr @@ -0,0 +1,20 @@ +warning: method `foo_a` is never used + --> $DIR/replace-vptr.rs:6:8 + | +LL | trait A { + | - method in this trait +LL | fn foo_a(&self); + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: method `foo_c` is never used + --> $DIR/replace-vptr.rs:14:8 + | +LL | trait C: A + B { + | - method in this trait +LL | fn foo_c(&self); + | ^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/trait-upcasting/struct.rs b/tests/ui/traits/trait-upcasting/struct.rs index 64fa9ca1b5fa5..a3e41696956cb 100644 --- a/tests/ui/traits/trait-upcasting/struct.rs +++ b/tests/ui/traits/trait-upcasting/struct.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.rs b/tests/ui/traits/trait-upcasting/subtrait-method.rs index 20277280440c5..136d15af0e8b2 100644 --- a/tests/ui/traits/trait-upcasting/subtrait-method.rs +++ b/tests/ui/traits/trait-upcasting/subtrait-method.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr index 3fdf3f4816160..918159e845b9e 100644 --- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr +++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr @@ -1,64 +1,64 @@ error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope - --> $DIR/subtrait-method.rs:53:9 + --> $DIR/subtrait-method.rs:55:9 | LL | bar.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:25:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:57:9 + --> $DIR/subtrait-method.rs:59:9 | LL | foo.b(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:15:1 + --> $DIR/subtrait-method.rs:17:1 | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:59:9 + --> $DIR/subtrait-method.rs:61:9 | LL | foo.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:25:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:63:9 + --> $DIR/subtrait-method.rs:65:9 | LL | foo.b(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:15:1 + --> $DIR/subtrait-method.rs:17:1 | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:65:9 + --> $DIR/subtrait-method.rs:67:9 | LL | foo.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:25:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr index 47ffa68b8ff88..10c22440a8346 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-1.rs:17:13 + --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr index 47ffa68b8ff88..10c22440a8346 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-1.rs:17:13 + --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs index 7d3deeeaa6173..54c3c5e0c28f5 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs @@ -1,6 +1,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait Foo: Bar + Bar {} trait Bar { fn bar(&self) -> Option { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs index b4df0f5a90258..b024b27750bc6 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo: Bar + Bar {} trait Bar { fn bar(&self) -> Option { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr index f84ea93dc6792..3e59b9d33634a 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -1,11 +1,11 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` - --> $DIR/type-checking-test-2.rs:17:13 + --> $DIR/type-checking-test-2.rs:19:13 | LL | let _ = x as &dyn Bar; // Error | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-2.rs:22:13 + --> $DIR/type-checking-test-2.rs:24:13 | LL | let a = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs index 3685569d98d1a..b2db3a127974c 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo<'a>: Bar<'a> {} trait Bar<'a> {} diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr index 640a6066268de..e6cb6a753998f 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:9:13 + --> $DIR/type-checking-test-3.rs:11:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _ = x as &dyn Bar<'a>; // Error | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:14:13 + --> $DIR/type-checking-test-3.rs:16:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) { | -- lifetime `'a` defined here diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs index 65391502386de..f40c48f0d125f 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo<'a>: Bar<'a, 'a> {} trait Bar<'a, 'b> { fn get_b(&self) -> Option<&'a u32> { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr index 7e7548955d39d..8d506e5807ece 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:13:13 + --> $DIR/type-checking-test-4.rs:15:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _ = x as &dyn Bar<'static, 'a>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:18:13 + --> $DIR/type-checking-test-4.rs:20:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -15,7 +15,7 @@ LL | let _ = x as &dyn Bar<'a, 'static>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:24:5 + --> $DIR/type-checking-test-4.rs:26:5 | LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -24,7 +24,7 @@ LL | y.get_b() // ERROR | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:29:5 + --> $DIR/type-checking-test-4.rs:31:5 | LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -32,7 +32,7 @@ LL | <_ as Bar>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:34:5 + --> $DIR/type-checking-test-4.rs:36:5 | LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -40,7 +40,7 @@ LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:42:5 + --> $DIR/type-checking-test-4.rs:44:5 | LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr new file mode 100644 index 0000000000000..86de78f858c9e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr @@ -0,0 +1,14 @@ +error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental + --> $DIR/upcast-through-struct-tail.rs:10:5 + | +LL | x + | ^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required when coercing `Box>` into `Box>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr new file mode 100644 index 0000000000000..86de78f858c9e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr @@ -0,0 +1,14 @@ +error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental + --> $DIR/upcast-through-struct-tail.rs:10:5 + | +LL | x + | ^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required when coercing `Box>` into `Box>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs index f8cf793e4a49c..948f058e5287b 100644 --- a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs @@ -1,4 +1,3 @@ -// check-pass // revisions: current next //[next] compile-flags: -Znext-solver @@ -9,6 +8,7 @@ trait B {} fn test<'a>(x: Box>) -> Box> { x + //~^ ERROR cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental } fn main() {} diff --git a/tests/ui/traits/unsend-future.stderr b/tests/ui/traits/unsend-future.stderr index 25df34197947b..4462208cb4956 100644 --- a/tests/ui/traits/unsend-future.stderr +++ b/tests/ui/traits/unsend-future.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | require_handler(handler) | ^^^^^^^ future returned by `handler` is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `*const i32` + = help: within `impl Future`, the trait `Send` is not implemented for `*const i32`, which is required by `fn() -> impl Future {handler}: Handler` note: future is not `Send` as this value is used across an await --> $DIR/unsend-future.rs:15:14 | diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs new file mode 100644 index 0000000000000..32e32850925f7 --- /dev/null +++ b/tests/ui/traits/upcast_soundness_bug.rs @@ -0,0 +1,69 @@ +#![feature(trait_upcasting)] +// known-bug: #120222 +// check-pass +//! This will segfault at runtime. + +pub trait SupSupA { + fn method(&self) {} +} +pub trait SupSupB {} +impl SupSupA for T {} +impl SupSupB for T {} + +pub trait Super: SupSupA + SupSupB {} + +pub trait Unimplemented {} + +pub trait Trait: Super + Super { + fn missing_method(&self) + where + T1: Unimplemented, + { + } +} + +impl Super for S {} + +impl Trait for S {} + +#[inline(never)] +pub fn user1() -> &'static dyn Trait { + &() + /* VTABLE: + .L__unnamed_2: + .quad core::ptr::drop_in_place<()> + .asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000" + .quad example::SupSupA::method + .quad .L__unnamed_4 // SupSupB vtable (pointer) + .zero 8 // null pointer for missing_method + */ +} + +#[inline(never)] +pub fn user2() -> &'static dyn Trait { + &() + /* VTABLE: + .L__unnamed_3: + .quad core::ptr::drop_in_place<()> + .asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000" + .quad example::SupSupA::method + .quad .L__unnamed_4 // SupSupB vtable (pointer) + .quad .L__unnamed_5 // Super vtable (pointer) + .zero 8 // null pointer for missing_method + */ +} + +fn main() { + let p: *const dyn Trait = &(); + let p = p as *const dyn Trait; // <- this is bad! + let p = p as *const dyn Super; // <- this upcast accesses improper vtable entry + // accessing from L__unnamed_2 the position for the 'Super vtable (pointer)', + // thus reading 'null pointer for missing_method' + + let p = p as *const dyn SupSupB; // <- this upcast dereferences (null) pointer from that entry + // to read the SupSupB vtable (pointer) + + // SEGFAULT + + println!("{:?}", p); +} diff --git a/tests/ui/traits/use-before-def.rs b/tests/ui/traits/use-before-def.rs index 1ee2b941909f4..e52dc53fbab79 100644 --- a/tests/ui/traits/use-before-def.rs +++ b/tests/ui/traits/use-before-def.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(non_camel_case_types)] // Issue #1761 diff --git a/tests/ui/traits/wf-object/reverse-order.rs b/tests/ui/traits/wf-object/reverse-order.rs index 74b2ef48533d2..e90c8763d651f 100644 --- a/tests/ui/traits/wf-object/reverse-order.rs +++ b/tests/ui/traits/wf-object/reverse-order.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed. diff --git a/tests/ui/transmutability/region-infer.stderr b/tests/ui/transmutability/region-infer.stderr index 50d060cd47431..805862d6c4afc 100644 --- a/tests/ui/transmutability/region-infer.stderr +++ b/tests/ui/transmutability/region-infer.stderr @@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `W<'_>` in the defining scop --> $DIR/region-infer.rs:20:5 | LL | test(); - | ^^^^ The size of `()` is smaller than the size of `W<'_>` + | ^^^^^^ The size of `()` is smaller than the size of `W<'_>` | note: required by a bound in `test` --> $DIR/region-infer.rs:11:12 diff --git a/tests/ui/treat-err-as-bug/eagerly-emit.rs b/tests/ui/treat-err-as-bug/eagerly-emit.rs index 5f32f5a1d94b7..ede190575d529 100644 --- a/tests/ui/treat-err-as-bug/eagerly-emit.rs +++ b/tests/ui/treat-err-as-bug/eagerly-emit.rs @@ -6,6 +6,5 @@ fn main() {} fn f() -> impl Foo { //~^ ERROR the trait bound `i32: Foo` is not satisfied - //~| ERROR `report_selection_error` did not emit an error 1i32 } diff --git a/tests/ui/treat-err-as-bug/eagerly-emit.stderr b/tests/ui/treat-err-as-bug/eagerly-emit.stderr index 3d25741d52de8..4ae596435aa7f 100644 --- a/tests/ui/treat-err-as-bug/eagerly-emit.stderr +++ b/tests/ui/treat-err-as-bug/eagerly-emit.stderr @@ -1,9 +1,3 @@ -error: `report_selection_error` did not emit an error - --> $DIR/eagerly-emit.rs:7:11 - | -LL | fn f() -> impl Foo { - | ^^^^^^^^ - error: trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging error[E0277]: the trait bound `i32: Foo` is not satisfied @@ -11,7 +5,7 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied | LL | fn f() -> impl Foo { | ^^^^^^^^ the trait `Foo` is not implemented for `i32` -... +LL | LL | 1i32 | ---- return type was inferred to be `i32` here | @@ -21,8 +15,6 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^ -error: expected fulfillment errors - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index 4c5d0e5ae7987..f1b61c3607b77 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -8,5 +8,5 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `C` -#1 [eval_to_allocation_raw] const-evaluating + checking `C` +#1 [lint_mod] linting top-level module end of query stack diff --git a/tests/ui/trivial_casts-rpass.rs b/tests/ui/trivial_casts-rpass.rs index 8e49468bf0c45..4653a8df802da 100644 --- a/tests/ui/trivial_casts-rpass.rs +++ b/tests/ui/trivial_casts-rpass.rs @@ -4,7 +4,7 @@ #![allow(trivial_casts, trivial_numeric_casts)] trait Foo { - fn foo(&self) {} + fn foo(&self) {} //~ WARN method `foo` is never used } pub struct Bar; diff --git a/tests/ui/trivial_casts-rpass.stderr b/tests/ui/trivial_casts-rpass.stderr new file mode 100644 index 0000000000000..74698b61ab4a4 --- /dev/null +++ b/tests/ui/trivial_casts-rpass.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/trivial_casts-rpass.rs:7:8 + | +LL | trait Foo { + | --- method in this trait +LL | fn foo(&self) {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index d58a011ff5501..6c41b42dc643f 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -2,7 +2,7 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError`, which is required by `Result: FromResidual>` | | | this can't be annotated with `?` because it has type `Result<_, &str>` | diff --git a/tests/ui/try-block/try-block-in-match-arm.rs b/tests/ui/try-block/try-block-in-match-arm.rs new file mode 100644 index 0000000000000..ea004ebe29f9e --- /dev/null +++ b/tests/ui/try-block/try-block-in-match-arm.rs @@ -0,0 +1,11 @@ +// check-pass +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn main() { + let _ = match 1 { + 1 => try {} + _ => Ok::<(), ()>(()), + }; +} diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 97fbbdbf8f8a8..80471c0ab1a40 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -4,14 +4,15 @@ error[E0277]: `?` couldn't convert the error to `u8` LL | fn result_to_result() -> Result { | --------------- expected `u8` because of this LL | Ok(Err(123_i32)?) - | ------------^ the trait `From` is not implemented for `u8` + | ------------^ the trait `From` is not implemented for `u8`, which is required by `Result: FromResidual>` | | | this can't be annotated with `?` because it has type `Result<_, i32>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: > - > + >> + > = note: required for `Result` to implement `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index b155b3ff66313..34618de78cd0f 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -4,7 +4,7 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result { | --------------- expected `()` because of this LL | Err(5)?; - | ------^ the trait `From<{integer}>` is not implemented for `()` + | ------^ the trait `From<{integer}>` is not implemented for `()`, which is required by `Result: FromResidual>` | | | this can't be annotated with `?` because it has type `Result<_, {integer}>` | diff --git a/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr index 94113b336c330..7f80c3cfaba44 100644 --- a/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -4,11 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `Alph LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... - --> $DIR/self-in-enum-definition.rs:5:10 - | -LL | V3 = Self::V1 {} as u8 + 2, - | ^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr index 2ed918eca1714..5c5506fb8532d 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr @@ -9,7 +9,7 @@ LL | is_send(m::foo()); | | | required by a bound introduced by this call | - = help: within `Foo`, the trait `Send` is not implemented for `Rc` + = help: within `Foo`, the trait `Send` is not implemented for `Rc`, which is required by `Foo: Send` note: required because it appears within the type `Foo` --> $DIR/auto-trait-leakage2.rs:7:16 | diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs index e440dce5e514f..4c881dd133086 100644 --- a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs @@ -1,9 +1,8 @@ -//! This test shows that we can even follow projections -//! into associated types of the same impl if they are -//! indirectly mentioned in a struct field. +//! This test shows that we do not treat opaque types +//! as defined by a method if the opaque type is +//! only indirectly mentioned in a struct field. #![feature(impl_trait_in_assoc_type)] -// check-pass struct Bar; @@ -16,6 +15,7 @@ impl Trait for Bar { type Assoc = impl std::fmt::Debug; fn foo() -> Foo { Foo { field: () } + //~^ ERROR: item constrains opaque type that is not in its signature } } diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr new file mode 100644 index 0000000000000..5c53dfa3a7500 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr @@ -0,0 +1,15 @@ +error: item constrains opaque type that is not in its signature + --> $DIR/hidden_behind_struct_field2.rs:17:22 + | +LL | Foo { field: () } + | ^^ + | + = note: this item must mention the opaque type in its signature in order to be able to register hidden types +note: this item must mention the opaque type in its signature in order to be able to register hidden types + --> $DIR/hidden_behind_struct_field2.rs:16:8 + | +LL | fn foo() -> Foo { + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait.rs b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait.rs new file mode 100644 index 0000000000000..a788563ab779e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait.rs @@ -0,0 +1,38 @@ +//! Check that we cannot instantiate a hidden type in the body +//! of an assoc fn or const unless mentioned in the signature. + +#![feature(impl_trait_in_assoc_type)] + +trait Trait: Sized { + type Assoc; + fn foo(); + fn bar() -> Self::Assoc; +} + +impl Trait for () { + type Assoc = impl std::fmt::Debug; + fn foo() { + let x: Self::Assoc = 42; //~ ERROR: mismatched types + } + fn bar() -> Self::Assoc { + "" + } +} + +trait Trait2: Sized { + type Assoc; + const FOO: (); + fn bar() -> Self::Assoc; +} + +impl Trait2 for () { + type Assoc = impl std::fmt::Debug; + const FOO: () = { + let x: Self::Assoc = 42; //~ ERROR: mismatched types + }; + fn bar() -> Self::Assoc { + "" + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait.stderr b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait.stderr new file mode 100644 index 0000000000000..1d7a97c536713 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait.stderr @@ -0,0 +1,41 @@ +error[E0308]: mismatched types + --> $DIR/impl_trait_in_trait_defined_outside_trait.rs:15:30 + | +LL | type Assoc = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | fn foo() { +LL | let x: Self::Assoc = 42; + | ----------- ^^ expected opaque type, found integer + | | + | expected due to this + | + = note: expected opaque type `<() as Trait>::Assoc` + found type `{integer}` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/impl_trait_in_trait_defined_outside_trait.rs:14:8 + | +LL | fn foo() { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/impl_trait_in_trait_defined_outside_trait.rs:31:30 + | +LL | type Assoc = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | const FOO: () = { +LL | let x: Self::Assoc = 42; + | ----------- ^^ expected opaque type, found integer + | | + | expected due to this + | + = note: expected opaque type `<() as Trait2>::Assoc` + found type `{integer}` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/impl_trait_in_trait_defined_outside_trait.rs:30:11 + | +LL | const FOO: () = { + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait2.rs b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait2.rs new file mode 100644 index 0000000000000..77cdca198daea --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait2.rs @@ -0,0 +1,22 @@ +//! Check that we cannot instantiate a hidden type from another assoc type. + +#![feature(impl_trait_in_assoc_type)] + +trait Trait: Sized { + type Assoc; + type Foo; + fn foo() -> Self::Assoc; +} + +impl Trait for () { + type Assoc = impl std::fmt::Debug; + type Foo = [(); { + let x: Self::Assoc = 42; //~ ERROR: mismatched types + 3 + }]; + fn foo() -> Self::Assoc { + "" + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait2.stderr b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait2.stderr new file mode 100644 index 0000000000000..708c3f28d2d2e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait2.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/impl_trait_in_trait_defined_outside_trait2.rs:14:30 + | +LL | type Assoc = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | type Foo = [(); { +LL | let x: Self::Assoc = 42; + | ----------- ^^ expected opaque type, found integer + | | + | expected due to this + | + = note: expected opaque type `<() as Trait>::Assoc` + found type `{integer}` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait3.rs b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait3.rs new file mode 100644 index 0000000000000..dfcf733653376 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_trait_in_trait_defined_outside_trait3.rs @@ -0,0 +1,38 @@ +//! Check that non-defining assoc items can use the opaque type +//! opaquely. + +// check-pass + +#![feature(impl_trait_in_assoc_type)] + +trait Trait: Sized { + type Assoc; + fn foo(); + fn bar() -> Self::Assoc; +} + +impl Trait for () { + type Assoc = impl std::fmt::Debug; + fn foo() { + let x: Self::Assoc = Self::bar(); + } + fn bar() -> Self::Assoc { + "" + } +} + +trait Trait2: Sized { + type Assoc; + const FOO: (); + const BAR: Self::Assoc; +} + +impl Trait2 for () { + type Assoc = impl Copy; + const FOO: () = { + let x: Self::Assoc = Self::BAR; + }; + const BAR: Self::Assoc = ""; +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs new file mode 100644 index 0000000000000..baeba1d3de635 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs @@ -0,0 +1,17 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Assoc<'a, 'b>; + fn bar<'a: 'a, 'b: 'b>(_: &'a ()) -> Self::Assoc<'a, 'b>; +} + +impl Foo for () { + type Assoc<'a, 'b> = impl Sized; + fn bar<'a: 'a, 'b: 'b>(x: &'a ()) -> Self::Assoc<'a, 'b> { + let closure = |x: &'a ()| -> Self::Assoc<'b, 'a> { x }; + //~^ ERROR `<() as Foo>::Assoc<'b, 'a>` captures lifetime that does not appear in bounds + x + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.stderr b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.stderr new file mode 100644 index 0000000000000..a7d3e7f0be403 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.stderr @@ -0,0 +1,13 @@ +error[E0700]: hidden type for `<() as Foo>::Assoc<'b, 'a>` captures lifetime that does not appear in bounds + --> $DIR/in-assoc-ty-early-bound.rs:11:60 + | +LL | type Assoc<'a, 'b> = impl Sized; + | ---------- opaque type defined here +LL | fn bar<'a: 'a, 'b: 'b>(x: &'a ()) -> Self::Assoc<'a, 'b> { + | -- hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | let closure = |x: &'a ()| -> Self::Assoc<'b, 'a> { x }; + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs new file mode 100644 index 0000000000000..7452000b65dc8 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs @@ -0,0 +1,21 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Assoc<'a>; + fn bar<'a: 'a>(); +} + +impl Foo for () { + type Assoc<'a> = impl Sized; //~ ERROR unconstrained opaque type + fn bar<'a: 'a>() + where + Self::Assoc<'a>:, + { + let _ = |x: &'a ()| { + let _: Self::Assoc<'a> = x; + //~^ ERROR `<() as Foo>::Assoc<'a>` captures lifetime that does not appear in bound + }; + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr new file mode 100644 index 0000000000000..1274a8b60dea0 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr @@ -0,0 +1,22 @@ +error[E0700]: hidden type for `<() as Foo>::Assoc<'a>` captures lifetime that does not appear in bounds + --> $DIR/in-assoc-ty-early-bound2.rs:15:20 + | +LL | type Assoc<'a> = impl Sized; + | ---------- opaque type defined here +LL | fn bar<'a: 'a>() + | -- hidden type `&'a ()` captures the lifetime `'a` as defined here +... +LL | let _: Self::Assoc<'a> = x; + | ^^^^^^^^^^^^^^^ + +error: unconstrained opaque type + --> $DIR/in-assoc-ty-early-bound2.rs:9:22 + | +LL | type Assoc<'a> = impl Sized; + | ^^^^^^^^^^ + | + = note: `Assoc` must be used in combination with a concrete type within the same impl + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs new file mode 100644 index 0000000000000..0ad6e7a6f6014 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs @@ -0,0 +1,16 @@ +//! We evaluate `1 + 2` with `Reveal::All` during typeck, causing +//! us to to get the concrete type of `Bar` while computing it. +//! This again requires type checking `foo`. +#![feature(type_alias_impl_trait)] +type Bar = impl Sized; +//~^ ERROR: cycle +//~| ERROR: cycle + +fn foo() -> Bar +where + Bar: Send, +{ + [0; 1 + 2] +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr new file mode 100644 index 0000000000000..9c08b8f127d27 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -0,0 +1,50 @@ +error[E0391]: cycle detected when computing type of `Bar::{opaque#0}` + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + | +note: ...which requires computing type of opaque `Bar::{opaque#0}`... + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ +note: ...which requires type-checking `foo`... + --> $DIR/in-where-clause.rs:9:1 + | +LL | / fn foo() -> Bar +LL | | where +LL | | Bar: Send, + | |______________^ + = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }]`... + = note: ...which again requires computing type of `Bar::{opaque#0}`, completing the cycle +note: cycle used when checking that `Bar::{opaque#0}` is well-formed + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + | +note: ...which requires type-checking `foo`... + --> $DIR/in-where-clause.rs:13:9 + | +LL | [0; 1 + 2] + | ^^^^^ + = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Send`... + = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle +note: cycle used when computing type of `Bar::{opaque#0}` + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/issue-58887.rs b/tests/ui/type-alias-impl-trait/issue-58887.rs index 9675867656a96..68d85ed6b0f9b 100644 --- a/tests/ui/type-alias-impl-trait/issue-58887.rs +++ b/tests/ui/type-alias-impl-trait/issue-58887.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(impl_trait_in_assoc_type)] diff --git a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs index af1c18bbb59c8..b6906f68ded57 100644 --- a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +++ b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -4,20 +4,14 @@ // revisions: current next //[next] compile-flags: -Znext-solver // check-pass - #![feature(type_alias_impl_trait)] -trait Dummy {} -impl Dummy for () {} - -type F = impl Dummy; -fn f() -> F {} - trait Test { fn test(self); } -impl Test for F { + +impl Test for define::F { fn test(self) {} } @@ -27,7 +21,17 @@ impl Test for i32 { fn test(self) {} } +mod define { + use super::*; + + pub trait Dummy {} + impl Dummy for () {} + + pub type F = impl Dummy; + pub fn f() -> F {} +} + fn main() { - let x: F = f(); + let x = define::f(); x.test(); } diff --git a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr index 37abb3fe021bb..5e978e97d6b50 100644 --- a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `B: Bar` is not satisfied --> $DIR/issue-90400-2.rs:25:9 | LL | MyBaz(bar) - | ^^^^^^^^^^ the trait `Bar` is not implemented for `B` + | ^^^^^^^^^^ the trait `Bar` is not implemented for `B`, which is required by `MyBaz: Baz` | note: required for `MyBaz` to implement `Baz` --> $DIR/issue-90400-2.rs:30:14 diff --git a/tests/ui/type-alias-impl-trait/itiat-allow-nested-closures.bad.stderr b/tests/ui/type-alias-impl-trait/itiat-allow-nested-closures.bad.stderr new file mode 100644 index 0000000000000..4acc47eaef220 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/itiat-allow-nested-closures.bad.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/itiat-allow-nested-closures.rs:21:22 + | +LL | type Assoc = impl Sized; + | ---------- the found opaque type +... +LL | let _: i32 = closure(); + | --- ^^^^^^^^^ expected `i32`, found opaque type + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/itiat-allow-nested-closures.rs:22:9 + | +LL | fn bar() -> Self::Assoc { + | ----------- expected `()` because of return type +... +LL | 1i32 + | ^^^^ expected `()`, found `i32` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/itiat-allow-nested-closures.rs b/tests/ui/type-alias-impl-trait/itiat-allow-nested-closures.rs new file mode 100644 index 0000000000000..55994d6a3259d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/itiat-allow-nested-closures.rs @@ -0,0 +1,26 @@ +#![feature(impl_trait_in_assoc_type)] + +// revisions: ok bad +// [ok] check-pass + +trait Foo { + type Assoc; + fn bar() -> Self::Assoc; +} + +impl Foo for () { + type Assoc = impl Sized; + fn bar() -> Self::Assoc { + let closure = || -> Self::Assoc { + #[cfg(ok)] + let x: Self::Assoc = 42_i32; + #[cfg(bad)] + let x: Self::Assoc = (); + x + }; + let _: i32 = closure(); //[bad]~ ERROR mismatched types + 1i32 //[bad]~ ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs b/tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs new file mode 100644 index 0000000000000..8c9d780c1119d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs @@ -0,0 +1,20 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Assoc; + fn bar() -> Self::Assoc; +} + +impl Foo for () { + type Assoc = impl Sized; + fn bar() -> Self::Assoc { + fn foo() -> <() as Foo>::Assoc { + let x: <() as Foo>::Assoc = 42_i32; //~ ERROR mismatched types + x + }; + let _: i32 = foo(); + 1i32 + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.stderr b/tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.stderr new file mode 100644 index 0000000000000..c177201431a61 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/itiat-forbid-nested-items.rs:12:41 + | +LL | type Assoc = impl Sized; + | ---------- the expected opaque type +... +LL | let x: <() as Foo>::Assoc = 42_i32; + | ------------------ ^^^^^^ expected opaque type, found `i32` + | | + | expected due to this + | + = note: expected opaque type `<() as Foo>::Assoc` + found type `i32` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/itiat-forbid-nested-items.rs:11:12 + | +LL | fn foo() -> <() as Foo>::Assoc { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr index b5f38074632ee..a7840e0a5bf24 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied --> $DIR/multiple-def-uses-in-one-fn.rs:9:45 | LL | fn f(a: &'static A, b: B) -> (X, X) { - | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B` + | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`, which is required by `&A: Into<&'static B>` | = note: required for `&A` to implement `Into<&'static B>` help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr index d92bafce142c2..fd76526644bdd 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr @@ -1,4 +1,4 @@ -note: no errors encountered even though `span_delayed_bug` issued +note: no errors encountered even though delayed bugs were created note: those delayed bugs will now be shown as internal compiler errors diff --git a/tests/ui/type-alias-impl-trait/struct-assignment-validity.rs b/tests/ui/type-alias-impl-trait/struct-assignment-validity.rs new file mode 100644 index 0000000000000..39f0b9a02eeae --- /dev/null +++ b/tests/ui/type-alias-impl-trait/struct-assignment-validity.rs @@ -0,0 +1,31 @@ +// compile-flags: -Zvalidate-mir +// check-pass + +// Check that we don't cause cycle errors when validating pre-`Reveal::All` MIR +// that assigns opaques through normalized projections. + +#![feature(impl_trait_in_assoc_type)] + +struct Bar; + +trait Trait { + type Assoc; + fn foo() -> Foo; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo + where + Self::Assoc:, + { + let x: ::Assoc = (); + Foo { field: () } + } +} + +struct Foo { + field: ::Assoc, +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr index e4de9245951cf..913a35eb9fb0e 100644 --- a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr +++ b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/underconstrained_generic.rs:22:5 | LL | () - | ^^ the trait `Trait` is not implemented for `T` + | ^^ the trait `Trait` is not implemented for `T`, which is required by `(): ProofForConversion` | note: required for `()` to implement `ProofForConversion` --> $DIR/underconstrained_generic.rs:13:16 diff --git a/tests/ui/type/issue-101866.stderr b/tests/ui/type/issue-101866.stderr index 6f4b380b4e746..4d02153ebe20e 100644 --- a/tests/ui/type/issue-101866.stderr +++ b/tests/ui/type/issue-101866.stderr @@ -5,7 +5,7 @@ LL | fn func(); | ---------- `TraitA::func` defined here ... LL | TraitA::::func(); - | ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | ^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use the fully-qualified path to the only available implementation | diff --git a/tests/ui/type/issue-58355.stderr b/tests/ui/type/issue-58355.stderr index b6056f0fd65ad..cd8e353880241 100644 --- a/tests/ui/type/issue-58355.stderr +++ b/tests/ui/type/issue-58355.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn ToString` cannot be known at comp LL | x = Some(Box::new(callback)); | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString` + = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString`, which is required by `fn() -> dyn ToString: Fn()` = note: required because it appears within the type `fn() -> dyn ToString` = note: required for the cast from `Box dyn ToString>` to `Box (dyn ToString + 'static)>` diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr index bd7fd0392c378..137c7b0639667 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.stderr +++ b/tests/ui/typeck/bad-index-due-to-nested.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `K: Hash` is not satisfied --> $DIR/bad-index-due-to-nested.rs:20:5 | LL | map[k] - | ^^^ the trait `Hash` is not implemented for `K` + | ^^^ the trait `Hash` is not implemented for `K`, which is required by `HashMap<_, _>: Index<&_>` | note: required for `HashMap` to implement `Index<&K>` --> $DIR/bad-index-due-to-nested.rs:7:12 @@ -21,7 +21,7 @@ error[E0277]: the trait bound `V: Copy` is not satisfied --> $DIR/bad-index-due-to-nested.rs:20:5 | LL | map[k] - | ^^^ the trait `Copy` is not implemented for `V` + | ^^^ the trait `Copy` is not implemented for `V`, which is required by `HashMap<_, _>: Index<&_>` | note: required for `HashMap` to implement `Index<&K>` --> $DIR/bad-index-due-to-nested.rs:7:12 diff --git a/tests/ui/typeck/derive-sugg-arg-arity.stderr b/tests/ui/typeck/derive-sugg-arg-arity.stderr index 41b16a772ca95..382b324c4cc50 100644 --- a/tests/ui/typeck/derive-sugg-arg-arity.stderr +++ b/tests/ui/typeck/derive-sugg-arg-arity.stderr @@ -2,11 +2,7 @@ error[E0599]: the function or associated item `partial_cmp` exists for struct `A --> $DIR/derive-sugg-arg-arity.rs:5:23 | LL | pub struct A; - | ------------ - | | - | function or associated item `partial_cmp` not found for this struct - | doesn't satisfy `A: Iterator` - | doesn't satisfy `A: PartialOrd<_>` + | ------------ function or associated item `partial_cmp` not found for this struct because it doesn't satisfy `A: Iterator` or `A: PartialOrd<_>` ... LL | _ => match A::partial_cmp() {}, | ^^^^^^^^^^^ function or associated item cannot be called on `A` due to unsatisfied trait bounds diff --git a/tests/ui/typeck/issue-104510-ice.rs b/tests/ui/typeck/issue-104510-ice.rs index 157bdf07e3826..635cc8fad66f1 100644 --- a/tests/ui/typeck/issue-104510-ice.rs +++ b/tests/ui/typeck/issue-104510-ice.rs @@ -6,7 +6,7 @@ struct W(Oops); unsafe fn test() { let j = W(()); - let pointer = &j as *const _; + let pointer = &j as *const _; //~ ERROR type annotations needed core::arch::asm!( "nop", in("eax") pointer, diff --git a/tests/ui/typeck/issue-104510-ice.stderr b/tests/ui/typeck/issue-104510-ice.stderr index 143139b2c089c..774e52681849f 100644 --- a/tests/ui/typeck/issue-104510-ice.stderr +++ b/tests/ui/typeck/issue-104510-ice.stderr @@ -4,6 +4,18 @@ error[E0412]: cannot find type `Oops` in this scope LL | struct W(Oops); | ^^^^ not found in this scope -error: aborting due to 1 previous error +error[E0282]: type annotations needed for `*const W` + --> $DIR/issue-104510-ice.rs:9:9 + | +LL | let pointer = &j as *const _; + | ^^^^^^^ + | +help: consider giving `pointer` an explicit type, where the type for type parameter `T` is specified + | +LL | let pointer: *const W = &j as *const _; + | +++++++++++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0282, E0412. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/typeck/issue-31173.stderr b/tests/ui/typeck/issue-31173.stderr index d65c4306a5f28..0983147a5f0c5 100644 --- a/tests/ui/typeck/issue-31173.stderr +++ b/tests/ui/typeck/issue-31173.stderr @@ -35,12 +35,6 @@ LL | | .collect(); | | -^^^^^^^ method cannot be called due to unsatisfied trait bounds | |_________| | - --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL - | - = note: doesn't satisfy `<_ as Iterator>::Item = &_` - --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL - | - = note: doesn't satisfy `_: Iterator` | = note: the following trait bounds were not satisfied: `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index a24f9cb540fc8..d5ba157974d93 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `PathBuf: From>` is not satisfied --> $DIR/issue-90101.rs:6:10 | LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `PathBuf` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `PathBuf`, which is required by `Cow<'_, str>: Into` | | | required by a bound introduced by this call | diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed new file mode 100644 index 0000000000000..9ce46bc1a65b2 --- /dev/null +++ b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed @@ -0,0 +1,32 @@ +// run-rustfix +trait Trait {} +struct Struct; +impl Trait for Struct {} +fn foo() -> Box { + Box::new(Struct) +} +fn bar() -> impl Trait { + Struct +} +fn main() { + let _ = if true { + Box::new(Struct) + } else { + foo() //~ ERROR E0308 + }; + let _ = if true { + foo() + } else { + Box::new(Struct) //~ ERROR E0308 + }; + let _ = if true { + Box::new(Struct) as Box + } else { + Box::new(bar()) //~ ERROR E0308 + }; + let _ = if true { + Box::new(bar()) as Box + } else { + Box::new(Struct) //~ ERROR E0308 + }; +} diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs new file mode 100644 index 0000000000000..7f65a3bb59d31 --- /dev/null +++ b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs @@ -0,0 +1,32 @@ +// run-rustfix +trait Trait {} +struct Struct; +impl Trait for Struct {} +fn foo() -> Box { + Box::new(Struct) +} +fn bar() -> impl Trait { + Struct +} +fn main() { + let _ = if true { + Struct + } else { + foo() //~ ERROR E0308 + }; + let _ = if true { + foo() + } else { + Struct //~ ERROR E0308 + }; + let _ = if true { + Struct + } else { + bar() //~ ERROR E0308 + }; + let _ = if true { + bar() + } else { + Struct //~ ERROR E0308 + }; +} diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr new file mode 100644 index 0000000000000..c58bf60e7d656 --- /dev/null +++ b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr @@ -0,0 +1,94 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/suggest-box-on-divergent-if-else-arms.rs:15:9 + | +LL | let _ = if true { + | _____________- +LL | | Struct + | | ------ expected because of this +LL | | } else { +LL | | foo() + | | ^^^^^ expected `Struct`, found `Box` +LL | | }; + | |_____- `if` and `else` have incompatible types + | + = note: expected struct `Struct` + found struct `Box` +help: `Struct` implements `Trait` so you can box it to coerce to the trait object `Box` + | +LL | Box::new(Struct) + | +++++++++ + + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/suggest-box-on-divergent-if-else-arms.rs:20:9 + | +LL | let _ = if true { + | _____________- +LL | | foo() + | | ----- expected because of this +LL | | } else { +LL | | Struct + | | ^^^^^^ expected `Box`, found `Struct` +LL | | }; + | |_____- `if` and `else` have incompatible types + | + = note: expected struct `Box` + found struct `Struct` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(Struct) + | +++++++++ + + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/suggest-box-on-divergent-if-else-arms.rs:25:9 + | +LL | fn bar() -> impl Trait { + | ---------- the found opaque type +... +LL | let _ = if true { + | _____________- +LL | | Struct + | | ------ expected because of this +LL | | } else { +LL | | bar() + | | ^^^^^ expected `Struct`, found opaque type +LL | | }; + | |_____- `if` and `else` have incompatible types + | + = note: expected struct `Struct` + found opaque type `impl Trait` +help: `Struct` implements `Trait` so you can box both arms and coerce to the trait object `Box` + | +LL ~ Box::new(Struct) as Box +LL | } else { +LL ~ Box::new(bar()) + | + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/suggest-box-on-divergent-if-else-arms.rs:30:9 + | +LL | fn bar() -> impl Trait { + | ---------- the expected opaque type +... +LL | let _ = if true { + | _____________- +LL | | bar() + | | ----- expected because of this +LL | | } else { +LL | | Struct + | | ^^^^^^ expected opaque type, found `Struct` +LL | | }; + | |_____- `if` and `else` have incompatible types + | + = note: expected opaque type `impl Trait` + found struct `Struct` +help: `Struct` implements `Trait` so you can box both arms and coerce to the trait object `Box` + | +LL ~ Box::new(bar()) as Box +LL | } else { +LL ~ Box::new(Struct) + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index b9fca1a1b54b8..f5311b6e8ed7f 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -17,7 +17,7 @@ error[E0277]: `UnsafeCell` cannot be shared between threads safely LL | is_sync::(); | ^^^^^^^^^^^^^ `UnsafeCell` cannot be shared between threads safely | - = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell` + = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell`, which is required by `MyTypeWUnsafe: Sync` note: required because it appears within the type `MyTypeWUnsafe` --> $DIR/typeck-default-trait-impl-negation-sync.rs:21:8 | @@ -35,7 +35,7 @@ error[E0277]: `Managed` cannot be shared between threads safely LL | is_sync::(); | ^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely | - = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed` + = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed`, which is required by `MyTypeManaged: Sync` note: required because it appears within the type `MyTypeManaged` --> $DIR/typeck-default-trait-impl-negation-sync.rs:25:8 | diff --git a/tests/ui/typeck/typeck-unsafe-always-share.stderr b/tests/ui/typeck/typeck-unsafe-always-share.stderr index 154e504996bc4..3eb792b82e0f4 100644 --- a/tests/ui/typeck/typeck-unsafe-always-share.stderr +++ b/tests/ui/typeck/typeck-unsafe-always-share.stderr @@ -36,7 +36,7 @@ LL | test(ms); | | | required by a bound introduced by this call | - = help: within `MySync`, the trait `Sync` is not implemented for `UnsafeCell` + = help: within `MySync`, the trait `Sync` is not implemented for `UnsafeCell`, which is required by `MySync: Sync` note: required because it appears within the type `MySync` --> $DIR/typeck-unsafe-always-share.rs:8:8 | diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index f6d1fb6a23d4c..4eba14f5a93fb 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -198,7 +198,6 @@ trait Qux { //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types } impl Qux for Struct { - //~^ ERROR: not all trait items implemented, missing: `F` type A = _; //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types type B = _; diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index bfcc76c1dae7d..a4325b01f02c4 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -29,7 +29,7 @@ LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier error: associated constant in `impl` without body - --> $DIR/typeck_type_placeholder_item.rs:206:5 + --> $DIR/typeck_type_placeholder_item.rs:205:5 | LL | const C: _; | ^^^^^^^^^^- @@ -411,7 +411,7 @@ LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/typeck_type_placeholder_item.rs:217:31 + --> $DIR/typeck_type_placeholder_item.rs:216:31 | LL | fn value() -> Option<&'static _> { | ----------------^- @@ -420,7 +420,7 @@ LL | fn value() -> Option<&'static _> { | help: replace with the correct return type: `Option<&'static u8>` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants - --> $DIR/typeck_type_placeholder_item.rs:222:10 + --> $DIR/typeck_type_placeholder_item.rs:221:10 | LL | const _: Option<_> = map(value); | ^^^^^^^^^ @@ -429,7 +429,7 @@ LL | const _: Option<_> = map(value); | help: replace with the correct type: `Option` error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/typeck_type_placeholder_item.rs:225:31 + --> $DIR/typeck_type_placeholder_item.rs:224:31 | LL | fn evens_squared(n: usize) -> _ { | ^ @@ -438,13 +438,13 @@ LL | fn evens_squared(n: usize) -> _ { | help: replace with an appropriate return type: `impl Iterator` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants - --> $DIR/typeck_type_placeholder_item.rs:230:10 + --> $DIR/typeck_type_placeholder_item.rs:229:10 | LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^ not allowed in type signatures | -note: however, the inferred type `Map, {closure@typeck_type_placeholder_item.rs:230:29}>, {closure@typeck_type_placeholder_item.rs:230:49}>` cannot be named - --> $DIR/typeck_type_placeholder_item.rs:230:14 +note: however, the inferred type `Map, {closure@typeck_type_placeholder_item.rs:229:29}>, {closure@typeck_type_placeholder_item.rs:229:49}>` cannot be named + --> $DIR/typeck_type_placeholder_item.rs:229:14 | LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -631,25 +631,25 @@ LL | fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; } | ~~~~~~~~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types - --> $DIR/typeck_type_placeholder_item.rs:202:14 + --> $DIR/typeck_type_placeholder_item.rs:201:14 | LL | type A = _; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types - --> $DIR/typeck_type_placeholder_item.rs:204:14 + --> $DIR/typeck_type_placeholder_item.rs:203:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:206:14 + --> $DIR/typeck_type_placeholder_item.rs:205:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:209:14 + --> $DIR/typeck_type_placeholder_item.rs:208:14 | LL | const D: _ = 42; | ^ @@ -657,16 +657,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error[E0046]: not all trait items implemented, missing: `F` - --> $DIR/typeck_type_placeholder_item.rs:200:1 - | -LL | type F: std::ops::Fn(_); - | ----------------------- `F` from trait -... -LL | impl Qux for Struct { - | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation - -error: aborting due to 72 previous errors +error: aborting due to 71 previous errors -Some errors have detailed explanations: E0046, E0121, E0282, E0403. -For more information about an error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0121, E0282, E0403. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index ae0a06e6328df..e90784a54ae0d 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -59,7 +59,7 @@ error[E0277]: cannot add `u32` to `i32` --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 | LL | >::add(1, 2); - | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed index 5be6ff8e7e14e..700e4f2542384 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs index d7072aa118161..66ba9b24dac2f 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr index 54e62f34fbaa3..f012120e550d7 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:13:17 + --> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:14:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed index 0f1be586589e2..56682db3b0b43 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed @@ -1,5 +1,6 @@ // edition:2018 // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs index 59f7e472e2d34..5302b2f1576b6 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs @@ -1,5 +1,6 @@ // edition:2018 // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr index 36f3e9ef14527..7d675dd41e904 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:14:17 + --> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:15:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed index 55c7470960eb2..f3adc7e7fad32 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs index 42a35b0216119..1e084e9ad41bb 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr index 92b7a9c2af893..8aa0e52c688db 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-trait-impl-region-2015.rs:10:17 + --> $DIR/where-clause-trait-impl-region-2015.rs:11:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed index 09b96fe5ea42a..dd8074abed728 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed @@ -1,6 +1,8 @@ // run-rustfix // edition:2018 +#![allow(dead_code)] + trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs index 445f38cbee187..4fc9c71b17943 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs @@ -1,6 +1,8 @@ // run-rustfix // edition:2018 +#![allow(dead_code)] + trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr index 63d8b99ed18fb..22940d0b0b18d 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-trait-impl-region-2018.rs:11:17 + --> $DIR/where-clause-trait-impl-region-2018.rs:13:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/union/issue-81199.rs b/tests/ui/union/issue-81199.rs index b8b0d9d33e791..2083ee15d87bd 100644 --- a/tests/ui/union/issue-81199.rs +++ b/tests/ui/union/issue-81199.rs @@ -9,7 +9,7 @@ union PtrRepr { #[repr(C)] struct PtrComponents { - data_address: *const (), + data_pointer: *const (), metadata: ::Metadata, } diff --git a/tests/ui/union/projection-as-union-type-error-2.stderr b/tests/ui/union/projection-as-union-type-error-2.stderr index 3b073ca1fb4e0..39cdf30d8605a 100644 --- a/tests/ui/union/projection-as-union-type-error-2.stderr +++ b/tests/ui/union/projection-as-union-type-error-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `u8: NotImplemented` is not satisfied --> $DIR/projection-as-union-type-error-2.rs:18:8 | LL | a: ::Identity, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8`, which is required by `u8: Identity` | help: this trait has no implementations, consider adding one --> $DIR/projection-as-union-type-error-2.rs:9:1 diff --git a/tests/ui/union/union-derive-clone.stderr b/tests/ui/union/union-derive-clone.stderr index 39f1e32e6eb71..a2b81f0dba1c3 100644 --- a/tests/ui/union/union-derive-clone.stderr +++ b/tests/ui/union/union-derive-clone.stderr @@ -17,10 +17,7 @@ error[E0599]: the method `clone` exists for union `U5`, but its tra --> $DIR/union-derive-clone.rs:35:15 | LL | union U5 { - | ----------- - | | - | method `clone` not found for this union - | doesn't satisfy `U5: Clone` + | ----------- method `clone` not found for this union because it doesn't satisfy `U5: Clone` ... LL | struct CloneNoCopy; | ------------------ doesn't satisfy `CloneNoCopy: Copy` diff --git a/tests/ui/union/union-pat-refutability.rs b/tests/ui/union/union-pat-refutability.rs index 17ac6c6dfa9bf..edcc1add38fde 100644 --- a/tests/ui/union/union-pat-refutability.rs +++ b/tests/ui/union/union-pat-refutability.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] -#![allow(illegal_floating_point_literal_pattern)] #[repr(u32)] enum Tag { diff --git a/tests/ui/unsafe/const_pat_in_layout_restricted.rs b/tests/ui/unsafe/const_pat_in_layout_restricted.rs index 5bc7a7113e4f6..9a085958c1080 100644 --- a/tests/ui/unsafe/const_pat_in_layout_restricted.rs +++ b/tests/ui/unsafe/const_pat_in_layout_restricted.rs @@ -2,7 +2,6 @@ // unsafe because they're within a pattern for a layout constrained stuct. // check-pass -#![allow(incomplete_features)] #![feature(rustc_attrs)] #![feature(inline_const_pat)] diff --git a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr index 1187c2d80f388..2eb1754392e1a 100644 --- a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr +++ b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr @@ -4,6 +4,7 @@ warning: call to unsafe function `unsf` is unsafe and requires unsafe block (err LL | unsf(); | ^^^^^^ call to unsafe function | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:9:1 diff --git a/tests/ui/unsafe/union_destructure.rs b/tests/ui/unsafe/union_destructure.rs index d0cf8640eaa22..bb75dbf0997ce 100644 --- a/tests/ui/unsafe/union_destructure.rs +++ b/tests/ui/unsafe/union_destructure.rs @@ -1,4 +1,5 @@ // run-pass +#![allow(unreachable_patterns)] #[derive(Copy, Clone)] #[allow(dead_code)] diff --git a/tests/ui/unsafe/auxiliary/external_unsafe_macro.rs b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/auxiliary/external_unsafe_macro.rs similarity index 100% rename from tests/ui/unsafe/auxiliary/external_unsafe_macro.rs rename to tests/ui/unsafe/unsafe_op_in_unsafe_fn/auxiliary/external_unsafe_macro.rs diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs new file mode 100644 index 0000000000000..4196b1cae249d --- /dev/null +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs @@ -0,0 +1,20 @@ +// edition: 2024 +// compile-flags: -Zunstable-options +// check-pass + +// Tests that `unsafe_op_in_unsafe_fn` is warn-by-default in edition 2024 and that the +// `unused_unsafe` lint does not consider the inner unsafe block to be unused. +#![crate_type = "lib"] +#![deny(unused_unsafe)] + +unsafe fn unsf() {} + +unsafe fn foo() { + unsf(); + //~^ WARN + + // no unused_unsafe + unsafe { + unsf(); + } +} diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr new file mode 100644 index 0000000000000..e6d1d4e5cc780 --- /dev/null +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr @@ -0,0 +1,17 @@ +warning: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133) + --> $DIR/edition_2024_default.rs:13:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 + = note: consult the function's documentation for information on how to avoid undefined behavior +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/edition_2024_default.rs:12:1 + | +LL | unsafe fn foo() { + | ^^^^^^^^^^^^^^^ + = note: `#[warn(unsafe_op_in_unsafe_fn)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.rs b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.rs new file mode 100644 index 0000000000000..ec04bf8d63143 --- /dev/null +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.rs @@ -0,0 +1,9 @@ +#![deny(rust_2024_compatibility)] +#![crate_type = "lib"] + +unsafe fn unsf() {} + +unsafe fn foo() { + unsf(); + //~^ ERROR call to unsafe function `unsf` is unsafe and requires unsafe block +} diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr new file mode 100644 index 0000000000000..5092c1e689d67 --- /dev/null +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr @@ -0,0 +1,22 @@ +error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133) + --> $DIR/in_2024_compatibility.rs:7:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 + = note: consult the function's documentation for information on how to avoid undefined behavior +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/in_2024_compatibility.rs:6:1 + | +LL | unsafe fn foo() { + | ^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/in_2024_compatibility.rs:1:9 + | +LL | #![deny(rust_2024_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(rust_2024_compatibility)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.rs similarity index 100% rename from tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs rename to tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.rs diff --git a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr similarity index 87% rename from tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr rename to tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr index ea0659b2e104d..4bc604a110ea1 100644 --- a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -4,6 +4,7 @@ error: call to unsafe function `unsf` is unsafe and requires unsafe block (error LL | unsf(); | ^^^^^^ call to unsafe function | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:1 @@ -22,6 +23,7 @@ error: dereference of raw pointer is unsafe and requires unsafe block (error E01 LL | *PTR; | ^^^^ dereference of raw pointer | + = note: for more information, see issue #71668 = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) @@ -30,6 +32,7 @@ error: use of mutable static is unsafe and requires unsafe block (error E0133) LL | VOID = (); | ^^^^ use of mutable static | + = note: for more information, see issue #71668 = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error: unnecessary `unsafe` block @@ -50,6 +53,7 @@ error: call to unsafe function `unsf` is unsafe and requires unsafe block (error LL | unsf(); | ^^^^^^ call to unsafe function | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:23:1 @@ -69,6 +73,7 @@ error: dereference of raw pointer is unsafe and requires unsafe block (error E01 LL | *PTR; | ^^^^ dereference of raw pointer | + = note: for more information, see issue #71668 = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) @@ -77,6 +82,7 @@ error: use of mutable static is unsafe and requires unsafe block (error E0133) LL | VOID = (); | ^^^^ use of mutable static | + = note: for more information, see issue #71668 = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error: unnecessary `unsafe` block diff --git a/tests/ui/unsafe/wrapping-unsafe-block-sugg.fixed b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.fixed similarity index 56% rename from tests/ui/unsafe/wrapping-unsafe-block-sugg.fixed rename to tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.fixed index 20f4fe847daca..8f5cc014a3bab 100644 --- a/tests/ui/unsafe/wrapping-unsafe-block-sugg.fixed +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.fixed @@ -11,50 +11,60 @@ unsafe fn unsf() {} pub unsafe fn foo() { unsafe { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default unsf(); //~ ERROR call to unsafe function `unsf` is unsafe - //~^ NOTE - //~| NOTE + //~^ NOTE call to unsafe function + //~| NOTE for more information, see issue #71668 + //~| NOTE consult the function's documentation unsf(); //~ ERROR call to unsafe function `unsf` is unsafe - //~^ NOTE - //~| NOTE + //~^ NOTE call to unsafe function + //~| NOTE for more information, see issue #71668 + //~| NOTE consult the function's documentation }} pub unsafe fn bar(x: *const i32) -> i32 { unsafe { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default let y = *x; //~ ERROR dereference of raw pointer is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE dereference of raw pointer + //~| NOTE for more information, see issue #71668 + //~| NOTE raw pointers may be null y + *x //~ ERROR dereference of raw pointer is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE dereference of raw pointer + //~| NOTE for more information, see issue #71668 + //~| NOTE raw pointers may be null }} static mut BAZ: i32 = 0; pub unsafe fn baz() -> i32 { unsafe { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default let y = BAZ; //~ ERROR use of mutable static is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE use of mutable static + //~| NOTE for more information, see issue #71668 + //~| NOTE mutable statics can be mutated by multiple threads y + BAZ //~ ERROR use of mutable static is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE use of mutable static + //~| NOTE for more information, see issue #71668 + //~| NOTE mutable statics can be mutated by multiple threads }} macro_rules! unsafe_macro { () => (unsf()) } //~^ ERROR call to unsafe function `unsf` is unsafe -//~| NOTE -//~| NOTE +//~| NOTE call to unsafe function +//~| NOTE for more information, see issue #71668 +//~| NOTE consult the function's documentation //~| ERROR call to unsafe function `unsf` is unsafe -//~| NOTE -//~| NOTE +//~| NOTE call to unsafe function +//~| NOTE for more information, see issue #71668 +//~| NOTE consult the function's documentation pub unsafe fn unsafe_in_macro() { unsafe { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default unsafe_macro!(); - //~^ NOTE - //~| NOTE + //~^ NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion unsafe_macro!(); - //~^ NOTE - //~| NOTE + //~^ NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion }} pub unsafe fn unsafe_in_external_macro() { diff --git a/tests/ui/unsafe/wrapping-unsafe-block-sugg.rs b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.rs similarity index 56% rename from tests/ui/unsafe/wrapping-unsafe-block-sugg.rs rename to tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.rs index 13a446d2d2480..90c9e28239693 100644 --- a/tests/ui/unsafe/wrapping-unsafe-block-sugg.rs +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.rs @@ -11,50 +11,60 @@ unsafe fn unsf() {} pub unsafe fn foo() { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default unsf(); //~ ERROR call to unsafe function `unsf` is unsafe - //~^ NOTE - //~| NOTE + //~^ NOTE call to unsafe function + //~| NOTE for more information, see issue #71668 + //~| NOTE consult the function's documentation unsf(); //~ ERROR call to unsafe function `unsf` is unsafe - //~^ NOTE - //~| NOTE + //~^ NOTE call to unsafe function + //~| NOTE for more information, see issue #71668 + //~| NOTE consult the function's documentation } pub unsafe fn bar(x: *const i32) -> i32 { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default let y = *x; //~ ERROR dereference of raw pointer is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE dereference of raw pointer + //~| NOTE for more information, see issue #71668 + //~| NOTE raw pointers may be null y + *x //~ ERROR dereference of raw pointer is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE dereference of raw pointer + //~| NOTE for more information, see issue #71668 + //~| NOTE raw pointers may be null } static mut BAZ: i32 = 0; pub unsafe fn baz() -> i32 { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default let y = BAZ; //~ ERROR use of mutable static is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE use of mutable static + //~| NOTE for more information, see issue #71668 + //~| NOTE mutable statics can be mutated by multiple threads y + BAZ //~ ERROR use of mutable static is unsafe and requires unsafe block - //~^ NOTE - //~| NOTE + //~^ NOTE use of mutable static + //~| NOTE for more information, see issue #71668 + //~| NOTE mutable statics can be mutated by multiple threads } macro_rules! unsafe_macro { () => (unsf()) } //~^ ERROR call to unsafe function `unsf` is unsafe -//~| NOTE -//~| NOTE +//~| NOTE call to unsafe function +//~| NOTE for more information, see issue #71668 +//~| NOTE consult the function's documentation //~| ERROR call to unsafe function `unsf` is unsafe -//~| NOTE -//~| NOTE +//~| NOTE call to unsafe function +//~| NOTE for more information, see issue #71668 +//~| NOTE consult the function's documentation pub unsafe fn unsafe_in_macro() { //~^ NOTE an unsafe function restricts its caller, but its body is safe by default unsafe_macro!(); - //~^ NOTE - //~| NOTE + //~^ NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion unsafe_macro!(); - //~^ NOTE - //~| NOTE + //~^ NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion } pub unsafe fn unsafe_in_external_macro() { diff --git a/tests/ui/unsafe/wrapping-unsafe-block-sugg.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr similarity index 74% rename from tests/ui/unsafe/wrapping-unsafe-block-sugg.stderr rename to tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr index 84b58bc028858..b9f5969474d00 100644 --- a/tests/ui/unsafe/wrapping-unsafe-block-sugg.stderr +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr @@ -4,6 +4,7 @@ error: call to unsafe function `unsf` is unsafe and requires unsafe block (error LL | unsf(); | ^^^^^^ call to unsafe function | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/wrapping-unsafe-block-sugg.rs:11:1 @@ -17,57 +18,62 @@ LL | #![deny(unsafe_op_in_unsafe_fn)] | ^^^^^^^^^^^^^^^^^^^^^^ error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:16:5 + --> $DIR/wrapping-unsafe-block-sugg.rs:17:5 | LL | unsf(); | ^^^^^^ call to unsafe function | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:23:13 + --> $DIR/wrapping-unsafe-block-sugg.rs:25:13 | LL | let y = *x; | ^^ dereference of raw pointer | + = note: for more information, see issue #71668 = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior note: an unsafe function restricts its caller, but its body is safe by default - --> $DIR/wrapping-unsafe-block-sugg.rs:21:1 + --> $DIR/wrapping-unsafe-block-sugg.rs:23:1 | LL | pub unsafe fn bar(x: *const i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:26:9 + --> $DIR/wrapping-unsafe-block-sugg.rs:29:9 | LL | y + *x | ^^ dereference of raw pointer | + = note: for more information, see issue #71668 = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:34:13 + --> $DIR/wrapping-unsafe-block-sugg.rs:38:13 | LL | let y = BAZ; | ^^^ use of mutable static | + = note: for more information, see issue #71668 = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior note: an unsafe function restricts its caller, but its body is safe by default - --> $DIR/wrapping-unsafe-block-sugg.rs:32:1 + --> $DIR/wrapping-unsafe-block-sugg.rs:36:1 | LL | pub unsafe fn baz() -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:37:9 + --> $DIR/wrapping-unsafe-block-sugg.rs:42:9 | LL | y + BAZ | ^^^ use of mutable static | + = note: for more information, see issue #71668 = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:42:36 + --> $DIR/wrapping-unsafe-block-sugg.rs:48:36 | LL | macro_rules! unsafe_macro { () => (unsf()) } | ^^^^^^ call to unsafe function @@ -75,16 +81,17 @@ LL | macro_rules! unsafe_macro { () => (unsf()) } LL | unsafe_macro!(); | --------------- in this macro invocation | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default - --> $DIR/wrapping-unsafe-block-sugg.rs:50:1 + --> $DIR/wrapping-unsafe-block-sugg.rs:58:1 | LL | pub unsafe fn unsafe_in_macro() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `unsafe_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: call to unsafe function `unsf` is unsafe and requires unsafe block (error E0133) - --> $DIR/wrapping-unsafe-block-sugg.rs:42:36 + --> $DIR/wrapping-unsafe-block-sugg.rs:48:36 | LL | macro_rules! unsafe_macro { () => (unsf()) } | ^^^^^^ call to unsafe function @@ -92,6 +99,7 @@ LL | macro_rules! unsafe_macro { () => (unsf()) } LL | unsafe_macro!(); | --------------- in this macro invocation | + = note: for more information, see issue #71668 = note: consult the function's documentation for information on how to avoid undefined behavior = note: this error originates in the macro `unsafe_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unsized-locals/issue-50940-with-feature.stderr b/tests/ui/unsized-locals/issue-50940-with-feature.stderr index b39eb2e70bbae..4c06566709ede 100644 --- a/tests/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/tests/ui/unsized-locals/issue-50940-with-feature.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | - = help: within `A`, the trait `Sized` is not implemented for `str` + = help: within `A`, the trait `Sized` is not implemented for `str`, which is required by `A: Sized` note: required because it appears within the type `A` --> $DIR/issue-50940-with-feature.rs:5:12 | diff --git a/tests/ui/unsized-locals/rust-call.stderr b/tests/ui/unsized-locals/rust-call.stderr index 9eb0f3dabcca1..b2e13b553e921 100644 --- a/tests/ui/unsized-locals/rust-call.stderr +++ b/tests/ui/unsized-locals/rust-call.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | f(*slice); | ^^^^^^ doesn't have a size known at compile-time | - = help: within `([u8],)`, the trait `Sized` is not implemented for `[u8]` + = help: within `([u8],)`, the trait `Sized` is not implemented for `[u8]`, which is required by `([u8],): Sized` = note: required because it appears within the type `([u8],)` = note: argument required to be sized due to `extern "rust-call"` ABI diff --git a/tests/ui/unsized-locals/unsized-exprs.stderr b/tests/ui/unsized-locals/unsized-exprs.stderr index a7f57e3fd1566..6da37749facbb 100644 --- a/tests/ui/unsized-locals/unsized-exprs.stderr +++ b/tests/ui/unsized-locals/unsized-exprs.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]` + = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]`, which is required by `({integer}, [u8]): Sized` = note: required because it appears within the type `({integer}, [u8])` = note: tuples must have a statically known size to be initialized @@ -14,7 +14,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `A<[u8]>: Sized` note: required because it appears within the type `A<[u8]>` --> $DIR/unsized-exprs.rs:3:8 | @@ -26,9 +26,9 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> $DIR/unsized-exprs.rs:26:22 | LL | udrop::>(A(*foo())); - | ^ doesn't have a size known at compile-time + | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `A<[u8]>: Sized` note: required because it appears within the type `A<[u8]>` --> $DIR/unsized-exprs.rs:3:8 | diff --git a/tests/ui/unsized/unsized-bare-typaram.stderr b/tests/ui/unsized/unsized-bare-typaram.stderr index aa3f8fae72a17..4202e76b6a2ae 100644 --- a/tests/ui/unsized/unsized-bare-typaram.stderr +++ b/tests/ui/unsized/unsized-bare-typaram.stderr @@ -7,10 +7,10 @@ LL | fn foo() { bar::() } | this type parameter needs to be `Sized` | note: required by a bound in `bar` - --> $DIR/unsized-bare-typaram.rs:1:8 + --> $DIR/unsized-bare-typaram.rs:1:11 | LL | fn bar() { } - | ^ required by this bound in `bar` + | ^^^^^ required by this bound in `bar` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn foo() { bar::() } diff --git a/tests/ui/unsized/unsized-enum.stderr b/tests/ui/unsized/unsized-enum.stderr index 8c56a83a5122e..5a30d7fab65a7 100644 --- a/tests/ui/unsized/unsized-enum.stderr +++ b/tests/ui/unsized/unsized-enum.stderr @@ -6,11 +6,11 @@ LL | fn foo2() { not_sized::>() } | | | this type parameter needs to be `Sized` | -note: required by a bound in `Foo` +note: required by an implicit `Sized` bound in `Foo` --> $DIR/unsized-enum.rs:4:10 | LL | enum Foo { FooSome(U), FooNone } - | ^ required by this bound in `Foo` + | ^ required by the implicit `Sized` requirement on this type parameter in `Foo` help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box` --> $DIR/unsized-enum.rs:4:10 | diff --git a/tests/ui/unsized/unsized-enum2.stderr b/tests/ui/unsized/unsized-enum2.stderr index 71cf782120e57..48cca6eb4bd06 100644 --- a/tests/ui/unsized/unsized-enum2.stderr +++ b/tests/ui/unsized/unsized-enum2.stderr @@ -320,7 +320,7 @@ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot b LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)` + = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)`, which is required by `Path1: Sized` note: required because it appears within the type `Path1` --> $DIR/unsized-enum2.rs:16:8 | @@ -343,7 +343,7 @@ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot b LL | VJ{x: Path2}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)` + = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)`, which is required by `Path2: Sized` note: required because it appears within the type `Path2` --> $DIR/unsized-enum2.rs:17:8 | @@ -366,7 +366,7 @@ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot b LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)` + = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)`, which is required by `Path3: Sized` note: required because it appears within the type `Path3` --> $DIR/unsized-enum2.rs:18:8 | @@ -389,7 +389,7 @@ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot b LL | VL{u: isize, x: Path4}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)` + = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)`, which is required by `Path4: Sized` note: required because it appears within the type `Path4` --> $DIR/unsized-enum2.rs:19:8 | diff --git a/tests/ui/unsized/unsized-inherent-impl-self-type.stderr b/tests/ui/unsized/unsized-inherent-impl-self-type.stderr index 3e16a20d726dc..5a379f4065aa7 100644 --- a/tests/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/tests/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -6,11 +6,11 @@ LL | impl S5 { | | | this type parameter needs to be `Sized` | -note: required by a bound in `S5` +note: required by an implicit `Sized` bound in `S5` --> $DIR/unsized-inherent-impl-self-type.rs:5:11 | LL | struct S5(Y); - | ^ required by this bound in `S5` + | ^ required by the implicit `Sized` requirement on this type parameter in `S5` help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-inherent-impl-self-type.rs:5:11 | diff --git a/tests/ui/unsized/unsized-struct.stderr b/tests/ui/unsized/unsized-struct.stderr index 4e7cb09f0ccaf..06c4ffb7773c6 100644 --- a/tests/ui/unsized/unsized-struct.stderr +++ b/tests/ui/unsized/unsized-struct.stderr @@ -6,11 +6,11 @@ LL | fn foo2() { not_sized::>() } | | | this type parameter needs to be `Sized` | -note: required by a bound in `Foo` +note: required by an implicit `Sized` bound in `Foo` --> $DIR/unsized-struct.rs:4:12 | LL | struct Foo { data: T } - | ^ required by this bound in `Foo` + | ^ required by the implicit `Sized` requirement on this type parameter in `Foo` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/unsized-struct.rs:4:12 | @@ -38,10 +38,10 @@ note: required because it appears within the type `Bar` LL | struct Bar { data: T } | ^^^ note: required by a bound in `is_sized` - --> $DIR/unsized-struct.rs:1:13 + --> $DIR/unsized-struct.rs:1:15 | LL | fn is_sized() { } - | ^ required by this bound in `is_sized` + | ^^^^^ required by this bound in `is_sized` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn bar2() { is_sized::>() } diff --git a/tests/ui/unsized/unsized-trait-impl-self-type.stderr b/tests/ui/unsized/unsized-trait-impl-self-type.stderr index 5bc8dc590cacb..3b684193b4aca 100644 --- a/tests/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/tests/ui/unsized/unsized-trait-impl-self-type.stderr @@ -6,11 +6,11 @@ LL | impl T3 for S5 { | | | this type parameter needs to be `Sized` | -note: required by a bound in `S5` +note: required by an implicit `Sized` bound in `S5` --> $DIR/unsized-trait-impl-self-type.rs:8:11 | LL | struct S5(Y); - | ^ required by this bound in `S5` + | ^ required by the implicit `Sized` requirement on this type parameter in `S5` help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-trait-impl-self-type.rs:8:11 | diff --git a/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr b/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr index e9353d2bbd94a..79fc9567dae6f 100644 --- a/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -6,11 +6,11 @@ LL | impl T2 for S4 { | | | this type parameter needs to be `Sized` | -note: required by a bound in `T2` +note: required by an implicit `Sized` bound in `T2` --> $DIR/unsized-trait-impl-trait-arg.rs:4:10 | LL | trait T2 { - | ^ required by this bound in `T2` + | ^ required by the implicit `Sized` requirement on this type parameter in `T2` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl T2 for S4 { diff --git a/tests/ui/unsized/unsized3.stderr b/tests/ui/unsized/unsized3.stderr index a11243980d1a3..c7a145b1c5171 100644 --- a/tests/ui/unsized/unsized3.stderr +++ b/tests/ui/unsized/unsized3.stderr @@ -6,11 +6,11 @@ LL | fn f1(x: &X) { LL | f2::(x); | ^ doesn't have a size known at compile-time | -note: required by a bound in `f2` +note: required by an implicit `Sized` bound in `f2` --> $DIR/unsized3.rs:10:7 | LL | fn f2(x: &X) { - | ^ required by this bound in `f2` + | ^ required by the implicit `Sized` requirement on this type parameter in `f2` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f1(x: &X) { @@ -29,11 +29,11 @@ LL | fn f3(x: &X) { LL | f4::(x); | ^ doesn't have a size known at compile-time | -note: required by a bound in `f4` +note: required by an implicit `Sized` bound in `f4` --> $DIR/unsized3.rs:21:7 | LL | fn f4(x: &X) { - | ^ required by this bound in `f4` + | ^ required by the implicit `Sized` requirement on this type parameter in `f4` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f3(x: &X) { @@ -59,11 +59,11 @@ note: required because it appears within the type `S` | LL | struct S { | ^ -note: required by a bound in `f5` +note: required by an implicit `Sized` bound in `f5` --> $DIR/unsized3.rs:24:7 | LL | fn f5(x: &Y) {} - | ^ required by this bound in `f5` + | ^ required by the implicit `Sized` requirement on this type parameter in `f5` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f8(x1: &S, x2: &S) { @@ -131,11 +131,11 @@ note: required because it appears within the type `S` LL | struct S { | ^ = note: required because it appears within the type `({integer}, S)` -note: required by a bound in `f5` +note: required by an implicit `Sized` bound in `f5` --> $DIR/unsized3.rs:24:7 | LL | fn f5(x: &Y) {} - | ^ required by this bound in `f5` + | ^ required by the implicit `Sized` requirement on this type parameter in `f5` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f10(x1: Box>) { diff --git a/tests/ui/unsized/unsized7.stderr b/tests/ui/unsized/unsized7.stderr index 2edde15965343..6e9c052a07022 100644 --- a/tests/ui/unsized/unsized7.stderr +++ b/tests/ui/unsized/unsized7.stderr @@ -6,11 +6,11 @@ LL | impl T1 for S3 { | | | this type parameter needs to be `Sized` | -note: required by a bound in `T1` +note: required by an implicit `Sized` bound in `T1` --> $DIR/unsized7.rs:7:10 | LL | trait T1 { - | ^ required by this bound in `T1` + | ^ required by the implicit `Sized` requirement on this type parameter in `T1` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl T1 for S3 { diff --git a/tests/ui/variance/variance-regions-unused-direct.stderr b/tests/ui/variance/variance-regions-unused-direct.stderr index 1a600f5b0580f..4dc2af6ce2cc8 100644 --- a/tests/ui/variance/variance-regions-unused-direct.stderr +++ b/tests/ui/variance/variance-regions-unused-direct.stderr @@ -1,16 +1,16 @@ -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/variance-regions-unused-direct.rs:5:18 | LL | struct Bivariant<'a>; - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `'d` is never used +error[E0392]: lifetime parameter `'d` is never used --> $DIR/variance-regions-unused-direct.rs:7:19 | LL | struct Struct<'a, 'd> { - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'d`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/variance/variance-regions-unused-indirect.stderr b/tests/ui/variance/variance-regions-unused-indirect.stderr index 14fdd849294b1..ec4d480baab78 100644 --- a/tests/ui/variance/variance-regions-unused-indirect.stderr +++ b/tests/ui/variance/variance-regions-unused-indirect.stderr @@ -21,19 +21,19 @@ LL | enum Bar<'a> { LL ~ Bar1(Box>) | -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:3:10 | LL | enum Foo<'a> { - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:8:10 | LL | enum Bar<'a> { - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/variance/variance-unused-region-param.stderr b/tests/ui/variance/variance-unused-region-param.stderr index 7c7ec40ba35c3..b9c08bd43c454 100644 --- a/tests/ui/variance/variance-unused-region-param.stderr +++ b/tests/ui/variance/variance-unused-region-param.stderr @@ -1,16 +1,16 @@ -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/variance-unused-region-param.rs:3:19 | LL | struct SomeStruct<'a> { x: u32 } - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `'a` is never used +error[E0392]: lifetime parameter `'a` is never used --> $DIR/variance-unused-region-param.rs:4:15 | LL | enum SomeEnum<'a> { Nothing } - | ^^ unused parameter + | ^^ unused lifetime parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/variance/variance-unused-type-param.stderr b/tests/ui/variance/variance-unused-type-param.stderr index e612da118f058..3011b7bd18fa7 100644 --- a/tests/ui/variance/variance-unused-type-param.stderr +++ b/tests/ui/variance/variance-unused-type-param.stderr @@ -1,51 +1,51 @@ -error[E0392]: parameter `A` is never used +error[E0392]: type parameter `A` is never used --> $DIR/variance-unused-type-param.rs:6:19 | LL | struct SomeStruct { x: u32 } - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `A` to be a const parameter, use `const A: usize` instead + = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead -error[E0392]: parameter `A` is never used +error[E0392]: type parameter `A` is never used --> $DIR/variance-unused-type-param.rs:9:15 | LL | enum SomeEnum { Nothing } - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `A` to be a const parameter, use `const A: usize` instead + = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/variance-unused-type-param.rs:13:15 | LL | enum ListCell { - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/variance-unused-type-param.rs:19:19 | LL | struct WithBounds {} - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/variance-unused-type-param.rs:22:24 | LL | struct WithWhereBounds where T: Sized {} - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error[E0392]: parameter `T` is never used +error[E0392]: type parameter `T` is never used --> $DIR/variance-unused-type-param.rs:25:27 | LL | struct WithOutlivesBounds {} - | ^ unused parameter + | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 6d40d6377c5de..748fe13c1e47a 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -231,6 +231,31 @@ fn infcx() { let _cx: cx::cx::Cx = cx::cx::cx::cx::cx::Cx; } +fn return_already() -> impl std::fmt::Debug { + loop { + return !!!!!!! + break !!!!!!1111 + } +} + +fn fake_macros() -> impl std::fmt::Debug { + loop { + if! { + match! ( + break! { + return! { + 1337 + } + } + ) + + {} + } + + {} + } +} + pub fn main() { strange(); funny(); @@ -257,4 +282,6 @@ pub fn main() { semisemisemisemisemi(); useful_syntax(); infcx(); + return_already(); + fake_macros(); } diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr index 21122e37da53d..4dca1f65232e2 100644 --- a/tests/ui/wf/hir-wf-canonicalized.stderr +++ b/tests/ui/wf/hir-wf-canonicalized.stderr @@ -29,11 +29,11 @@ LL | callback: Box>>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static)` -note: required by a bound in `Bar` +note: required by an implicit `Sized` bound in `Bar` --> $DIR/hir-wf-canonicalized.rs:9:16 | LL | struct Bar<'a, T> { - | ^ required by this bound in `Bar` + | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` help: consider relaxing the implicit `Sized` restriction | LL | struct Bar<'a, T: ?Sized> { diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.stderr index 4b696dc1d1dfe..93449d60e9d0d 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.stderr +++ b/tests/ui/wf/hir-wf-check-erase-regions.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'a T` is not an iterator LL | type IntoIter = std::iter::Flatten>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator | - = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `Flatten>: Iterator` = help: the trait `Iterator` is implemented for `&mut I` = note: required for `Flatten>` to implement `Iterator` note: required by a bound in `std::iter::IntoIterator::IntoIter` @@ -16,7 +16,7 @@ error[E0277]: `&'a T` is not an iterator LL | type IntoIter = std::iter::Flatten>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator | - = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `&'a T: IntoIterator` = help: the trait `Iterator` is implemented for `&mut I` = note: required for `&'a T` to implement `IntoIterator` note: required by a bound in `Flatten` @@ -28,7 +28,7 @@ error[E0277]: `&'a T` is not an iterator LL | fn into_iter(self) -> Self::IntoIter { | ^^^^^^^^^^^^^^ `&'a T` is not an iterator | - = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `&'a T: IntoIterator` = help: the trait `Iterator` is implemented for `&mut I` = note: required for `&'a T` to implement `IntoIterator` note: required by a bound in `Flatten` diff --git a/tests/ui/wf/wf-const-type.stderr b/tests/ui/wf/wf-const-type.stderr index 039e907705ee6..d5e0f7672a6f3 100644 --- a/tests/ui/wf/wf-const-type.stderr +++ b/tests/ui/wf/wf-const-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:12 | LL | const FOO: IsCopy> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` note: required by a bound in `IsCopy` @@ -20,7 +20,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:50 | LL | const FOO: IsCopy> = IsCopy { t: None }; - | ^^^^ the trait `Copy` is not implemented for `NotCopy` + | ^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` note: required by a bound in `IsCopy` diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr index cd6c051feedf5..40f2f45263930 100644 --- a/tests/ui/wf/wf-fn-where-clause.stderr +++ b/tests/ui/wf/wf-fn-where-clause.stderr @@ -30,11 +30,11 @@ LL | fn bar() where Vec:, {} | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)` -note: required by a bound in `Vec` +note: required by an implicit `Sized` bound in `Vec` --> $DIR/wf-fn-where-clause.rs:16:12 | LL | struct Vec { - | ^ required by this bound in `Vec` + | ^ required by the implicit `Sized` requirement on this type parameter in `Vec` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/wf-fn-where-clause.rs:16:12 | diff --git a/tests/ui/wf/wf-impl-self-type.stderr b/tests/ui/wf/wf-impl-self-type.stderr index 86fe6df32bf21..6c3abd9f2816e 100644 --- a/tests/ui/wf/wf-impl-self-type.stderr +++ b/tests/ui/wf/wf-impl-self-type.stderr @@ -5,7 +5,7 @@ LL | impl Foo for Option<[u8]> {} | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `Option` +note: required by an implicit `Sized` bound in `Option` --> $SRC_DIR/core/src/option.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr index 65dae26014375..481173b8a269c 100644 --- a/tests/ui/wf/wf-static-type.stderr +++ b/tests/ui/wf/wf-static-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:13 | LL | static FOO: IsCopy> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` note: required by a bound in `IsCopy` @@ -20,7 +20,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:51 | LL | static FOO: IsCopy> = IsCopy { t: None }; - | ^^^^ the trait `Copy` is not implemented for `NotCopy` + | ^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option: Copy` | = note: required for `Option` to implement `Copy` note: required by a bound in `IsCopy` diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr index 4c15497d5308e..6de4caa76ee0e 100644 --- a/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr +++ b/tests/ui/where-clauses/higher-ranked-fn-type.quiet.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'b> fn(&'b ()): Foo` is not satisfied --> $DIR/higher-ranked-fn-type.rs:20:5 | LL | called() - | ^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&'b ())` + | ^^^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&'b ())` | help: this trait has no implementations, consider adding one --> $DIR/higher-ranked-fn-type.rs:6:1 diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr index 3318c70f1bb38..4cb3cdd69ad00 100644 --- a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr +++ b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for $DIR/higher-ranked-fn-type.rs:20:5 | LL | called() - | ^^^^^^ the trait `for Foo` is not implemented for `fn(&ReBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b) }) ())` + | ^^^^^^^^ the trait `for Foo` is not implemented for `fn(&ReBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b) }) ())` | help: this trait has no implementations, consider adding one --> $DIR/higher-ranked-fn-type.rs:6:1 diff --git a/tests/ui/where-clauses/issue-50825-1.rs b/tests/ui/where-clauses/issue-50825-1.rs index ee4316029a829..2ee34ad714ede 100644 --- a/tests/ui/where-clauses/issue-50825-1.rs +++ b/tests/ui/where-clauses/issue-50825-1.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // regression test for issue #50825 // Make sure that the `impl` bound (): X is preferred over // the (): X bound in the where clause. diff --git a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs index ea60fa708764f..65fd2f3096c93 100644 --- a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs +++ b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Bound { diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs index 6fc570b9b5b9b..a7ce0590fcd46 100644 --- a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs +++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs @@ -3,7 +3,7 @@ // pretty-expanded FIXME #23616 -trait TheTrait { fn dummy(&self) { } } +trait TheTrait { fn dummy(&self) { } } //~ WARN method `dummy` is never used impl TheTrait for &'static isize { } diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr new file mode 100644 index 0000000000000..a9fe11ea6b316 --- /dev/null +++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/where-clause-early-bound-lifetimes.rs:6:21 + | +LL | trait TheTrait { fn dummy(&self) { } } + | -------- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs b/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs index daa3c8dd8e367..8f9c6fbff3d8f 100644 --- a/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs +++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs @@ -2,7 +2,7 @@ #![allow(unused_variables)] // pretty-expanded FIXME #23616 -trait Foo { fn dummy(&self, arg: T) { } } +trait Foo { fn dummy(&self, arg: T) { } } //~ WARN method `dummy` is never used trait Bar { fn method(&self) where A: Foo; diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr new file mode 100644 index 0000000000000..0d09cb9de3f6b --- /dev/null +++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/where-clause-method-substituion-rpass.rs:5:19 + | +LL | trait Foo { fn dummy(&self, arg: T) { } } + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed index 2f47c0d91fa96..4e1aa59aac0f0 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed @@ -1,6 +1,8 @@ // check-pass // run-rustfix +#![allow(dead_code)] + trait Trait { // Fine. type Assoc where u32: Copy; diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs index b20aa9398b58f..05b2f8c82a456 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs @@ -1,6 +1,8 @@ // check-pass // run-rustfix +#![allow(dead_code)] + trait Trait { // Fine. type Assoc where u32: Copy; diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr index b4de051845fa6..6ff9d2dd73b5b 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:13:16 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:16:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:24:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17 | LL | type Assoc2 where u32: Copy, i32: Copy = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed index d171eba50b788..940e2cc8e9750 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed @@ -1,6 +1,7 @@ // check-pass // run-rustfix +#![allow(dead_code)] #![feature(associated_type_defaults)] trait Trait { diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs index 59afee65794c4..7001a9245a5f3 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs @@ -1,6 +1,7 @@ // check-pass // run-rustfix +#![allow(dead_code)] #![feature(associated_type_defaults)] trait Trait { diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr index a81cb8c8cd62e..9e9967ef7391a 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-trait.rs:8:16 + --> $DIR/where-clause-placement-assoc-type-in-trait.rs:9:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-trait.rs:11:17 + --> $DIR/where-clause-placement-assoc-type-in-trait.rs:12:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ diff --git a/triagebot.toml b/triagebot.toml index b3f3051e177f2..eba8e283815c8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,3 +1,6 @@ +# This file's format is documented at +# https://forge.rust-lang.org/triagebot/pr-assignment.html#configuration + [relabel] allow-unauthenticated = [ "A-*", @@ -364,7 +367,8 @@ new_pr = true [autolabel."needs-triage"] new_issue = true exclude_labels = [ - "C-tracking-issue" + "C-tracking-issue", + "A-diagnostics", ] [autolabel."WG-trait-system-refactor"] @@ -472,7 +476,7 @@ of `ObligationCtxt`. """ cc = ["@lcnr", "@compiler-errors"] -[mentions."compiler/rustc_error_codes/src/error_codes.rs"] +[mentions."compiler/rustc_error_codes/src/lib.rs"] message = "Some changes occurred in diagnostic error codes" cc = ["@GuillaumeGomez"] @@ -484,6 +488,13 @@ cc = ["@Nadrieril"] message = "Some changes might have occurred in exhaustiveness checking" cc = ["@Nadrieril"] +[mentions."library/core/src/intrinsics/simd.rs"] +message = """ +Some changes occurred to the platform-builtins intrinsics. Make sure the +LLVM backend as well as portable-simd gets adapted for the changes. +""" +cc = ["@antoyo", "@GuillaumeGomez", "@bjorn3", "@calebzulawski", "@programmerjake"] + [mentions."library/portable-simd"] message = """ Portable SIMD is developed in its own repository. If possible, consider \ @@ -639,12 +650,16 @@ compiler-team = [ "@compiler-errors", "@petrochenkov", "@davidtwco", + "@estebank", "@oli-obk", + "@pnkfelix", "@wesleywiser", + "@michaelwoerister", ] compiler-team-contributors = [ "@TaKO8Ki", - "@b-naber", + "@nnethercote", + "@fmease", ] compiler = [ "compiler-team", @@ -655,7 +670,6 @@ libs = [ "@joshtriplett", "@Mark-Simulacrum", "@m-ou-se", - "@thomcc", ] bootstrap = [ "@Mark-Simulacrum", @@ -688,22 +702,29 @@ incremental = [ diagnostics = [ "@compiler-errors", "@davidtwco", + "@estebank", "@oli-obk", "@TaKO8Ki", ] parser = [ "@compiler-errors", "@davidtwco", + "@estebank", "@nnethercote", "@petrochenkov", ] lexer = [ "@nnethercote", "@petrochenkov", + "@estebank", +] +arena = [ + "@nnethercote", ] mir = [ "@davidtwco", "@oli-obk", + "@matthewjasper" ] mir-opt = [ "@oli-obk", @@ -720,11 +741,17 @@ types = [ borrowck = [ "@davidtwco", "@pnkfelix", + "@matthewjasper" ] ast_lowering = [ "@compiler-errors", + "@estebank", "@spastorino", ] +debuginfo = [ + "@michaelwoerister", + "@davidtwco" +] fallback = [ "@Mark-Simulacrum" ] @@ -734,7 +761,6 @@ style-team = [ "@joshtriplett", "@yaahc", ] - project-const-traits = [ "@compiler-errors", "@fee1-dead", @@ -749,65 +775,73 @@ project-stable-mir = [ ] [assign.owners] -"/.github/workflows" = ["infra-ci"] -"/Cargo.lock" = ["@Mark-Simulacrum"] -"/Cargo.toml" = ["@Mark-Simulacrum"] -"/compiler" = ["compiler"] -"/compiler/rustc_ast" = ["compiler", "parser"] -"/compiler/rustc_ast_lowering" = ["compiler", "ast_lowering"] -"/compiler/rustc_hir_analysis" = ["compiler", "types"] -"/compiler/rustc_lexer" = ["compiler", "lexer"] -"/compiler/rustc_llvm" = ["@cuviper"] -"/compiler/rustc_middle/src/mir" = ["compiler", "mir"] -"/compiler/rustc_middle/src/traits" = ["compiler", "types"] -"/compiler/rustc_middle/src/ty" = ["compiler", "types"] -"/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"] -"/compiler/rustc_const_eval/src/transform" = ["compiler", "mir-opt"] -"/compiler/rustc_mir_build/src/build" = ["compiler", "mir"] -"/compiler/rustc_smir" = ["project-stable-mir"] -"/compiler/rustc_parse" = ["compiler", "parser"] -"/compiler/rustc_parse/src/lexer" = ["compiler", "lexer"] -"/compiler/rustc_query_impl" = ["compiler", "query-system"] -"/compiler/rustc_query_system" = ["compiler", "query-system"] -"/compiler/rustc_trait_selection" = ["compiler", "types"] -"/compiler/rustc_traits" = ["compiler", "types"] -"/compiler/rustc_type_ir" = ["compiler", "types"] -"/compiler/stable_mir" = ["project-stable-mir"] -"/library/alloc" = ["libs"] -"/library/core" = ["libs"] -"/library/panic_abort" = ["libs"] -"/library/panic_unwind" = ["libs"] -"/library/proc_macro" = ["@petrochenkov"] -"/library/std" = ["libs"] -"/library/std/src/sys/pal/windows" = ["@ChrisDenton", "@thomcc"] -"/library/stdarch" = ["libs"] -"/library/test" = ["libs"] -"/src/bootstrap" = ["bootstrap"] -"/src/ci" = ["infra-ci"] -"/src/doc" = ["docs"] -"/src/doc/book" = ["@ehuss"] -"/src/doc/edition-guide" = ["@ehuss"] -"/src/doc/embedded-book" = ["@ehuss"] -"/src/doc/nomicon" = ["@ehuss"] -"/src/doc/reference" = ["@ehuss"] -"/src/doc/rust-by-example" = ["@ehuss"] -"/src/doc/rustc-dev-guide" = ["@ehuss"] -"/src/doc/rustdoc" = ["rustdoc"] -"/src/doc/style-guide" = ["style-team"] -"/src/etc" = ["@Mark-Simulacrum"] -"/src/librustdoc" = ["rustdoc"] -"/src/llvm-project" = ["@cuviper"] -"/src/rustdoc-json-types" = ["rustdoc"] -"/src/stage0.json" = ["bootstrap"] -"/tests/ui" = ["compiler"] -"/src/tools/cargo" = ["@ehuss", "@joshtriplett"] -"/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors"] -"/src/tools/linkchecker" = ["@ehuss"] -"/src/tools/rust-installer" = ["bootstrap"] -"/src/tools/rustbook" = ["@ehuss"] -"/src/tools/rustdoc" = ["rustdoc"] -"/src/tools/rustdoc-js" = ["rustdoc"] -"/src/tools/rustdoc-themes" = ["rustdoc"] -"/src/tools/tidy" = ["bootstrap"] -"/src/tools/x" = ["bootstrap"] -"/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"] +"/.github/workflows" = ["infra-ci"] +"/Cargo.lock" = ["@Mark-Simulacrum"] +"/Cargo.toml" = ["@Mark-Simulacrum"] +"/compiler" = ["compiler"] +"/compiler/rustc_arena" = ["compiler", "arena"] +"/compiler/rustc_ast" = ["compiler", "parser"] +"/compiler/rustc_ast_lowering" = ["compiler", "ast_lowering"] +"/compiler/rustc_data_structures/src/stable_hasher.rs" = ["compiler", "incremental"] +"/compiler/rustc_hir_analysis" = ["compiler", "types"] +"/compiler/rustc_incremental" = ["compiler", "incremental"] +"/compiler/rustc_borrowck" = ["compiler", "borrowck"] +"/compiler/rustc_lexer" = ["compiler", "lexer"] +"/compiler/rustc_llvm" = ["@cuviper"] +"/compiler/rustc_codegen_llvm/src/debuginfo" = ["compiler", "debuginfo"] +"/compiler/rustc_middle/src/mir" = ["compiler", "mir"] +"/compiler/rustc_middle/src/traits" = ["compiler", "types"] +"/compiler/rustc_middle/src/ty" = ["compiler", "types"] +"/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"] +"/compiler/rustc_const_eval/src/transform" = ["compiler", "mir-opt"] +"/compiler/rustc_mir_build/src/build" = ["compiler", "mir"] +"/compiler/rustc_mir_transform" = ["compiler", "mir", "mir-opt"] +"/compiler/rustc_smir" = ["project-stable-mir"] +"/compiler/rustc_parse" = ["compiler", "parser"] +"/compiler/rustc_parse/src/lexer" = ["compiler", "lexer"] +"/compiler/rustc_query_impl" = ["compiler", "query-system"] +"/compiler/rustc_query_system" = ["compiler", "query-system"] +"/compiler/rustc_query_system/src/dep_graph" = ["compiler", "incremental", "query-system"] +"/compiler/rustc_query_system/src/ich" = ["compiler", "incremental", "query-system"] +"/compiler/rustc_trait_selection" = ["compiler", "types"] +"/compiler/rustc_traits" = ["compiler", "types"] +"/compiler/rustc_type_ir" = ["compiler", "types"] +"/compiler/stable_mir" = ["project-stable-mir"] +"/library/alloc" = ["libs"] +"/library/core" = ["libs"] +"/library/panic_abort" = ["libs"] +"/library/panic_unwind" = ["libs"] +"/library/proc_macro" = ["@petrochenkov"] +"/library/std" = ["libs"] +"/library/std/src/sys/pal/windows" = ["@ChrisDenton"] +"/library/stdarch" = ["libs"] +"/library/test" = ["libs"] +"/src/bootstrap" = ["bootstrap"] +"/src/ci" = ["infra-ci"] +"/src/doc" = ["docs"] +"/src/doc/book" = ["@ehuss"] +"/src/doc/edition-guide" = ["@ehuss"] +"/src/doc/embedded-book" = ["@ehuss"] +"/src/doc/nomicon" = ["@ehuss"] +"/src/doc/reference" = ["@ehuss"] +"/src/doc/rust-by-example" = ["@ehuss"] +"/src/doc/rustc-dev-guide" = ["@ehuss"] +"/src/doc/rustdoc" = ["rustdoc"] +"/src/doc/style-guide" = ["style-team"] +"/src/etc" = ["@Mark-Simulacrum"] +"/src/librustdoc" = ["rustdoc"] +"/src/llvm-project" = ["@cuviper"] +"/src/rustdoc-json-types" = ["rustdoc"] +"/src/stage0.json" = ["bootstrap"] +"/tests/ui" = ["compiler"] +"/src/tools/cargo" = ["@ehuss", "@joshtriplett"] +"/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors"] +"/src/tools/linkchecker" = ["@ehuss"] +"/src/tools/rust-installer" = ["bootstrap"] +"/src/tools/rustbook" = ["@ehuss"] +"/src/tools/rustdoc" = ["rustdoc"] +"/src/tools/rustdoc-js" = ["rustdoc"] +"/src/tools/rustdoc-themes" = ["rustdoc"] +"/src/tools/tidy" = ["bootstrap"] +"/src/tools/x" = ["bootstrap"] +"/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"]

{ - match self { - AssertLint::ArithmeticOverflow(_, p) | AssertLint::UnconditionalPanic(_, p) => p, + AssertLintKind::ArithmeticOverflow => lint::builtin::ARITHMETIC_OVERFLOW, + AssertLintKind::UnconditionalPanic => lint::builtin::UNCONDITIONAL_PANIC, } } } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 26fcfad828777..b0d758bcbfe3b 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -26,7 +26,6 @@ fn abi_can_unwind(abi: Abi) -> bool { PtxKernel | Msp430Interrupt | X86Interrupt - | AmdGpuKernel | EfiApi | AvrInterrupt | AvrNonBlockingInterrupt @@ -58,6 +57,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let body_abi = match body_ty.kind() { ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::Closure(..) => Abi::RustCall, + ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), }; @@ -112,7 +112,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let span = terminator.source_info.span; let foreign = fn_def_id.is_some(); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( FFI_UNWIND_CALLS, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 61d99f1f018b5..f413bd9b31168 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -185,7 +185,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { ret, ); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( FUNCTION_ITEM_REFERENCES, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 390ec3e1a36ac..f9798bc4e70e6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -861,9 +861,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let tcx = self.tcx; if fields.is_empty() { let is_zst = match *kind { - AggregateKind::Array(..) | AggregateKind::Tuple | AggregateKind::Closure(..) => { - true - } + AggregateKind::Array(..) + | AggregateKind::Tuple + | AggregateKind::Closure(..) + | AggregateKind::CoroutineClosure(..) => true, // Only enums can be non-ZST. AggregateKind::Adt(did, ..) => tcx.def_kind(did) != DefKind::Enum, // Coroutines are never ZST, as they at least contain the implicit states. @@ -885,7 +886,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { assert!(!fields.is_empty()); (AggregateTy::Tuple, FIRST_VARIANT) } - AggregateKind::Closure(did, substs) | AggregateKind::Coroutine(did, substs) => { + AggregateKind::Closure(did, substs) + | AggregateKind::CoroutineClosure(did, substs) + | AggregateKind::Coroutine(did, substs) => { (AggregateTy::Def(did, substs), FIRST_VARIANT) } AggregateKind::Adt(did, variant_index, substs, _, None) => { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 67668a216dee3..e77553a03d672 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -317,6 +317,8 @@ impl<'tcx> Inliner<'tcx> { | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index d30e0bad81301..5b03bc361dd3c 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -87,6 +87,8 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::ThreadLocalShim { .. } | InstanceDef::CloneShim(..) => {} diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 14d089fb25876..fc131459c92b1 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -36,16 +36,21 @@ //! cost by `MAX_COST`. use rustc_arena::DroplessArena; +use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, ScalarInt, TyCtxt}; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; +use rustc_span::DUMMY_SP; use rustc_target::abi::{TagEncoding, Variants}; use crate::cost_checker::CostChecker; +use crate::dataflow_const_prop::DummyMachine; pub struct JumpThreading; @@ -71,6 +76,7 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { let mut finder = TOFinder { tcx, param_env, + ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), body, arena: &arena, map: &map, @@ -88,7 +94,7 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { debug!(?discr, ?bb); let discr_ty = discr.ty(body, tcx).ty; - let Ok(discr_layout) = tcx.layout_of(param_env.and(discr_ty)) else { continue }; + let Ok(discr_layout) = finder.ecx.layout_of(discr_ty) else { continue }; let Some(discr) = finder.map.find(discr.as_ref()) else { continue }; debug!(?discr); @@ -142,6 +148,7 @@ struct ThreadingOpportunity { struct TOFinder<'tcx, 'a> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, + ecx: InterpCx<'tcx, 'tcx, DummyMachine>, body: &'a Body<'tcx>, map: &'a Map, loop_headers: &'a BitSet, @@ -330,11 +337,11 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { } #[instrument(level = "trace", skip(self))] - fn process_operand( + fn process_immediate( &mut self, bb: BasicBlock, lhs: PlaceIndex, - rhs: &Operand<'tcx>, + rhs: ImmTy<'tcx>, state: &mut State>, ) -> Option { let register_opportunity = |c: Condition| { @@ -342,13 +349,70 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) }; + let conditions = state.try_get_idx(lhs, self.map)?; + if let Immediate::Scalar(Scalar::Int(int)) = *rhs { + conditions.iter_matches(int).for_each(register_opportunity); + } + + None + } + + /// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. + #[instrument(level = "trace", skip(self))] + fn process_constant( + &mut self, + bb: BasicBlock, + lhs: PlaceIndex, + constant: OpTy<'tcx>, + state: &mut State>, + ) { + self.map.for_each_projection_value( + lhs, + constant, + &mut |elem, op| match elem { + TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(), + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(), + TrackElem::Discriminant => { + let variant = self.ecx.read_discriminant(op).ok()?; + let discr_value = + self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?; + Some(discr_value.into()) + } + TrackElem::DerefLen => { + let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into(); + let len_usize = op.len(&self.ecx).ok()?; + let layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); + Some(ImmTy::from_uint(len_usize, layout).into()) + } + }, + &mut |place, op| { + if let Some(conditions) = state.try_get_idx(place, self.map) + && let Ok(imm) = self.ecx.read_immediate_raw(op) + && let Some(imm) = imm.right() + && let Immediate::Scalar(Scalar::Int(int)) = *imm + { + conditions.iter_matches(int).for_each(|c: Condition| { + self.opportunities + .push(ThreadingOpportunity { chain: vec![bb], target: c.target }) + }) + } + }, + ); + } + + #[instrument(level = "trace", skip(self))] + fn process_operand( + &mut self, + bb: BasicBlock, + lhs: PlaceIndex, + rhs: &Operand<'tcx>, + state: &mut State>, + ) -> Option { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let conditions = state.try_get_idx(lhs, self.map)?; - let constant = - constant.const_.normalize(self.tcx, self.param_env).try_to_scalar_int()?; - conditions.iter_matches(constant).for_each(register_opportunity); + let constant = self.ecx.eval_mir_constant(&constant.const_, None, None).ok()?; + self.process_constant(bb, lhs, constant, state); } // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { @@ -360,6 +424,84 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { None } + #[instrument(level = "trace", skip(self))] + fn process_assign( + &mut self, + bb: BasicBlock, + lhs_place: &Place<'tcx>, + rhs: &Rvalue<'tcx>, + state: &mut State>, + ) -> Option { + let lhs = self.map.find(lhs_place.as_ref())?; + match rhs { + Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state)?, + // Transfer the conditions on the copy rhs. + Rvalue::CopyForDeref(rhs) => { + self.process_operand(bb, lhs, &Operand::Copy(*rhs), state)? + } + Rvalue::Discriminant(rhs) => { + let rhs = self.map.find_discr(rhs.as_ref())?; + 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) => { + let agg_ty = lhs_place.ty(self.body, self.tcx).ty; + let lhs = match kind { + // Do not support unions. + AggregateKind::Adt(.., Some(_)) => return None, + AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { + if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant) + && let Ok(discr_value) = + self.ecx.discriminant_for_variant(agg_ty, *variant_index) + { + self.process_immediate(bb, discr_target, discr_value, state); + } + self.map.apply(lhs, TrackElem::Variant(*variant_index))? + } + _ => lhs, + }; + for (field_index, operand) in operands.iter_enumerated() { + if let Some(field) = self.map.apply(lhs, TrackElem::Field(field_index)) { + self.process_operand(bb, field, operand, state); + } + } + } + // Transfer the conditions on the copy rhs, after inversing polarity. + Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { + let conditions = state.try_get_idx(lhs, self.map)?; + let place = self.map.find(place.as_ref())?; + let conds = conditions.map(self.arena, Condition::inv); + state.insert_value_idx(place, conds, self.map); + } + // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. + // Create a condition on `rhs ?= B`. + Rvalue::BinaryOp( + op, + box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value)) + | box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)), + ) => { + let conditions = state.try_get_idx(lhs, self.map)?; + let place = self.map.find(place.as_ref())?; + let equals = match op { + BinOp::Eq => ScalarInt::TRUE, + BinOp::Ne => ScalarInt::FALSE, + _ => return None, + }; + let value = value.const_.normalize(self.tcx, self.param_env).try_to_scalar_int()?; + let conds = conditions.map(self.arena, |c| Condition { + value, + polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, + ..c + }); + state.insert_value_idx(place, conds, self.map); + } + + _ => {} + } + + None + } + #[instrument(level = "trace", skip(self))] fn process_statement( &mut self, @@ -375,18 +517,6 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // Below, `lhs` is the return value of `mutated_statement`, // the place to which `conditions` apply. - let discriminant_for_variant = |enum_ty: Ty<'tcx>, variant_index| { - let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?; - let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?; - let scalar = ScalarInt::try_from_uint(discr.val, discr_layout.size)?; - Some(Operand::const_from_scalar( - self.tcx, - discr.ty, - scalar.into(), - rustc_span::DUMMY_SP, - )) - }; - match &stmt.kind { // If we expect `discriminant(place) ?= A`, // we have an opportunity if `variant_index ?= A`. @@ -396,7 +526,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant // of a niche encoding. If we cannot ensure that we write to the discriminant, do // nothing. - let enum_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; + let enum_layout = self.ecx.layout_of(enum_ty).ok()?; let writes_discriminant = match enum_layout.variants { Variants::Single { index } => { assert_eq!(index, *variant_index); @@ -409,8 +539,8 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { } => *variant_index != untagged_variant, }; if writes_discriminant { - let discr = discriminant_for_variant(enum_ty, *variant_index)?; - self.process_operand(bb, discr_target, &discr, state)?; + let discr = self.ecx.discriminant_for_variant(enum_ty, *variant_index).ok()?; + self.process_immediate(bb, discr_target, discr, state)?; } } // If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`. @@ -421,89 +551,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity); } StatementKind::Assign(box (lhs_place, rhs)) => { - if let Some(lhs) = self.map.find(lhs_place.as_ref()) { - match rhs { - Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state)?, - // Transfer the conditions on the copy rhs. - Rvalue::CopyForDeref(rhs) => { - self.process_operand(bb, lhs, &Operand::Copy(*rhs), state)? - } - Rvalue::Discriminant(rhs) => { - let rhs = self.map.find_discr(rhs.as_ref())?; - 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) => { - let agg_ty = lhs_place.ty(self.body, self.tcx).ty; - let lhs = match kind { - // Do not support unions. - AggregateKind::Adt(.., Some(_)) => return None, - AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { - if let Some(discr_target) = - self.map.apply(lhs, TrackElem::Discriminant) - && let Some(discr_value) = - discriminant_for_variant(agg_ty, *variant_index) - { - self.process_operand(bb, discr_target, &discr_value, state); - } - self.map.apply(lhs, TrackElem::Variant(*variant_index))? - } - _ => lhs, - }; - for (field_index, operand) in operands.iter_enumerated() { - if let Some(field) = - self.map.apply(lhs, TrackElem::Field(field_index)) - { - self.process_operand(bb, field, operand, state); - } - } - } - // Transfer the conditions on the copy rhs, after inversing polarity. - Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { - let conditions = state.try_get_idx(lhs, self.map)?; - let place = self.map.find(place.as_ref())?; - let conds = conditions.map(self.arena, Condition::inv); - state.insert_value_idx(place, conds, self.map); - } - // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. - // Create a condition on `rhs ?= B`. - Rvalue::BinaryOp( - op, - box ( - Operand::Move(place) | Operand::Copy(place), - Operand::Constant(value), - ) - | box ( - Operand::Constant(value), - Operand::Move(place) | Operand::Copy(place), - ), - ) => { - let conditions = state.try_get_idx(lhs, self.map)?; - let place = self.map.find(place.as_ref())?; - let equals = match op { - BinOp::Eq => ScalarInt::TRUE, - BinOp::Ne => ScalarInt::FALSE, - _ => return None, - }; - let value = value - .const_ - .normalize(self.tcx, self.param_env) - .try_to_scalar_int()?; - let conds = conditions.map(self.arena, |c| Condition { - value, - polarity: if c.matches(equals) { - Polarity::Eq - } else { - Polarity::Ne - }, - ..c - }); - state.insert_value_idx(place, conds, self.map); - } - - _ => {} - } - } + self.process_assign(bb, lhs_place, rhs, state)?; } _ => {} } @@ -519,11 +567,6 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { cost: &CostChecker<'_, 'tcx>, depth: usize, ) { - let register_opportunity = |c: Condition| { - debug!(?bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }; - let term = self.body.basic_blocks[bb].terminator(); let place_to_flood = match term.kind { // We come from a target, so those are not possible. @@ -545,16 +588,8 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // Flood the overwritten place, and progress through. TerminatorKind::Drop { place: destination, .. } | TerminatorKind::Call { destination, .. } => Some(destination), - // Treat as an `assume(cond == expected)`. - TerminatorKind::Assert { ref cond, expected, .. } => { - if let Some(place) = cond.place() - && let Some(conditions) = state.try_get(place.as_ref(), self.map) - { - let expected = if expected { ScalarInt::TRUE } else { ScalarInt::FALSE }; - conditions.iter_matches(expected).for_each(register_opportunity); - } - None - } + // Ignore, as this can be a no-op at codegen time. + TerminatorKind::Assert { .. } => None, }; // We can recurse through this terminator. @@ -578,7 +613,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { let discr = discr.place()?; let discr_ty = discr.ty(self.body, self.tcx).ty; - let discr_layout = self.tcx.layout_of(self.param_env.and(discr_ty)).ok()?; + let discr_layout = self.ecx.layout_of(discr_ty).ok()?; let conditions = state.try_get(discr.as_ref(), self.map)?; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 19bfed4333c03..031515ea95828 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -2,9 +2,11 @@ #![deny(rustc::diagnostic_outside_of_impl)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(const_type_name)] #![feature(cow_is_borrowed)] #![feature(decl_macro)] #![feature(impl_trait_in_assoc_type)] +#![feature(inline_const)] #![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] @@ -12,11 +14,9 @@ #![feature(never_type)] #![feature(option_get_or_insert_default)] #![feature(round_char_boundary)] -#![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] #![feature(if_let_guard)] -#![recursion_limit = "256"] #[macro_use] extern crate tracing; @@ -307,6 +307,10 @@ fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), + // If this is an async closure's output coroutine, generate + // by-move and by-mut bodies if needed. We do this first so + // they can be optimized in lockstep with their parent bodies. + &coroutine::ByMoveBody, // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, &rustc_peek::SanityCheck, // Just a lint diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index ff309bd10ec82..c3a92911bbf0f 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -1,7 +1,7 @@ //! See the docs for [`RenameReturnPlace`]. use rustc_hir::Mutability; -use rustc_index::bit_set::HybridBitSet; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; @@ -123,7 +123,7 @@ fn find_local_assigned_to_return_place( body: &mut mir::Body<'_>, ) -> Option { let mut block = start; - let mut seen = HybridBitSet::new_empty(body.basic_blocks.len()); + let mut seen = BitSet::new_empty(body.basic_blocks.len()); // Iterate as long as `block` has exactly one predecessor that we have not yet visited. while seen.insert(block) { diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index f4c572aec128a..605e1ad46d775 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -7,8 +7,20 @@ use crate::{lint::lint_body, validate, MirPass}; /// Just like `MirPass`, except it cannot mutate `Body`. pub trait MirLint<'tcx> { fn name(&self) -> &'static str { - let name = std::any::type_name::(); - if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } + // FIXME Simplify the implementation once more `str` methods get const-stable. + const { + let name = std::any::type_name::(); + let bytes = name.as_bytes(); + let mut i = bytes.len(); + while i > 0 && bytes[i - 1] != b':' { + i = i - 1; + } + let (_, bytes) = bytes.split_at(i); + match std::str::from_utf8(bytes) { + Ok(name) => name, + Err(_) => name, + } + } } fn is_enabled(&self, _sess: &Session) -> bool { @@ -177,6 +189,15 @@ fn run_passes_inner<'tcx>( body.pass_count = 1; } + + if let Some(coroutine) = body.coroutine.as_mut() { + if let Some(by_move_body) = coroutine.by_move_body.as_mut() { + run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each); + } + if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() { + run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each); + } + } } pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index 795f5232ee302..f68e592db154f 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -7,14 +7,10 @@ pub struct RemoveStorageMarkers; impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() > 0 + sess.mir_opt_level() > 0 && !sess.emit_lifetime_markers() } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.emit_lifetime_markers() { - return; - } - + fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemoveStorageMarkers on {:?}", body.source); for data in body.basic_blocks.as_mut_preserves_cfg() { data.statements.retain(|statement| match statement.kind { diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 34d57a45301d7..9a94cae338288 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -46,6 +46,7 @@ fn maybe_zst(ty: Ty<'_>) -> bool { ty::Adt(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Tuple(..) | ty::Alias(ty::Opaque, ..) => true, // definitely ZST diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 89414ce940e05..7b6de3a543955 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{GenericArgs, CAPTURE_STRUCT_LOCAL}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_index::{Idx, IndexVec}; @@ -66,11 +66,76 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } + ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind, + } => match target_kind { + ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"), + ty::ClosureKind::FnMut => { + // No need to optimize the body, it has already been optimized + // since we steal it from the `AsyncFn::call` body and just fix + // the return type. + return build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id); + } + ty::ClosureKind::FnOnce => { + build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id) + } + }, + + ty::InstanceDef::CoroutineKindShim { coroutine_def_id, target_kind } => match target_kind { + ty::ClosureKind::Fn => unreachable!(), + ty::ClosureKind::FnMut => { + return tcx + .optimized_mir(coroutine_def_id) + .coroutine_by_mut_body() + .unwrap() + .clone(); + } + ty::ClosureKind::FnOnce => { + return tcx + .optimized_mir(coroutine_def_id) + .coroutine_by_move_body() + .unwrap() + .clone(); + } + }, + ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? if let Some(ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) { - let body = tcx.optimized_mir(*coroutine_def_id).coroutine_drop().unwrap(); + let coroutine_body = tcx.optimized_mir(*coroutine_def_id); + + let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind() + else { + bug!() + }; + + // If this is a regular coroutine, grab its drop shim. If this is a coroutine + // that comes from a coroutine-closure, and the kind ty differs from the "maximum" + // kind that it supports, then grab the appropriate drop shim. This ensures that + // the future returned by `<[coroutine-closure] as AsyncFnOnce>::call_once` will + // drop the coroutine-closure's upvars. + let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() { + coroutine_body.coroutine_drop().unwrap() + } else { + match args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() { + ty::ClosureKind::Fn => { + unreachable!() + } + ty::ClosureKind::FnMut => coroutine_body + .coroutine_by_mut_body() + .unwrap() + .coroutine_drop() + .unwrap(), + ty::ClosureKind::FnOnce => coroutine_body + .coroutine_by_move_body() + .unwrap() + .coroutine_drop() + .unwrap(), + } + }; + let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); debug!("make_shim({:?}) = {:?}", instance, body); @@ -981,3 +1046,114 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } + +fn build_construct_coroutine_by_move_shim<'tcx>( + tcx: TyCtxt<'tcx>, + coroutine_closure_def_id: DefId, +) -> Body<'tcx> { + let self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); + let ty::CoroutineClosure(_, args) = *self_ty.kind() else { + bug!(); + }; + + let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { + tcx.mk_fn_sig( + [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()), + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(coroutine_closure_def_id), + ty::ClosureKind::FnOnce, + tcx.lifetimes.re_erased, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }); + let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig); + let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else { + bug!(); + }; + + let span = tcx.def_span(coroutine_closure_def_id); + let locals = local_decls_for_sig(&sig, span); + + let mut fields = vec![]; + for idx in 1..sig.inputs().len() { + fields.push(Operand::Move(Local::from_usize(idx + 1).into())); + } + for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() { + fields.push(Operand::Move(tcx.mk_place_field( + Local::from_usize(1).into(), + FieldIdx::from_usize(idx), + ty, + ))); + } + + let source_info = SourceInfo::outermost(span); + let rvalue = Rvalue::Aggregate( + Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)), + IndexVec::from_raw(fields), + ); + let stmt = Statement { + source_info, + kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + }; + let statements = vec![stmt]; + let start_block = BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), + is_cleanup: false, + }; + + let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind: ty::ClosureKind::FnOnce, + }); + + let body = + new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span); + dump_mir(tcx, false, "coroutine_closure_by_move", &0, &body, |_, _| Ok(())); + + body +} + +fn build_construct_coroutine_by_mut_shim<'tcx>( + tcx: TyCtxt<'tcx>, + coroutine_closure_def_id: DefId, +) -> Body<'tcx> { + let mut body = tcx.optimized_mir(coroutine_closure_def_id).clone(); + let coroutine_closure_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); + let ty::CoroutineClosure(_, args) = *coroutine_closure_ty.kind() else { + bug!(); + }; + let args = args.as_coroutine_closure(); + + body.local_decls[RETURN_PLACE].ty = + tcx.instantiate_bound_regions_with_erased(args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(coroutine_closure_def_id), + ty::ClosureKind::FnMut, + tcx.lifetimes.re_erased, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ) + })); + body.local_decls[CAPTURE_STRUCT_LOCAL].ty = + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_closure_ty); + + body.source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind: ty::ClosureKind::FnMut, + }); + + body.pass_count = 0; + dump_mir(tcx, false, "coroutine_closure_by_mut", &0, &body, |_, _| Ok(())); + + body +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 20e70f87b75e8..3376af986531e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -714,7 +714,7 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { // but correct span? This would make the lint at least accept crate-level lint attributes. return; }; - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( LARGE_ASSIGNMENTS, lint_root, span, @@ -783,8 +783,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { def_id, args, ty::ClosureKind::FnOnce, - ) - .expect("failed to normalize and resolve closure during codegen"); + ); if should_codegen_locally(self.tcx, &instance) { self.output.push(create_fn_mono_item(self.tcx, instance, span)); } @@ -984,6 +983,8 @@ fn visit_instance_use<'tcx>( | ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::CloneShim(..) @@ -1114,7 +1115,13 @@ fn find_vtable_types_for_unsizing<'tcx>( assert_eq!(source_adt_def, target_adt_def); let CustomCoerceUnsized::Struct(coerce_index) = - crate::custom_coerce_unsize_info(tcx, source_ty, target_ty); + match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) { + Ok(ccu) => ccu, + Err(e) => { + let e = Ty::new_error(tcx.tcx, e); + return (e, e); + } + }; let source_fields = &source_adt_def.non_enum_variant().fields; let target_fields = &target_adt_def.non_enum_variant().fields; diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 2f5f2d15cd456..b0cfa3568cad7 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_windows)] #![feature(is_sorted)] -#![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -15,6 +14,7 @@ use rustc_middle::query::{Providers, TyCtxtAt}; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; use rustc_middle::ty::{self, Ty}; +use rustc_span::ErrorGuaranteed; mod collector; mod errors; @@ -28,7 +28,7 @@ fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxtAt<'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, -) -> CustomCoerceUnsized { +) -> Result { let trait_ref = ty::TraitRef::from_lang_item( tcx.tcx, LangItem::CoerceUnsized, @@ -40,7 +40,7 @@ fn custom_coerce_unsize_info<'tcx>( Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { impl_def_id, .. - })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), + })) => Ok(tcx.coerce_unsized_info(impl_def_id)?.custom_kind.unwrap()), impl_source => { bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source); } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 2c40cd4d8f26e..5cfebcaa5a5f9 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -156,7 +156,7 @@ where placed }; - // Merge until we have at most `max_cgu_count` codegen units. + // Merge until we don't exceed the max CGU count. // `merge_codegen_units` is responsible for updating the CGU size // estimates. { @@ -182,7 +182,7 @@ where } // Ensure CGUs are sorted by name, so that we get deterministic results. - if !codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str()))) { + if !codegen_units.is_sorted_by(|a, b| a.name().as_str() <= b.name().as_str()) { let mut names = String::new(); for cgu in codegen_units.iter() { names += &format!("- {}\n", cgu.name()); @@ -317,7 +317,7 @@ fn merge_codegen_units<'tcx>( assert!(cx.tcx.sess.codegen_units().as_usize() >= 1); // A sorted order here ensures merging is deterministic. - assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str())))); + assert!(codegen_units.is_sorted_by(|a, b| a.name().as_str() <= b.name().as_str())); // This map keeps track of what got merged into what. let mut cgu_contents: FxHashMap> = @@ -620,6 +620,8 @@ fn characteristic_def_id_of_mono_item<'tcx>( | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Virtual(..) @@ -783,6 +785,8 @@ fn mono_item_visibility<'tcx>( | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index db1aee1190359..42edbeaa622c2 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -332,7 +332,8 @@ impl, I: Interner> TypeFolder | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f904e0c44ea92..7c2ecf34c1754 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -22,6 +22,8 @@ parse_associated_static_item_not_allowed = associated `static` items are not all parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later +parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Rust 2018 or later + parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 .label = to use `async fn`, switch to Rust 2018 or later @@ -772,6 +774,20 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter .label = lifetime parameters cannot have default values +parse_unexpected_expr_in_pat = + expected {$is_bound -> + [true] a pattern range bound + *[false] a pattern + }, found {$is_method_call -> + [true] a method call + *[false] an expression + } + + .label = {$is_method_call -> + [true] method calls + *[false] arbitrary expressions + } are not allowed in patterns + parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40852048293a9..86a64d90deb20 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -25,7 +25,7 @@ pub(crate) struct AmbiguousPlus { } #[derive(Diagnostic)] -#[diag(parse_maybe_recover_from_bad_type_plus, code = "E0178")] +#[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)] pub(crate) struct BadTypePlus { pub ty: String, #[primary_span] @@ -807,7 +807,7 @@ pub(crate) struct InclusiveRangeMatchArrow { } #[derive(Diagnostic)] -#[diag(parse_inclusive_range_no_end, code = "E0586")] +#[diag(parse_inclusive_range_no_end, code = E0586)] #[note] pub(crate) struct InclusiveRangeNoEnd { #[primary_span] @@ -901,7 +901,7 @@ pub(crate) struct MismatchedClosingDelimiter { } #[derive(Diagnostic)] -#[diag(parse_incorrect_visibility_restriction, code = "E0704")] +#[diag(parse_incorrect_visibility_restriction, code = E0704)] #[help] pub(crate) struct IncorrectVisibilityRestriction { #[primary_span] @@ -925,7 +925,7 @@ pub(crate) struct ExpectedStatementAfterOuterAttr { } #[derive(Diagnostic)] -#[diag(parse_doc_comment_does_not_document_anything, code = "E0585")] +#[diag(parse_doc_comment_does_not_document_anything, code = E0585)] #[help] pub(crate) struct DocCommentDoesNotDocumentAnything { #[primary_span] @@ -1357,7 +1357,7 @@ pub(crate) struct AttributeOnParamType { } #[derive(Diagnostic)] -#[diag(parse_pattern_method_param_without_body, code = "E0642")] +#[diag(parse_pattern_method_param_without_body, code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] #[suggestion(code = "_", applicability = "machine-applicable")] @@ -1565,7 +1565,7 @@ pub(crate) struct WhereClauseBeforeTupleStructBodySugg { } #[derive(Diagnostic)] -#[diag(parse_async_fn_in_2015, code = "E0670")] +#[diag(parse_async_fn_in_2015, code = E0670)] pub(crate) struct AsyncFnIn2015 { #[primary_span] #[label] @@ -1588,6 +1588,15 @@ pub(crate) struct AsyncMoveBlockIn2015 { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_bound_modifier_in_2015)] +pub(crate) struct AsyncBoundModifierIn2015 { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub help: HelpUseLatestEdition, +} + #[derive(Diagnostic)] #[diag(parse_self_argument_pointer)] pub(crate) struct SelfArgumentPointer { @@ -1929,7 +1938,7 @@ pub struct CrDocComment { } #[derive(Diagnostic)] -#[diag(parse_no_digits_literal, code = "E0768")] +#[diag(parse_no_digits_literal, code = E0768)] pub struct NoDigitsLiteral { #[primary_span] pub span: Span, @@ -2415,6 +2424,18 @@ pub(crate) struct ExpectedCommaAfterPatternField { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_unexpected_expr_in_pat)] +pub(crate) struct UnexpectedExpressionInPattern { + #[primary_span] + #[label] + pub span: Span, + /// Was a `RangePatternBound` expected? + pub is_bound: bool, + /// Was the unexpected expression a `MethodCallExpression`? + pub is_method_call: bool, +} + #[derive(Diagnostic)] #[diag(parse_unexpected_paren_in_range_pat)] pub(crate) struct UnexpectedParenInRangePat { @@ -2499,7 +2520,7 @@ pub(crate) struct FnPointerCannotBeAsync { } #[derive(Diagnostic)] -#[diag(parse_nested_c_variadic_type, code = "E0743")] +#[diag(parse_nested_c_variadic_type, code = E0743)] pub(crate) struct NestedCVariadicType { #[primary_span] pub span: Span, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d7ecf577ed676..3155245267600 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, DiagCtxt, DiagnosticBuilder, StashKey}; +use rustc_errors::{codes::*, Applicability, DiagCtxt, DiagnosticBuilder, StashKey}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Cursor, LiteralKind}; @@ -397,10 +397,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { if !terminated { self.dcx() .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") - .with_code(error_code!(E0762)) + .with_code(E0762) .emit() } - self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' + self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { @@ -409,10 +409,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start + BytePos(1), end), "unterminated byte constant", ) - .with_code(error_code!(E0763)) + .with_code(E0763) .emit() } - self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' + self.cook_unicode(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { @@ -421,10 +421,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start, end), "unterminated double quote string", ) - .with_code(error_code!(E0765)) + .with_code(E0765) .emit() } - self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " + self.cook_unicode(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { @@ -433,10 +433,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start + BytePos(1), end), "unterminated double quote byte string", ) - .with_code(error_code!(E0766)) + .with_code(E0766) .emit() } - self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " + self.cook_unicode(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { @@ -445,16 +445,16 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start + BytePos(1), end), "unterminated C string", ) - .with_code(error_code!(E0767)) + .with_code(E0767) .emit() } - self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" " + self.cook_mixed(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::StrRaw(n_hashes); - self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## + self.cook_unicode(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## } else { self.report_raw_str_error(start, 1); } @@ -463,7 +463,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::ByteStrRaw(n_hashes); - self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## + self.cook_unicode(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## } else { self.report_raw_str_error(start, 2); } @@ -472,7 +472,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::CStrRaw(n_hashes); - self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## + self.cook_unicode(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## } else { self.report_raw_str_error(start, 2); } @@ -582,7 +582,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { ) -> ! { let mut err = self.dcx().struct_span_fatal(self.mk_sp(start, start), "unterminated raw string"); - err.code(error_code!(E0748)); + err.code(E0748); err.span_label(self.mk_sp(start, start), "unterminated raw string"); if n_hashes > 0 { @@ -614,7 +614,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { }; let last_bpos = self.pos; let mut err = self.dcx().struct_span_fatal(self.mk_sp(start, last_bpos), msg); - err.code(error_code!(E0758)); + err.code(E0758); let mut nested_block_comment_open_idxs = vec![]; let mut last_nested_block_comment_idxs = None; let mut content_chars = self.str_from(start).char_indices().peekable(); @@ -735,7 +735,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { } } - fn cook_quoted( + fn cook_unicode( &self, kind: token::LitKind, mode: Mode, @@ -745,13 +745,13 @@ impl<'sess, 'src> StringReader<'sess, 'src> { postfix_len: u32, ) -> (token::LitKind, Symbol) { self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape::unescape_literal(src, mode, &mut |span, result| { + unescape::unescape_unicode(src, mode, &mut |span, result| { callback(span, result.map(drop)) }) }) } - fn cook_c_string( + fn cook_mixed( &self, kind: token::LitKind, mode: Mode, @@ -761,7 +761,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { postfix_len: u32, ) -> (token::LitKind, Symbol) { self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape::unescape_c_string(src, mode, &mut |span, result| { + unescape::unescape_mixed(src, mode, &mut |span, result| { callback(span, result.map(drop)) }) }) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index c00e318f22709..d5fa11086872f 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -5,9 +5,6 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![feature(never_type)] -#![feature(rustc_attrs)] -#![recursion_limit = "256"] #![allow(internal_features)] #[macro_use] @@ -42,7 +39,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // uses a HOF to parse anything, and includes file and // `source_str`. -/// A variant of 'panictry!' that works on a `Vec` instead of a single +/// A variant of 'panictry!' that works on a `Vec` instead of a single /// `DiagnosticBuilder`. macro_rules! panictry_buffer { ($e:expr) => {{ diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a92609c2c2f87..98e062dd784d4 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -8,7 +8,7 @@ use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter, Nonterminal}; -use rustc_errors::{error_code, Diagnostic, PResult}; +use rustc_errors::{codes::*, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -61,7 +61,7 @@ impl<'a> Parser<'a> { let mut err = self .dcx() .struct_span_err(span, fluent::parse_inner_doc_comment_not_permitted); - err.code(error_code!(E0753)); + err.code(E0753); if let Some(replacement_span) = self.annotate_following_item_if_applicable( &mut err, span, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 720a610fdf518..7a24b819b5f56 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -23,7 +23,7 @@ use crate::parser; use crate::parser::attr::InnerAttrPolicy; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; +use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ @@ -448,12 +448,11 @@ impl<'a> Parser<'a> { }) } - let mut expected = edible + self.expected_tokens.extend(edible.iter().chain(inedible).cloned().map(TokenType::Token)); + let mut expected = self + .expected_tokens .iter() - .chain(inedible) .cloned() - .map(TokenType::Token) - .chain(self.expected_tokens.iter().cloned()) .filter(|token| { // Filter out suggestions that suggest the same token which was found and deemed incorrect. fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool { @@ -792,13 +791,28 @@ impl<'a> Parser<'a> { && let [segment] = &attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg && let Some(args_span) = attr_kind.item.args.span() - && let Ok(next_attr) = snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) + && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) + { + Ok(next_attr) => next_attr, + Err(inner_err) => { + err.cancel(); + inner_err.cancel(); + return; + } + } && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind && let Some(next_attr_args_span) = next_attr_kind.item.args.span() && let [next_segment] = &next_attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg - && let Ok(next_expr) = snapshot.parse_expr() { + let next_expr = match snapshot.parse_expr() { + Ok(next_expr) => next_expr, + Err(inner_err) => { + err.cancel(); + inner_err.cancel(); + return; + } + }; // We have for sure // #[cfg(..)] // expr @@ -2927,6 +2941,22 @@ impl<'a> Parser<'a> { Ok(()) } + /// Check for exclusive ranges written as `..<` + pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'a>) -> PErr<'a> { + if maybe_lt == token::Lt + && (self.expected_tokens.contains(&TokenType::Token(token::Gt)) + || matches!(self.token.kind, token::Literal(..))) + { + err.span_suggestion( + maybe_lt.span, + "remove the `<` to write an exclusive range", + "", + Applicability::MachineApplicable, + ); + } + err + } + pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool { (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind)) && self.look_ahead(3, |tok| tok == short_kind) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f858706805dbc..e36a648e2032e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -28,12 +28,12 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, PResult, StashKey, }; +use rustc_lexer::unescape::unescape_char; use rustc_macros::Subdiagnostic; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Spanned}; -use rustc_span::symbol::kw::PathRoot; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos, Span}; use thin_vec::{thin_vec, ThinVec}; @@ -445,6 +445,19 @@ impl<'a> Parser<'a> { ) 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 `..`. + ( + Some( + AssocOp::Assign + | AssocOp::AssignOp(_) + | AssocOp::BitOr + | AssocOp::DotDot + | AssocOp::DotDotEq, + ), + _, + ) if self.restrictions.contains(Restrictions::IS_PAT) => { + return None; + } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { self.dcx().emit_err(errors::InvalidLogicalOperator { @@ -483,7 +496,11 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?) + let maybe_lt = self.token.clone(); + Some( + self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed) + .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?, + ) } else { None }; @@ -532,11 +549,13 @@ impl<'a> Parser<'a> { let attrs = self.parse_or_use_outer_attributes(attrs)?; self.collect_tokens_for_expr(attrs, |this, attrs| { let lo = this.token.span; + let maybe_lt = this.look_ahead(1, |t| t.clone()); this.bump(); let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) - .map(|x| (lo.to(x.span), Some(x)))? + .map(|x| (lo.to(x.span), Some(x))) + .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? } else { (lo, None) }; @@ -642,26 +661,13 @@ impl<'a> Parser<'a> { } /// Parse `box expr` - this syntax has been removed, but we still parse this - /// for now to provide an automated way to fix usages of it - fn parse_expr_box(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - let (span, expr) = self.parse_expr_prefix_common(lo)?; - let code = self.sess.source_map().span_to_snippet(span.with_lo(lo.hi())).unwrap(); - self.dcx().emit_err(errors::BoxSyntaxRemoved { span, code: code.trim() }); - // So typechecking works, parse `box ` as `::std::boxed::Box::new(expr)` - let path = Path { - span, - segments: [ - PathSegment::from_ident(Ident::with_dummy_span(PathRoot)), - PathSegment::from_ident(Ident::with_dummy_span(sym::std)), - PathSegment::from_ident(Ident::from_str("boxed")), - PathSegment::from_ident(Ident::from_str("Box")), - PathSegment::from_ident(Ident::with_dummy_span(sym::new)), - ] - .into(), - tokens: None, - }; - let path = self.mk_expr(span, ExprKind::Path(None, path)); - Ok((span, self.mk_call(path, ThinVec::from([expr])))) + /// for now to provide a more useful error + fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> { + let (span, _) = self.parse_expr_prefix_common(box_kw)?; + let inner_span = span.with_lo(box_kw.hi()); + let code = self.sess.source_map().span_to_snippet(inner_span).unwrap(); + self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() }); + Ok((span, ExprKind::Err)) } fn is_mistaken_not_ident_negation(&self) -> bool { @@ -1660,6 +1666,7 @@ impl<'a> Parser<'a> { && self.may_recover() && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) || self.token.is_punct()) + && could_be_unclosed_char_literal(label_.ident) { let (lit, _) = self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| { @@ -1745,16 +1752,17 @@ impl<'a> Parser<'a> { Ok(expr) } - /// Emit an error when a char is parsed as a lifetime because of a missing quote. + /// Emit an error when a char is parsed as a lifetime or label because of a missing quote. pub(super) fn recover_unclosed_char( &self, - lifetime: Ident, + ident: Ident, mk_lit_char: impl FnOnce(Symbol, Span) -> L, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a>, ) -> L { - if let Some(diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { + assert!(could_be_unclosed_char_literal(ident)); + if let Some(diag) = self.dcx().steal_diagnostic(ident.span, StashKey::LifetimeIsChar) { diag.with_span_suggestion_verbose( - lifetime.span.shrink_to_hi(), + ident.span.shrink_to_hi(), "add `'` to close the char literal", "'", Applicability::MaybeIncorrect, @@ -1763,15 +1771,15 @@ impl<'a> Parser<'a> { } else { err(self) .with_span_suggestion_verbose( - lifetime.span.shrink_to_hi(), + ident.span.shrink_to_hi(), "add `'` to close the char literal", "'", Applicability::MaybeIncorrect, ) .emit(); } - let name = lifetime.without_first_quote().name; - mk_lit_char(name, lifetime.span) + let name = ident.without_first_quote().name; + mk_lit_char(name, ident.span) } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. @@ -2042,8 +2050,11 @@ impl<'a> Parser<'a> { let msg = format!("unexpected token: {}", super::token_descr(&token)); self_.dcx().struct_span_err(token.span, msg) }; - // On an error path, eagerly consider a lifetime to be an unclosed character lit - if self.token.is_lifetime() { + // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that + // makes sense. + if let Some(ident) = self.token.lifetime() + && could_be_unclosed_char_literal(ident) + { let lt = self.expect_lifetime(); Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err)) } else { @@ -3277,7 +3288,7 @@ impl<'a> Parser<'a> { } else { Applicability::MaybeIncorrect }; - err.span_suggestion_verbose(sugg_sp, msg, "=> ".to_string(), applicability); + err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability); } } err @@ -3771,6 +3782,13 @@ impl<'a> Parser<'a> { } } +/// Could this lifetime/label be an unclosed char literal? For example, `'a` +/// could be, but `'abc` could not. +pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool { + ident.name.as_str().starts_with('\'') + && unescape_char(ident.without_first_quote().name.as_str()).is_ok() +} + /// Used to forbid `let` expressions in certain syntactic locations. #[derive(Clone, Copy, Subdiagnostic)] pub(crate) enum ForbiddenLetReason { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 48cf04f7790d0..e059e7074910a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -148,7 +148,7 @@ impl<'a> Parser<'a> { .with_span_suggestion_verbose( mistyped_const_ident.span, "use the `const` keyword", - kw::Const.as_str(), + kw::Const, Applicability::MachineApplicable, ) .emit(); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3bd8ae0258628..8050b34956ce9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -10,7 +10,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_code_err, Applicability, PResult, StashKey}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, PResult, StashKey}; use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; use rustc_span::source_map; @@ -1453,7 +1453,7 @@ impl<'a> Parser<'a> { err.span_suggestion_verbose( prev_span, "perhaps you meant to use `struct` here", - "struct".to_string(), + "struct", Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ff2fb6271a8df..623407eb38003 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -53,6 +53,7 @@ bitflags::bitflags! { const CONST_EXPR = 1 << 2; const ALLOW_LET = 1 << 3; const IN_IF_GUARD = 1 << 4; + const IS_PAT = 1 << 5; } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7918e03750ce3..12260ec95a5b9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,4 +1,4 @@ -use super::{ForceCollect, Parser, PathStyle, TrailingToken}; +use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, @@ -6,14 +6,15 @@ use crate::errors::{ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, + TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; +use crate::parser::expr::could_be_unclosed_char_literal; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, BinOpToken, Delimiter, Token}; use rustc_ast::{ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -23,7 +24,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -336,6 +337,95 @@ impl<'a> Parser<'a> { } } + /// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator. + /// + /// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end)) + /// in order to say "expected a pattern range bound" instead of "expected a pattern"; + /// ```text + /// 0..=1 + 2 + /// ^^^^^ + /// ``` + /// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter. + #[must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some"] + fn maybe_recover_trailing_expr( + &mut self, + pat_span: Span, + is_end_bound: bool, + ) -> Option { + if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() { + // Don't recover anything after an `_` or if recovery is disabled. + return None; + } + + // Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`. + let has_trailing_method = self.check_noexpect(&token::Dot) + && self.look_ahead(1, |tok| { + tok.ident() + .and_then(|(ident, _)| ident.name.as_str().chars().next()) + .is_some_and(char::is_lowercase) + }) + && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis)); + + // Check for operators. + // `|` is excluded as it is used in pattern alternatives and lambdas, + // `?` is included for error propagation, + // `[` 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`) + let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or) + || self.token.kind == token::Question + || (self.token.kind == token::OpenDelim(Delimiter::Bracket) + && self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket))); + + if !has_trailing_method && !has_trailing_operator { + // Nothing to recover here. + return None; + } + + // Let's try to parse an expression to emit a better diagnostic. + let mut snapshot = self.create_snapshot_for_diagnostic(); + snapshot.restrictions.insert(Restrictions::IS_PAT); + + // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. + if let Ok(expr) = snapshot + .parse_expr_dot_or_call_with( + self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr` + pat_span, + AttrVec::new(), + ) + .map_err(|err| err.cancel()) + { + let non_assoc_span = expr.span; + + // Parse an associative expression such as `+ expr`, `% expr`, ... + // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. + if let Ok(expr) = + snapshot.parse_expr_assoc_with(0, expr.into()).map_err(|err| err.cancel()) + { + // We got a valid expression. + self.restore_snapshot(snapshot); + self.restrictions.remove(Restrictions::IS_PAT); + + let is_bound = is_end_bound + // is_start_bound: either `..` or `)..` + || self.token.is_range_separator() + || self.token.kind == token::CloseDelim(Delimiter::Parenthesis) + && self.look_ahead(1, Token::is_range_separator); + + // Check that `parse_expr_assoc_with` didn't eat a rhs. + let is_method_call = has_trailing_method && non_assoc_span == expr.span; + + return Some(self.dcx().emit_err(UnexpectedExpressionInPattern { + span: expr.span, + is_bound, + is_method_call, + })); + } + } + + // We got a trailing method/operator, but we couldn't parse an expression. + 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( @@ -441,13 +531,17 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { self.parse_pat_tuple_struct(qself, path)? } else { - PatKind::Path(qself, path) + match self.maybe_recover_trailing_expr(span, false) { + Some(guar) => PatKind::Err(guar), + None => PatKind::Path(qself, path), + } } - } else if matches!(self.token.kind, token::Lifetime(_)) + } else if let token::Lifetime(lt) = self.token.kind // In pattern position, we're totally fine with using "next token isn't colon" // as a heuristic. We could probably just always try to recover if it's a lifetime, // because we never have `'a: label {}` in a pattern position anyways, but it does // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..` + && could_be_unclosed_char_literal(Ident::with_dummy_span(lt)) && !self.look_ahead(1, |token| matches!(token.kind, token::Colon)) { // Recover a `'a` as a `'a'` literal @@ -470,10 +564,17 @@ impl<'a> Parser<'a> { } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { - Ok(begin) => match self.parse_range_end() { - Some(form) => self.parse_pat_range_begin_with(begin, form)?, - None => PatKind::Lit(begin), - }, + Ok(begin) => { + let begin = match self.maybe_recover_trailing_expr(begin.span, false) { + Some(_) => self.mk_expr_err(begin.span), + None => begin, + }; + + match self.parse_range_end() { + Some(form) => self.parse_pat_range_begin_with(begin, form)?, + None => PatKind::Lit(begin), + } + } Err(err) => return self.fatal_unexpected_non_pat(err, expected), } }; @@ -615,6 +716,21 @@ impl<'a> Parser<'a> { self.parse_pat_range_begin_with(begin.clone(), form)? } + // recover ranges with parentheses around the `(start)..` + PatKind::Err(_) + if self.may_recover() + && let Some(form) = self.parse_range_end() => + { + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, close_paren], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: close_paren, + }, + }); + + self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)? + } // (pat) with optional parentheses _ => PatKind::Paren(pat), @@ -853,6 +969,8 @@ impl<'a> Parser<'a> { self.parse_literal_maybe_minus() }?; + let recovered = self.maybe_recover_trailing_expr(bound.span, true); + // recover trailing `)` if let Some(open_paren) = open_paren { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; @@ -866,7 +984,10 @@ impl<'a> Parser<'a> { }); } - Ok(bound) + Ok(match recovered { + Some(_) => self.mk_expr_err(bound.span), + None => bound, + }) } /// Is this the start of a pattern beginning with a path? @@ -929,7 +1050,17 @@ impl<'a> Parser<'a> { .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span })); } - Ok(PatKind::Ident(binding_annotation, ident, sub)) + // Check for method calls after the `ident`, + // but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`. + + let pat = if sub.is_none() + && let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false) + { + PatKind::Err(guar) + } else { + PatKind::Ident(binding_annotation, ident, sub) + }; + Ok(pat) } /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a4fb92c67ac68..5fe54a536a7f1 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -3,19 +3,18 @@ use super::{Parser, PathStyle, TokenType}; use crate::errors::{ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg, - InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, - ReturnTypesUseThinArrow, + HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, + NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; -use ast::DUMMY_NODE_ID; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, BareFnTy, BoundConstness, BoundPolarity, FnRetTy, GenericBound, GenericBounds, - GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, - TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, + self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, + GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, + TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID, }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{kw, sym, Ident}; @@ -880,6 +879,24 @@ impl<'a> Parser<'a> { BoundConstness::Never }; + let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) { + self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span); + BoundAsyncness::Async(self.prev_token.span) + } else if self.may_recover() + && self.token.span.is_rust_2015() + && self.is_kw_followed_by_ident(kw::Async) + { + self.bump(); // eat `async` + self.dcx().emit_err(errors::AsyncBoundModifierIn2015 { + span: self.prev_token.span, + help: HelpUseLatestEdition::new(), + }); + self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span); + BoundAsyncness::Async(self.prev_token.span) + } else { + BoundAsyncness::Normal + }; + let polarity = if self.eat(&token::Question) { BoundPolarity::Maybe(self.prev_token.span) } else if self.eat(&token::Not) { @@ -889,7 +906,7 @@ impl<'a> Parser<'a> { BoundPolarity::Positive }; - Ok(TraitBoundModifiers { constness, polarity }) + Ok(TraitBoundModifiers { constness, asyncness, polarity }) } /// Parses a type bound according to: diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 1e1d45d6f702c..d76ee161da6fd 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -11,8 +11,9 @@ )] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -// WARNING: We want to be able to build this crate with a stable compiler, -// so no `#![feature]` attributes should be added! +// We want to be able to build this crate with a stable compiler, +// so no `#![feature]` attributes should be added. +#![deny(unstable_features)] use rustc_lexer::unescape; pub use Alignment::*; @@ -1055,7 +1056,7 @@ fn find_width_map_from_snippet( fn unescape_string(string: &str) -> Option { let mut buf = string::String::new(); let mut ok = true; - unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| { + unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| { match unescaped_char { Ok(c) => buf.push(c), Err(_) => ok = false, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d41cc724408a4..648ef9d51deaa 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -323,9 +323,6 @@ passes_ffi_const_invalid_target = passes_ffi_pure_invalid_target = `#[ffi_pure]` may only be used on foreign functions -passes_ffi_returns_twice_invalid_target = - `#[ffi_returns_twice]` may only be used on foreign functions - passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. .label = only adts, extern types and traits are supported diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 20ed2573e3a71..e652c79d85157 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -5,8 +5,10 @@ //! item. use crate::{errors, fluent_generated as fluent}; -use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; +use rustc_ast::{ast, AttrKind, AttrStyle, Attribute, LitKind}; +use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::StashKey; use rustc_errors::{Applicability, DiagCtxt, IntoDiagnosticArg, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -78,7 +80,7 @@ pub(crate) enum ProcMacroKind { } impl IntoDiagnosticArg for ProcMacroKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { match self { ProcMacroKind::Attribute => "attribute proc macro", ProcMacroKind::Derive => "derive proc macro", @@ -190,7 +192,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target), sym::ffi_const => self.check_ffi_const(attr.span, target), - sym::ffi_returns_twice => self.check_ffi_returns_twice(attr.span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -246,13 +247,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { match attr.style { - ast::AttrStyle::Outer => self.tcx.emit_spanned_lint( + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, errors::OuterCrateLevelAttr, ), - ast::AttrStyle::Inner => self.tcx.emit_spanned_lint( + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -274,7 +275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -283,7 +284,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -304,7 +305,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) { if !matches!(target, Target::Trait) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -320,7 +321,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Closure | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -333,7 +334,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // accidentally, to be compatible with crates depending on them, we can't throw an // error here. Target::AssocConst => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -366,7 +367,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // function prototypes can't be covered Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -376,7 +377,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -386,7 +387,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Target::Expression | Target::Statement | Target::Arm => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -413,7 +414,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { allowed_target: Target, ) { if target != allowed_target { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -630,7 +631,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // FIXME: #[target_feature] was previously erroneously allowed on statements and some // crates used this, so only emit a warning. Target::Statement => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -769,7 +770,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return false; } if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, span, @@ -914,7 +915,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } _ => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -937,7 +938,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, ) -> bool { if target != Target::ExternCrate { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -951,7 +952,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } if self.tcx.extern_mod_stmt_cnum(hir_id.owner).is_none() { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -996,7 +997,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .then_some(errors::AttrCrateLevelOnlySugg { attr: attr.span.with_lo(bang_span).with_hi(bang_span), }); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -1016,7 +1017,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match (i_meta.name_or_empty(), i_meta.meta_item()) { (sym::attr | sym::no_crate_inject, _) => {} (_, Some(m)) => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span(), @@ -1027,7 +1028,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { is_valid = false; } (_, None) => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span(), @@ -1038,7 +1039,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } else { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -1055,7 +1056,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if meta.meta_item_list().is_some() { true } else { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -1188,7 +1189,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); if i_meta.has_name(sym::spotlight) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, @@ -1204,7 +1205,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }; // If there are multiple attributes, the suggestion would suggest // deleting all of them, which is incorrect. - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, @@ -1219,7 +1220,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, ); } else { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, @@ -1230,7 +1231,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } else { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), @@ -1307,15 +1308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_ffi_returns_twice(&self, attr_span: Span, target: Target) -> bool { - if target == Target::ForeignFn { - true - } else { - self.dcx().emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span }); - false - } - } - /// Warns against some misuses of `#[must_use]` fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool { if !matches!( @@ -1343,7 +1335,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => "a", }; - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1380,7 +1372,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used // this, so only emit a warning. - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1400,7 +1392,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1424,14 +1416,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // used this, so only emit a warning. let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span); if let Some(s) = attr.value_str() { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, errors::LinkName { span, attr_span, value: s.as_str() }, ); } else { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1710,7 +1702,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some // crates used this, so only emit a warning. - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1741,7 +1733,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::ForeignStatic => "static", _ => unreachable!(), }; - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1751,7 +1743,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some // crates used this, so only emit a warning. - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -1929,7 +1921,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return false; })) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( CONFLICTING_REPR_HINTS, hir_id, hint_spans.collect::>(), @@ -2171,7 +2163,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) { match target { Target::Closure | Target::Expression | Target::Statement | Target::Arm => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -2187,7 +2179,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::ExternCrate | Target::Mod => {} _ => { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -2199,7 +2191,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::MacroDef { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -2209,7 +2201,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && !meta_item_list.is_empty() { if meta_item_list.len() > 1 { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_MACRO_EXPORT_ARGUMENTS, hir_id, attr.span, @@ -2217,7 +2209,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } else { if meta_item_list[0].name_or_empty() != sym::local_inner_macros { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INVALID_MACRO_EXPORT_ARGUMENTS, hir_id, meta_item_list[0].span(), @@ -2234,7 +2226,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_decl_macro = !macro_definition.macro_rules; if is_decl_macro { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -2276,7 +2268,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; }; - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -2530,6 +2522,14 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { if attr.style == AttrStyle::Inner { for attr_to_check in ATTRS_TO_CHECK { if attr.has_name(*attr_to_check) { + if let AttrKind::Normal(ref p) = attr.kind + && let Some(diag) = tcx.dcx().steal_diagnostic( + p.item.path.span, + StashKey::UndeterminedMacroResolution, + ) + { + diag.cancel(); + } let item = tcx .hir() .items() @@ -2609,7 +2609,7 @@ fn check_duplicates( } else { (attr.span, *entry.get()) }; - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, this, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d7f17ac4547ab..e11102c459e42 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -4,6 +4,7 @@ // is dead. use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; +use hir::ItemKind; use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir as hir; @@ -14,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{sym, Symbol}; @@ -199,7 +200,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && !assign.span.from_expansion() { let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( lint::builtin::DEAD_CODE, assign.hir_id, assign.span, @@ -381,9 +382,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, item) } hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::Trait(..) => { + 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 + { + // skip items + // mark dependent traits live + intravisit::walk_generics(self, impl_ref.generics); + // mark dependent parameters live + intravisit::walk_path(self, impl_ref.of_trait.unwrap().path); + } + } + + intravisit::walk_item(self, item) + } _ => intravisit::walk_item(self, item), }, Node::TraitItem(trait_item) => { + // mark corresponing ImplTerm live + let trait_item_id = trait_item.owner_id.to_def_id(); + if let Some(trait_id) = self.tcx.trait_of_item(trait_item_id) { + // mark the trait live + self.check_def_id(trait_id); + + 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 + { + // mark self_ty live + intravisit::walk_ty(self, impl_ref.self_ty); + if let Some(&impl_item_id) = + self.tcx.impl_item_implementor_ids(impl_id).get(&trait_item_id) + { + self.check_def_id(impl_item_id); + } + } + } + } intravisit::walk_trait_item(self, trait_item); } Node::ImplItem(impl_item) => { @@ -464,7 +502,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.lookup_and_handle_method(expr.hir_id); } hir::ExprKind::Field(ref lhs, ..) => { - self.handle_field_access(lhs, expr.hir_id); + if self.typeck_results().opt_field_index(expr.hir_id).is_some() { + self.handle_field_access(lhs, expr.hir_id); + } else { + self.tcx.dcx().span_delayed_bug(expr.span, "couldn't resolve index for field"); + } } hir::ExprKind::Struct(qpath, fields, _) => { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); @@ -632,10 +674,6 @@ fn check_item<'tcx>( } } DefKind::Impl { of_trait } => { - if of_trait { - worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No)); - } - // get DefIds from another query let local_def_ids = tcx .associated_item_def_ids(id.owner_id) @@ -644,7 +682,11 @@ fn check_item<'tcx>( // And we access the Map here to get HirId from LocalDefId for id in local_def_ids { - if of_trait { + // for impl trait blocks, mark associate functions live if the trait is public + if of_trait + && (!matches!(tcx.def_kind(id), DefKind::AssocFn) + || tcx.local_visibility(id) == Visibility::Public) + { worklist.push((id, ComesFromAllowExpect::No)); } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id) { worklist.push((id, comes_from_allow)); @@ -675,7 +717,7 @@ fn check_trait_item( use hir::TraitItemKind::{Const, Fn}; if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) + if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { @@ -899,7 +941,7 @@ impl<'tcx> DeadVisitor<'tcx> { }; let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id); - self.tcx.emit_spanned_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); + self.tcx.emit_node_span_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); } fn warn_multiple( @@ -917,7 +959,7 @@ impl<'tcx> DeadVisitor<'tcx> { return; } dead_codes.sort_by_key(|v| v.level); - for group in dead_codes[..].group_by(|a, b| a.level == b.level) { + for group in dead_codes[..].chunk_by(|a, b| a.level == b.level) { self.lint_at_single_level(&group, participle, Some(def_id), report_on); } } @@ -944,7 +986,8 @@ impl<'tcx> DeadVisitor<'tcx> { | DefKind::TyAlias | DefKind::Enum | DefKind::Union - | DefKind::ForeignTy => self.warn_dead_code(def_id, "used"), + | DefKind::ForeignTy + | DefKind::Trait => self.warn_dead_code(def_id, "used"), DefKind::Struct => self.warn_dead_code(def_id, "constructed"), DefKind::Variant | DefKind::Field => bug!("should be handled specially"), _ => {} @@ -969,18 +1012,33 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let module_items = tcx.hir_module_items(module); for item in module_items.items() { - if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { - let mut dead_items = Vec::new(); - for item in impl_item.items { - let def_id = item.id.owner_id.def_id; - if !visitor.is_live_code(def_id) { - let name = tcx.item_name(def_id.to_def_id()); - let level = visitor.def_lint_level(def_id); + let def_kind = tcx.def_kind(item.owner_id); + + let mut dead_codes = Vec::new(); + // if we have diagnosed the trait, do not diagnose unused methods + if matches!(def_kind, DefKind::Impl { .. }) + || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) + { + for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { + // We have diagnosed unused methods in traits + if matches!(def_kind, DefKind::Impl { of_trait: true }) + && tcx.def_kind(def_id) == DefKind::AssocFn + || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn + { + continue; + } - dead_items.push(DeadItem { def_id, name, level }) + if let Some(local_def_id) = def_id.as_local() + && !visitor.is_live_code(local_def_id) + { + let name = tcx.item_name(def_id); + let level = visitor.def_lint_level(local_def_id); + dead_codes.push(DeadItem { def_id: local_def_id, name, level }); } } - visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, ReportOn::NamedField); + } + if !dead_codes.is_empty() { + visitor.warn_multiple(item.owner_id.def_id, "used", dead_codes, ReportOn::NamedField); } if !live_symbols.contains(&item.owner_id.def_id) { @@ -993,7 +1051,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { continue; } - let def_kind = tcx.def_kind(item.owner_id); if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind { let adt = tcx.adt_def(item.owner_id); let mut dead_variants = Vec::new(); @@ -1040,8 +1097,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { for foreign_item in module_items.foreign_items() { visitor.check_definition(foreign_item.owner_id.def_id); } - - // We do not warn trait items. } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 25ca685cbfade..97c70e327f0fe 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,6 +1,6 @@ use rustc_ast::attr; use rustc_ast::entry::EntryPointType; -use rustc_errors::error_code; +use rustc_errors::codes::*; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; @@ -180,8 +180,8 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) { Default::default() }); let main_def_opt = tcx.resolutions(()).main_def; - let code = error_code!(E0601); - let add_teach_note = tcx.sess.teach(&code); + let code = E0601; + let add_teach_note = tcx.sess.teach(code); // The file may be empty, which leads to the diagnostic machinery not emitting this // note. This is a relatively simple way to detect that case and emit a span-less // note instead. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cf3c7cc4ace0d..6a499a98681e6 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,7 +6,7 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::Label; use rustc_errors::{ - error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticSymbolList, EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, }; use rustc_hir::{self as hir, ExprKind, Target}; @@ -55,7 +55,7 @@ pub struct IgnoredInlineAttrFnProto; pub struct IgnoredInlineAttrConstants; #[derive(Diagnostic)] -#[diag(passes_inline_not_fn_or_closure, code = "E0518")] +#[diag(passes_inline_not_fn_or_closure, code = E0518)] pub struct InlineNotFnOrClosure { #[primary_span] pub attr_span: Span, @@ -76,7 +76,7 @@ pub struct IgnoredCoveragePropagate; pub struct IgnoredCoverageFnDefn; #[derive(Diagnostic)] -#[diag(passes_coverage_not_coverable, code = "E0788")] +#[diag(passes_coverage_not_coverable, code = E0788)] pub struct IgnoredCoverageNotCoverable { #[primary_span] pub attr_span: Span, @@ -95,14 +95,14 @@ pub struct AttrShouldBeAppliedToFn { } #[derive(Diagnostic)] -#[diag(passes_naked_tracked_caller, code = "E0736")] +#[diag(passes_naked_tracked_caller, code = E0736)] pub struct NakedTrackedCaller { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_fn, code = "E0739")] +#[diag(passes_should_be_applied_to_fn, code = E0739)] pub struct TrackedCallerWrongLocation { #[primary_span] pub attr_span: Span, @@ -112,7 +112,7 @@ pub struct TrackedCallerWrongLocation { } #[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")] +#[diag(passes_should_be_applied_to_struct_enum, code = E0701)] pub struct NonExhaustiveWrongLocation { #[primary_span] pub attr_span: Span, @@ -370,33 +370,26 @@ pub struct HasIncoherentInherentImpl { } #[derive(Diagnostic)] -#[diag(passes_both_ffi_const_and_pure, code = "E0757")] +#[diag(passes_both_ffi_const_and_pure, code = E0757)] pub struct BothFfiConstAndPure { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_ffi_pure_invalid_target, code = "E0755")] +#[diag(passes_ffi_pure_invalid_target, code = E0755)] pub struct FfiPureInvalidTarget { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_ffi_const_invalid_target, code = "E0756")] +#[diag(passes_ffi_const_invalid_target, code = E0756)] pub struct FfiConstInvalidTarget { #[primary_span] pub attr_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_ffi_returns_twice_invalid_target, code = "E0724")] -pub struct FfiReturnsTwiceInvalidTarget { - #[primary_span] - pub attr_span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_must_use_async)] pub struct MustUseAsync { @@ -552,21 +545,21 @@ pub struct NoMangle { } #[derive(Diagnostic)] -#[diag(passes_repr_ident, code = "E0565")] +#[diag(passes_repr_ident, code = E0565)] pub struct ReprIdent { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes_repr_conflicting, code = "E0566")] +#[diag(passes_repr_conflicting, code = E0566)] pub struct ReprConflicting { #[primary_span] pub hint_spans: Vec, } #[derive(LintDiagnostic)] -#[diag(passes_repr_conflicting, code = "E0566")] +#[diag(passes_repr_conflicting, code = E0566)] pub struct ReprConflictingLint; #[derive(Diagnostic)] @@ -667,7 +660,7 @@ pub(crate) struct EmptyConfusables { } #[derive(Diagnostic)] -#[diag(passes_incorrect_meta_item, code = "E0539")] +#[diag(passes_incorrect_meta_item, code = E0539)] pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, @@ -737,7 +730,7 @@ pub struct Unused { } #[derive(Diagnostic)] -#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")] +#[diag(passes_non_exported_macro_invalid_attrs, code = E0518)] pub struct NonExportedMacroInvalidAttrs { #[primary_span] #[label] @@ -801,7 +794,7 @@ pub struct DeprecatedAnnotationHasNoEffect { } #[derive(Diagnostic)] -#[diag(passes_unknown_external_lang_item, code = "E0264")] +#[diag(passes_unknown_external_lang_item, code = E0264)] pub struct UnknownExternLangItem { #[primary_span] pub span: Span, @@ -837,7 +830,7 @@ pub struct LangItemWithTargetFeature { } #[derive(Diagnostic)] -#[diag(passes_lang_item_on_incorrect_target, code = "E0718")] +#[diag(passes_lang_item_on_incorrect_target, code = E0718)] pub struct LangItemOnIncorrectTarget { #[primary_span] #[label] @@ -848,7 +841,7 @@ pub struct LangItemOnIncorrectTarget { } #[derive(Diagnostic)] -#[diag(passes_unknown_lang_item, code = "E0522")] +#[diag(passes_unknown_lang_item, code = E0522)] pub struct UnknownLangItem { #[primary_span] #[label] @@ -990,7 +983,7 @@ pub struct UnrecognizedField { } #[derive(Diagnostic)] -#[diag(passes_feature_stable_twice, code = "E0711")] +#[diag(passes_feature_stable_twice, code = E0711)] pub struct FeatureStableTwice { #[primary_span] pub span: Span, @@ -1000,7 +993,7 @@ pub struct FeatureStableTwice { } #[derive(Diagnostic)] -#[diag(passes_feature_previously_declared, code = "E0711")] +#[diag(passes_feature_previously_declared, code = E0711)] pub struct FeaturePreviouslyDeclared<'a, 'b> { #[primary_span] pub span: Span, @@ -1025,7 +1018,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_break_non_loop); diag.span(self.span); - diag.code(error_code!(E0571)); + diag.code(E0571); diag.arg("kind", self.kind); diag.span_label(self.span, fluent::passes_label); if let Some(head) = self.head { @@ -1063,7 +1056,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { } #[derive(Diagnostic)] -#[diag(passes_continue_labeled_block, code = "E0696")] +#[diag(passes_continue_labeled_block, code = E0696)] pub struct ContinueLabeledBlock { #[primary_span] #[label] @@ -1073,7 +1066,7 @@ pub struct ContinueLabeledBlock { } #[derive(Diagnostic)] -#[diag(passes_break_inside_closure, code = "E0267")] +#[diag(passes_break_inside_closure, code = E0267)] pub struct BreakInsideClosure<'a> { #[primary_span] #[label] @@ -1084,7 +1077,7 @@ pub struct BreakInsideClosure<'a> { } #[derive(Diagnostic)] -#[diag(passes_break_inside_async_block, code = "E0267")] +#[diag(passes_break_inside_async_block, code = E0267)] pub struct BreakInsideAsyncBlock<'a> { #[primary_span] #[label] @@ -1095,7 +1088,7 @@ pub struct BreakInsideAsyncBlock<'a> { } #[derive(Diagnostic)] -#[diag(passes_outside_loop, code = "E0268")] +#[diag(passes_outside_loop, code = E0268)] pub struct OutsideLoop<'a> { #[primary_span] #[label] @@ -1115,7 +1108,7 @@ pub struct OutsideLoopSuggestion { } #[derive(Diagnostic)] -#[diag(passes_unlabeled_in_labeled_block, code = "E0695")] +#[diag(passes_unlabeled_in_labeled_block, code = E0695)] pub struct UnlabeledInLabeledBlock<'a> { #[primary_span] #[label] @@ -1124,7 +1117,7 @@ pub struct UnlabeledInLabeledBlock<'a> { } #[derive(Diagnostic)] -#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")] +#[diag(passes_unlabeled_cf_in_while_condition, code = E0590)] pub struct UnlabeledCfInWhileCondition<'a> { #[primary_span] #[label] @@ -1169,7 +1162,7 @@ impl IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_naked_functions_asm_block); diag.span(self.span); - diag.code(error_code!(E0787)); + diag.code(E0787); for span in self.multiple_asms.iter() { diag.span_label(*span, fluent::passes_label_multiple_asm); } @@ -1181,14 +1174,14 @@ impl IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_operands, code = "E0787")] +#[diag(passes_naked_functions_operands, code = E0787)] pub struct NakedFunctionsOperands { #[primary_span] pub unsupported_operands: Vec, } #[derive(Diagnostic)] -#[diag(passes_naked_functions_asm_options, code = "E0787")] +#[diag(passes_naked_functions_asm_options, code = E0787)] pub struct NakedFunctionsAsmOptions { #[primary_span] pub span: Span, @@ -1196,7 +1189,7 @@ pub struct NakedFunctionsAsmOptions { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")] +#[diag(passes_naked_functions_must_use_noreturn, code = E0787)] pub struct NakedFunctionsMustUseNoreturn { #[primary_span] pub span: Span, @@ -1229,7 +1222,7 @@ pub struct AttrOnlyInFunctions { } #[derive(Diagnostic)] -#[diag(passes_multiple_rustc_main, code = "E0137")] +#[diag(passes_multiple_rustc_main, code = E0137)] pub struct MultipleRustcMain { #[primary_span] pub span: Span, @@ -1240,7 +1233,7 @@ pub struct MultipleRustcMain { } #[derive(Diagnostic)] -#[diag(passes_multiple_start_functions, code = "E0138")] +#[diag(passes_multiple_start_functions, code = E0138)] pub struct MultipleStartFunctions { #[primary_span] pub span: Span, @@ -1280,7 +1273,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_no_main_function); diag.span(DUMMY_SP); - diag.code(error_code!(E0601)); + diag.code(E0601); diag.arg("crate_name", self.crate_name); diag.arg("filename", self.filename); diag.arg("has_filename", self.has_filename); @@ -1345,7 +1338,7 @@ impl IntoDiagnostic<'_, G> for DuplicateLangItem { Duplicate::CrateDepends => fluent::passes_duplicate_lang_item_crate_depends, }, ); - diag.code(error_code!(E0152)); + diag.code(E0152); diag.arg("lang_item_name", self.lang_item_name); diag.arg("crate_name", self.crate_name); diag.arg("dependency_of", self.dependency_of); @@ -1382,7 +1375,7 @@ impl IntoDiagnostic<'_, G> for DuplicateLangItem { } #[derive(Diagnostic)] -#[diag(passes_incorrect_target, code = "E0718")] +#[diag(passes_incorrect_target, code = E0718)] pub struct IncorrectTarget<'a> { #[primary_span] pub span: Span, @@ -1418,7 +1411,7 @@ pub struct ObjectLifetimeErr { } #[derive(Diagnostic)] -#[diag(passes_unrecognized_repr_hint, code = "E0552")] +#[diag(passes_unrecognized_repr_hint, code = E0552)] #[help] pub struct UnrecognizedReprHint { #[primary_span] @@ -1427,35 +1420,35 @@ pub struct UnrecognizedReprHint { #[derive(Diagnostic)] pub enum AttrApplication { - #[diag(passes_attr_application_enum, code = "E0517")] + #[diag(passes_attr_application_enum, code = E0517)] Enum { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct, code = "E0517")] + #[diag(passes_attr_application_struct, code = E0517)] Struct { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct_union, code = "E0517")] + #[diag(passes_attr_application_struct_union, code = E0517)] StructUnion { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct_enum_union, code = "E0517")] + #[diag(passes_attr_application_struct_enum_union, code = E0517)] StructEnumUnion { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct_enum_function_method_union, code = "E0517")] + #[diag(passes_attr_application_struct_enum_function_method_union, code = E0517)] StructEnumFunctionMethodUnion { #[primary_span] hint_span: Span, @@ -1465,7 +1458,7 @@ pub enum AttrApplication { } #[derive(Diagnostic)] -#[diag(passes_transparent_incompatible, code = "E0692")] +#[diag(passes_transparent_incompatible, code = E0692)] pub struct TransparentIncompatible { #[primary_span] pub hint_spans: Vec, @@ -1473,7 +1466,7 @@ pub struct TransparentIncompatible { } #[derive(Diagnostic)] -#[diag(passes_deprecated_attribute, code = "E0549")] +#[diag(passes_deprecated_attribute, code = E0549)] pub struct DeprecatedAttribute { #[primary_span] pub span: Span, @@ -1524,7 +1517,7 @@ pub struct TraitImplConstStable { } #[derive(Diagnostic)] -#[diag(passes_feature_only_on_nightly, code = "E0554")] +#[diag(passes_feature_only_on_nightly, code = E0554)] pub struct FeatureOnlyOnNightly { #[primary_span] pub span: Span, @@ -1532,7 +1525,7 @@ pub struct FeatureOnlyOnNightly { } #[derive(Diagnostic)] -#[diag(passes_unknown_feature, code = "E0635")] +#[diag(passes_unknown_feature, code = E0635)] pub struct UnknownFeature { #[primary_span] pub span: Span, @@ -1549,7 +1542,7 @@ pub struct ImpliedFeatureNotExist { } #[derive(Diagnostic)] -#[diag(passes_duplicate_feature_err, code = "E0636")] +#[diag(passes_duplicate_feature_err, code = E0636)] pub struct DuplicateFeatureErr { #[primary_span] pub span: Span, diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 528a52f42255e..e94d8c4c932f9 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -328,11 +328,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_expr(self, e) } - fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) { - self.record("Let", Id::Node(lex.hir_id), lex); - hir_visit::walk_let_expr(self, lex) - } - fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) { self.record("ExprField", Id::Node(f.hir_id), f); hir_visit::walk_expr_field(self, f) diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 6aeaa8945fb59..9a21397789d6c 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -149,7 +149,9 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { } }; - self.tcx.dcx().emit_err(DuplicateLangItem { + // When there's a duplicate lang item, something went very wrong and there's no value in recovering or doing anything. + // Give the user the one message to let them debug the mess they created and then wish them farewell. + self.tcx.dcx().emit_fatal(DuplicateLangItem { local_span: item_span, lang_item_name, crate_name, diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index bb33a4feb0556..862b76b1f6048 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -8,13 +8,10 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![feature(iter_intersperse)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] -#![feature(slice_group_by)] #![feature(try_blocks)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 92687c705aee6..f7c382bcd7a40 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -719,6 +719,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ty::ClosureKind::FnMut => {} ty::ClosureKind::FnOnce => return succ, }, + ty::CoroutineClosure(_def_id, args) => match args.as_coroutine_closure().kind() { + ty::ClosureKind::Fn => {} + ty::ClosureKind::FnMut => {} + ty::ClosureKind::FnOnce => return succ, + }, ty::Coroutine(..) => return succ, _ => { span_bug!( @@ -1285,7 +1290,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // that we do not emit the same warning twice if the uninhabited type // is indeed `!`. - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNREACHABLE_CODE, expr_id, expr_span, @@ -1446,7 +1451,7 @@ impl<'tcx> Liveness<'_, 'tcx> { if self.used_on_entry(entry_ln, var) { if !self.live_on_entry(entry_ln, var) { if let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, var_hir_id, vec![span], @@ -1456,7 +1461,7 @@ impl<'tcx> Liveness<'_, 'tcx> { } } else { if let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, var_hir_id, vec![span], @@ -1478,7 +1483,7 @@ impl<'tcx> Liveness<'_, 'tcx> { if !self.live_on_entry(ln, var) && let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans, @@ -1552,7 +1557,7 @@ impl<'tcx> Liveness<'_, 'tcx> { if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) }; if is_assigned { - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans @@ -1574,7 +1579,7 @@ impl<'tcx> Liveness<'_, 'tcx> { span.with_hi(BytePos(span.hi().0 + 1)) }) .collect(); - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::>(), @@ -1599,7 +1604,7 @@ impl<'tcx> Liveness<'_, 'tcx> { let non_shorthands = non_shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect(); - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans @@ -1638,7 +1643,7 @@ impl<'tcx> Liveness<'_, 'tcx> { } }; - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans @@ -1690,7 +1695,7 @@ impl<'tcx> Liveness<'_, 'tcx> { if !self.live_on_exit(ln, var) && let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( + self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans, diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index d2cfdb7bf4774..0455d6d4acba3 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -70,7 +70,7 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) { if abi == Abi::Rust { let hir_id = tcx.local_def_id_to_hir_id(def_id); let span = tcx.def_span(def_id); - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 18b9ba0f042df..c1fe8c2133b75 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -122,7 +122,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) { let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( USELESS_DEPRECATED, hir_id, *span, @@ -739,7 +739,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // do not lint when the trait isn't resolved, since resolution error should // be fixed first if t.path.res != Res::Err && c.fully_stable { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), span, @@ -1073,7 +1073,7 @@ fn unnecessary_partially_stable_feature_lint( implies: Symbol, since: Symbol, ) { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, @@ -1096,7 +1096,7 @@ fn unnecessary_stable_feature_lint( if since.as_str() == VERSION_PLACEHOLDER { since = sym::env_CFG_RELEASE; } - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 1d0e1cb7e6a57..b9bdcb41929dc 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -derivative = "2.2.0" rustc-hash = "1.1.0" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 76098505b7944..24824682b74cd 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -162,7 +162,6 @@ use self::MaybeInfiniteInt::*; use self::SliceKind::*; use crate::index; -use crate::usefulness::PlaceCtxt; use crate::TypeCx; /// Whether we have seen a constructor in the column or not. @@ -391,12 +390,18 @@ impl IntRange { /// first. impl fmt::Debug for IntRange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Finite(lo) = self.lo { + if self.is_singleton() { + // Only finite ranges can be singletons. + let Finite(lo) = self.lo else { unreachable!() }; write!(f, "{lo}")?; - } - write!(f, "{}", RangeEnd::Excluded)?; - if let Finite(hi) = self.hi { - write!(f, "{hi}")?; + } else { + if let Finite(lo) = self.lo { + write!(f, "{lo}")?; + } + write!(f, "{}", RangeEnd::Excluded)?; + if let Finite(hi) = self.hi { + write!(f, "{hi}")?; + } } Ok(()) } @@ -642,8 +647,7 @@ impl OpaqueId { /// `specialize_constructor` returns the list of fields corresponding to a pattern, given a /// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and /// `Fields`. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))] +#[derive(Debug)] pub enum Constructor { /// Tuples and structs. Struct, @@ -686,6 +690,33 @@ pub enum Constructor { Missing, } +impl Clone for Constructor { + fn clone(&self) -> Self { + match self { + Constructor::Struct => Constructor::Struct, + Constructor::Variant(idx) => Constructor::Variant(idx.clone()), + Constructor::Ref => Constructor::Ref, + Constructor::Slice(slice) => Constructor::Slice(slice.clone()), + Constructor::UnionField => Constructor::UnionField, + Constructor::Bool(b) => Constructor::Bool(b.clone()), + Constructor::IntRange(range) => Constructor::IntRange(range.clone()), + Constructor::F32Range(lo, hi, end) => { + Constructor::F32Range(lo.clone(), hi.clone(), end.clone()) + } + Constructor::F64Range(lo, hi, end) => { + Constructor::F64Range(lo.clone(), hi.clone(), end.clone()) + } + Constructor::Str(value) => Constructor::Str(value.clone()), + Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), + Constructor::Or => Constructor::Or, + Constructor::Wildcard => Constructor::Wildcard, + Constructor::NonExhaustive => Constructor::NonExhaustive, + Constructor::Hidden => Constructor::Hidden, + Constructor::Missing => Constructor::Missing, + } + } +} + impl Constructor { pub(crate) fn is_non_exhaustive(&self) -> bool { matches!(self, NonExhaustive) @@ -718,8 +749,8 @@ impl Constructor { /// The number of fields for this constructor. This must be kept in sync with /// `Fields::wildcards`. - pub(crate) fn arity(&self, pcx: &PlaceCtxt<'_, Cx>) -> usize { - pcx.ctor_arity(self) + pub(crate) fn arity(&self, cx: &Cx, ty: &Cx::Ty) -> usize { + cx.ctor_arity(self, ty) } /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. @@ -727,12 +758,13 @@ impl Constructor { /// this checks for inclusion. // We inline because this has a single call site in `Matrix::specialize_constructor`. #[inline] - pub(crate) fn is_covered_by(&self, pcx: &PlaceCtxt<'_, Cx>, other: &Self) -> bool { - match (self, other) { - (Wildcard, _) => pcx - .mcx - .tycx - .bug(format_args!("Constructor splitting should not have returned `Wildcard`")), + pub(crate) fn is_covered_by(&self, cx: &Cx, other: &Self) -> Result { + Ok(match (self, other) { + (Wildcard, _) => { + return Err(cx.bug(format_args!( + "Constructor splitting should not have returned `Wildcard`" + ))); + } // Wildcards cover anything (_, Wildcard) => true, // Only a wildcard pattern can match these special constructors. @@ -773,10 +805,12 @@ impl Constructor { (Opaque(self_id), Opaque(other_id)) => self_id == other_id, (Opaque(..), _) | (_, Opaque(..)) => false, - _ => pcx.mcx.tycx.bug(format_args!( - "trying to compare incompatible constructors {self:?} and {other:?}" - )), - } + _ => { + return Err(cx.bug(format_args!( + "trying to compare incompatible constructors {self:?} and {other:?}" + ))); + } + }) } } @@ -850,10 +884,10 @@ pub enum ConstructorSet { /// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be /// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4. #[derive(Debug)] -pub(crate) struct SplitConstructorSet { - pub(crate) present: SmallVec<[Constructor; 1]>, - pub(crate) missing: Vec>, - pub(crate) missing_empty: Vec>, +pub struct SplitConstructorSet { + pub present: SmallVec<[Constructor; 1]>, + pub missing: Vec>, + pub missing_empty: Vec>, } impl ConstructorSet { @@ -861,12 +895,14 @@ impl ConstructorSet { /// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges /// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation /// and its invariants. - #[instrument(level = "debug", skip(self, pcx, ctors), ret)] - pub(crate) fn split<'a>( + #[instrument(level = "debug", skip(self, ctors), ret)] + pub fn split<'a>( &self, - pcx: &PlaceCtxt<'a, Cx>, ctors: impl Iterator> + Clone, - ) -> SplitConstructorSet { + ) -> SplitConstructorSet + where + Cx: 'a, + { let mut present: SmallVec<[_; 1]> = SmallVec::new(); // Empty constructors found missing. let mut missing_empty = Vec::new(); @@ -1006,17 +1042,6 @@ impl ConstructorSet { } } - // We have now grouped all the constructors into 3 buckets: present, missing, missing_empty. - // In the absence of the `exhaustive_patterns` feature however, we don't count nested empty - // types as empty. Only non-nested `!` or `enum Foo {}` are considered empty. - if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on() - && !(pcx.is_scrutinee && matches!(self, Self::NoConstructors)) - { - // Treat all missing constructors as nonempty. - // This clears `missing_empty`. - missing.append(&mut missing_empty); - } - SplitConstructorSet { present, missing, missing_empty } } } diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 88770b0c43b37..bdb6cf19eac4e 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -23,7 +23,10 @@ impl<'tcx> Uncovered<'tcx> { span: Span, cx: &RustcMatchCheckCtxt<'p, 'tcx>, witnesses: Vec>, - ) -> Self { + ) -> Self + where + 'tcx: 'p, + { let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()); Self { span, diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 21fa8e68d82e8..1a151e72488d9 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,6 +6,7 @@ pub mod errors; #[cfg(feature = "rustc")] pub(crate) mod lints; pub mod pat; +pub mod pat_column; #[cfg(feature = "rustc")] pub mod rustc; pub mod usefulness; @@ -67,8 +68,9 @@ use rustc_span::ErrorGuaranteed; use crate::constructor::{Constructor, ConstructorSet, IntRange}; #[cfg(feature = "rustc")] -use crate::lints::{lint_nonexhaustive_missing_variants, PatternColumn}; +use crate::lints::lint_nonexhaustive_missing_variants; use crate::pat::DeconstructedPat; +use crate::pat_column::PatternColumn; #[cfg(feature = "rustc")] use crate::rustc::RustcMatchCheckCtxt; #[cfg(feature = "rustc")] @@ -82,7 +84,7 @@ impl<'a, T: ?Sized> Captures<'a> for T {} /// Most of the crate is parameterized on a type that implements this trait. pub trait TypeCx: Sized + fmt::Debug { /// The type of a pattern. - type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy + type Ty: Clone + fmt::Debug; /// Errors that can abort analysis. type Error: fmt::Debug; /// The index of an enum variant. @@ -95,55 +97,62 @@ pub trait TypeCx: Sized + fmt::Debug { type PatData: Clone; fn is_exhaustive_patterns_feature_on(&self) -> bool; + fn is_min_exhaustive_patterns_feature_on(&self) -> bool; /// The number of fields for this constructor. - fn ctor_arity(&self, ctor: &Constructor, ty: Self::Ty) -> usize; + fn ctor_arity(&self, ctor: &Constructor, ty: &Self::Ty) -> usize; /// The types of the fields for this constructor. The result must have a length of /// `ctor_arity()`. - fn ctor_sub_tys(&self, ctor: &Constructor, ty: Self::Ty) -> &[Self::Ty]; + fn ctor_sub_tys<'a>( + &'a self, + ctor: &'a Constructor, + ty: &'a Self::Ty, + ) -> impl Iterator + ExactSizeIterator + Captures<'a>; /// The set of all the constructors for `ty`. /// /// This must follow the invariants of `ConstructorSet` - fn ctors_for_ty(&self, ty: Self::Ty) -> Result, Self::Error>; + fn ctors_for_ty(&self, ty: &Self::Ty) -> Result, Self::Error>; - /// Best-effort `Debug` implementation. - fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result; + /// Write the name of the variant represented by `pat`. Used for the best-effort `Debug` impl of + /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`. + fn write_variant_name( + f: &mut fmt::Formatter<'_>, + pat: &crate::pat::DeconstructedPat, + ) -> fmt::Result; /// Raise a bug. - fn bug(&self, fmt: fmt::Arguments<'_>) -> !; + fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error; /// Lint that the range `pat` overlapped with all the ranges in `overlaps_with`, where the range /// they overlapped over is `overlaps_on`. We only detect singleton overlaps. /// The default implementation does nothing. fn lint_overlapping_range_endpoints( &self, - _pat: &DeconstructedPat<'_, Self>, + _pat: &DeconstructedPat, _overlaps_on: IntRange, - _overlaps_with: &[&DeconstructedPat<'_, Self>], + _overlaps_with: &[&DeconstructedPat], ) { } } -/// Context that provides information global to a match. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""))] -pub struct MatchCtxt<'a, Cx: TypeCx> { - /// The context for type information. - pub tycx: &'a Cx, -} - /// The arm of a match expression. #[derive(Debug)] -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""))] pub struct MatchArm<'p, Cx: TypeCx> { - pub pat: &'p DeconstructedPat<'p, Cx>, + pub pat: &'p DeconstructedPat, pub has_guard: bool, pub arm_data: Cx::ArmData, } +impl<'p, Cx: TypeCx> Clone for MatchArm<'p, Cx> { + fn clone(&self) -> Self { + Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data } + } +} + +impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {} + /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are /// useful, and runs some lints. #[cfg(feature = "rustc")] @@ -154,15 +163,13 @@ pub fn analyze_match<'p, 'tcx>( ) -> Result, ErrorGuaranteed> { let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee); - let cx = MatchCtxt { tycx }; - - let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?; + let report = compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity)?; // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() { let pat_column = PatternColumn::new(arms); - lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?; + lint_nonexhaustive_missing_variants(tycx, arms, &pat_column, scrut_ty)?; } Ok(report) diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 4266e2a405e5f..3f1497540d25e 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -1,109 +1,24 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::ErrorGuaranteed; +use crate::constructor::Constructor; use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered}; -use crate::pat::PatOrWild; -use crate::rustc::{ - Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt, - SplitConstructorSet, WitnessPat, -}; - -/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that -/// inspect the same subvalue/place". -/// This is used to traverse patterns column-by-column for lints. Despite similarities with the -/// algorithm in [`crate::usefulness`], this does a different traversal. Notably this is linear in -/// the depth of patterns, whereas `compute_exhaustiveness_and_usefulness` is worst-case exponential -/// (exhaustiveness is NP-complete). The core difference is that we treat sub-columns separately. -/// -/// This must not contain an or-pattern. `expand_and_push` takes care to expand them. -/// -/// This is not used in the usefulness algorithm; only in lints. -#[derive(Debug)] -pub(crate) struct PatternColumn<'p, 'tcx> { - patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>, -} - -impl<'p, 'tcx> PatternColumn<'p, 'tcx> { - pub(crate) fn new(arms: &[MatchArm<'p, 'tcx>]) -> Self { - let patterns = Vec::with_capacity(arms.len()); - let mut column = PatternColumn { patterns }; - for arm in arms { - column.expand_and_push(PatOrWild::Pat(arm.pat)); - } - column - } - /// Pushes a pattern onto the column, expanding any or-patterns into its subpatterns. - /// Internal method, prefer [`PatternColumn::new`]. - fn expand_and_push(&mut self, pat: PatOrWild<'p, RustcMatchCheckCtxt<'p, 'tcx>>) { - // We flatten or-patterns and skip algorithm-generated wildcards. - if pat.is_or_pat() { - self.patterns.extend( - pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()), - ) - } else if let Some(pat) = pat.as_pat() { - self.patterns.push(pat) - } - } - - fn head_ty(&self) -> Option> { - self.patterns.first().map(|pat| pat.ty()) - } - - /// Do constructor splitting on the constructors of the column. - fn analyze_ctors( - &self, - pcx: &PlaceCtxt<'_, 'p, 'tcx>, - ) -> Result, ErrorGuaranteed> { - let column_ctors = self.patterns.iter().map(|p| p.ctor()); - let ctors_for_ty = &pcx.ctors_for_ty()?; - Ok(ctors_for_ty.split(pcx, column_ctors)) - } - - /// Does specialization: given a constructor, this takes the patterns from the column that match - /// the constructor, and outputs their fields. - /// This returns one column per field of the constructor. They usually all have the same length - /// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns - /// which may change the lengths. - fn specialize( - &self, - pcx: &PlaceCtxt<'_, 'p, 'tcx>, - ctor: &Constructor<'p, 'tcx>, - ) -> Vec> { - let arity = ctor.arity(pcx); - if arity == 0 { - return Vec::new(); - } - - // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These - // columns may have different lengths in the presence of or-patterns (this is why we can't - // reuse `Matrix`). - let mut specialized_columns: Vec<_> = - (0..arity).map(|_| Self { patterns: Vec::new() }).collect(); - let relevant_patterns = - self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); - for pat in relevant_patterns { - let specialized = pat.specialize(ctor, arity); - for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) { - column.expand_and_push(subpat); - } - } - specialized_columns - } -} +use crate::pat_column::PatternColumn; +use crate::rustc::{RevealedTy, RustcMatchCheckCtxt, WitnessPat}; +use crate::MatchArm; /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned /// in a given column. #[instrument(level = "debug", skip(cx), ret)] fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( - cx: MatchCtxt<'a, 'p, 'tcx>, - column: &PatternColumn<'p, 'tcx>, + cx: &RustcMatchCheckCtxt<'p, 'tcx>, + column: &PatternColumn<'p, RustcMatchCheckCtxt<'p, 'tcx>>, ) -> Result>, ErrorGuaranteed> { - let Some(ty) = column.head_ty() else { + let Some(&ty) = column.head_ty() else { return Ok(Vec::new()); }; - let pcx = &PlaceCtxt::new_dummy(cx, ty); - let set = column.analyze_ctors(pcx)?; + let set = column.analyze_ctors(cx, &ty)?; if set.present.is_empty() { // We can't consistently handle the case where no constructors are present (since this would // require digging deep through any type in case there's a non_exhaustive enum somewhere), @@ -112,20 +27,20 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( } let mut witnesses = Vec::new(); - if cx.tycx.is_foreign_non_exhaustive_enum(ty) { + if cx.is_foreign_non_exhaustive_enum(ty) { witnesses.extend( set.missing .into_iter() // This will list missing visible variants. .filter(|c| !matches!(c, Constructor::Hidden | Constructor::NonExhaustive)) - .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor)), + .map(|missing_ctor| WitnessPat::wild_from_ctor(cx, missing_ctor, ty)), ) } // Recurse into the fields. for ctor in set.present { - let specialized_columns = column.specialize(pcx, &ctor); - let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor); + let specialized_columns = column.specialize(cx, &ty, &ctor); + let wild_pat = WitnessPat::wild_from_ctor(cx, ctor, ty); for (i, col_i) in specialized_columns.iter().enumerate() { // Compute witnesses for each column. let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i)?; @@ -141,24 +56,23 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( Ok(witnesses) } -pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>( - cx: MatchCtxt<'a, 'p, 'tcx>, - arms: &[MatchArm<'p, 'tcx>], - pat_column: &PatternColumn<'p, 'tcx>, +pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>( + rcx: &RustcMatchCheckCtxt<'p, 'tcx>, + arms: &[MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>], + pat_column: &PatternColumn<'p, RustcMatchCheckCtxt<'p, 'tcx>>, scrut_ty: RevealedTy<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx; if !matches!( rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0, rustc_session::lint::Level::Allow ) { - let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column)?; + let witnesses = collect_nonexhaustive_missing_variants(rcx, pat_column)?; if !witnesses.is_empty() { // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` // is not exhaustive enough. // // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. - rcx.tcx.emit_spanned_lint( + rcx.tcx.emit_node_span_lint( NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level, rcx.scrut_span, diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 75fe59edf88f2..9bde23c7bf124 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -6,8 +6,7 @@ use std::fmt; use smallvec::{smallvec, SmallVec}; use crate::constructor::{Constructor, Slice, SliceKind}; -use crate::usefulness::PlaceCtxt; -use crate::{Captures, TypeCx}; +use crate::TypeCx; use self::Constructor::*; @@ -22,9 +21,9 @@ use self::Constructor::*; /// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't /// observe that it is uninhabited. In that case that field is not included in `fields`. Care must /// be taken when converting to/from `thir::Pat`. -pub struct DeconstructedPat<'p, Cx: TypeCx> { +pub struct DeconstructedPat { ctor: Constructor, - fields: &'p [DeconstructedPat<'p, Cx>], + fields: Vec>, ty: Cx::Ty, /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not /// correspond to a user-supplied pattern. @@ -33,14 +32,20 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> { useful: Cell, } -impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { +impl DeconstructedPat { pub fn wildcard(ty: Cx::Ty) -> Self { - DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) } + DeconstructedPat { + ctor: Wildcard, + fields: Vec::new(), + ty, + data: None, + useful: Cell::new(false), + } } pub fn new( ctor: Constructor, - fields: &'p [DeconstructedPat<'p, Cx>], + fields: Vec>, ty: Cx::Ty, data: Cx::PatData, ) -> Self { @@ -54,8 +59,8 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { pub fn ctor(&self) -> &Constructor { &self.ctor } - pub fn ty(&self) -> Cx::Ty { - self.ty + pub fn ty(&self) -> &Cx::Ty { + &self.ty } /// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that /// does not correspond to a user-supplied pattern. @@ -63,17 +68,17 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { self.data.as_ref() } - pub fn iter_fields(&self) -> impl Iterator> + Captures<'_> { + pub fn iter_fields<'a>(&'a self) -> impl Iterator> { self.fields.iter() } /// Specialize this pattern with a constructor. /// `other_ctor` can be different from `self.ctor`, but must be covered by it. - pub(crate) fn specialize( - &self, + pub(crate) fn specialize<'a>( + &'a self, other_ctor: &Constructor, ctor_arity: usize, - ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> { + ) -> SmallVec<[PatOrWild<'a, Cx>; 2]> { let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect(); match (&self.ctor, other_ctor) { // Return a wildcard for each field of `other_ctor`. @@ -140,9 +145,77 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { } /// This is best effort and not good enough for a `Display` impl. -impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { +impl fmt::Debug for DeconstructedPat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Cx::debug_pat(f, self) + let pat = self; + let mut first = true; + let mut start_or_continue = |s| { + if first { + first = false; + "" + } else { + s + } + }; + let mut start_or_comma = || start_or_continue(", "); + + match pat.ctor() { + Struct | Variant(_) | UnionField => { + Cx::write_variant_name(f, pat)?; + // Without `cx`, we can't know which field corresponds to which, so we can't + // get the names of the fields. Instead we just display everything as a tuple + // struct, which should be good enough. + write!(f, "(")?; + for p in pat.iter_fields() { + write!(f, "{}", start_or_comma())?; + write!(f, "{p:?}")?; + } + write!(f, ")") + } + // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should + // be careful to detect strings here. However a string literal pattern will never + // be reported as a non-exhaustiveness witness, so we can ignore this issue. + Ref => { + let subpattern = pat.iter_fields().next().unwrap(); + write!(f, "&{:?}", subpattern) + } + Slice(slice) => { + let mut subpatterns = pat.iter_fields(); + write!(f, "[")?; + match slice.kind { + SliceKind::FixedLen(_) => { + for p in subpatterns { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + } + SliceKind::VarLen(prefix_len, _) => { + for p in subpatterns.by_ref().take(prefix_len) { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + write!(f, "{}", start_or_comma())?; + write!(f, "..")?; + for p in subpatterns { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + } + } + write!(f, "]") + } + Bool(b) => write!(f, "{b}"), + // Best-effort, will render signed ranges incorrectly + IntRange(range) => write!(f, "{range:?}"), + F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), + F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), + Str(value) => write!(f, "{value:?}"), + Opaque(..) => write!(f, ""), + Or => { + for pat in pat.iter_fields() { + write!(f, "{}{:?}", start_or_continue(" | "), pat)?; + } + Ok(()) + } + Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()), + } } } @@ -150,17 +223,26 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { /// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input. /// /// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""))] pub(crate) enum PatOrWild<'p, Cx: TypeCx> { /// A non-user-provided wildcard, created during specialization. Wild, /// A user-provided pattern. - Pat(&'p DeconstructedPat<'p, Cx>), + Pat(&'p DeconstructedPat), } +impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> { + fn clone(&self) -> Self { + match self { + PatOrWild::Wild => PatOrWild::Wild, + PatOrWild::Pat(pat) => PatOrWild::Pat(pat), + } + } +} + +impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {} + impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> { - pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { + pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat> { match self { PatOrWild::Wild => None, PatOrWild::Pat(pat) => Some(pat), @@ -221,14 +303,19 @@ impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> { /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics /// purposes. As such they don't use interning and can be cloned. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] +#[derive(Debug)] pub struct WitnessPat { ctor: Constructor, pub(crate) fields: Vec>, ty: Cx::Ty, } +impl Clone for WitnessPat { + fn clone(&self) -> Self { + Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() } + } +} + impl WitnessPat { pub(crate) fn new(ctor: Constructor, fields: Vec, ty: Cx::Ty) -> Self { Self { ctor, fields, ty } @@ -240,17 +327,16 @@ impl WitnessPat { /// Construct a pattern that matches everything that starts with this constructor. /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern /// `Some(_)`. - pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, Cx>, ctor: Constructor) -> Self { - let field_tys = pcx.ctor_sub_tys(&ctor); - let fields = field_tys.iter().map(|ty| Self::wildcard(*ty)).collect(); - Self::new(ctor, fields, pcx.ty) + pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor, ty: Cx::Ty) -> Self { + let fields = cx.ctor_sub_tys(&ctor, &ty).map(|ty| Self::wildcard(ty)).collect(); + Self::new(ctor, fields, ty) } pub fn ctor(&self) -> &Constructor { &self.ctor } - pub fn ty(&self) -> Cx::Ty { - self.ty + pub fn ty(&self) -> &Cx::Ty { + &self.ty } pub fn iter_fields(&self) -> impl Iterator> { diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs new file mode 100644 index 0000000000000..ce14fdc364f79 --- /dev/null +++ b/compiler/rustc_pattern_analysis/src/pat_column.rs @@ -0,0 +1,90 @@ +use crate::constructor::{Constructor, SplitConstructorSet}; +use crate::pat::{DeconstructedPat, PatOrWild}; +use crate::{Captures, MatchArm, TypeCx}; + +/// A column of patterns in a match, where a column is the intuitive notion of "subpatterns that +/// inspect the same subvalue/place". +/// This is used to traverse patterns column-by-column for lints. Despite similarities with the +/// algorithm in [`crate::usefulness`], this does a different traversal. Notably this is linear in +/// the depth of patterns, whereas `compute_exhaustiveness_and_usefulness` is worst-case exponential +/// (exhaustiveness is NP-complete). The core difference is that we treat sub-columns separately. +/// +/// This is not used in the usefulness algorithm; only in lints. +#[derive(Debug)] +pub struct PatternColumn<'p, Cx: TypeCx> { + /// This must not contain an or-pattern. `expand_and_push` takes care to expand them. + patterns: Vec<&'p DeconstructedPat>, +} + +impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> { + pub fn new(arms: &[MatchArm<'p, Cx>]) -> Self { + let patterns = Vec::with_capacity(arms.len()); + let mut column = PatternColumn { patterns }; + for arm in arms { + column.expand_and_push(PatOrWild::Pat(arm.pat)); + } + column + } + /// Pushes a pattern onto the column, expanding any or-patterns into its subpatterns. + /// Internal method, prefer [`PatternColumn::new`]. + fn expand_and_push(&mut self, pat: PatOrWild<'p, Cx>) { + // We flatten or-patterns and skip algorithm-generated wildcards. + if pat.is_or_pat() { + self.patterns.extend( + pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()), + ) + } else if let Some(pat) = pat.as_pat() { + self.patterns.push(pat) + } + } + + 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> { + self.patterns.iter().copied() + } + + /// Do constructor splitting on the constructors of the column. + pub fn analyze_ctors( + &self, + cx: &Cx, + ty: &Cx::Ty, + ) -> Result, Cx::Error> { + let column_ctors = self.patterns.iter().map(|p| p.ctor()); + let ctors_for_ty = cx.ctors_for_ty(ty)?; + Ok(ctors_for_ty.split(column_ctors)) + } + + /// Does specialization: given a constructor, this takes the patterns from the column that match + /// the constructor, and outputs their fields. + /// This returns one column per field of the constructor. They usually all have the same length + /// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns + /// which may change the lengths. + pub fn specialize( + &self, + cx: &Cx, + ty: &Cx::Ty, + ctor: &Constructor, + ) -> Vec> { + let arity = ctor.arity(cx, ty); + if arity == 0 { + return Vec::new(); + } + + // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These + // columns may have different lengths in the presence of or-patterns (this is why we can't + // reuse `Matrix`). + let mut specialized_columns: Vec<_> = + (0..arity).map(|_| Self { patterns: Vec::new() }).collect(); + let relevant_patterns = + self.patterns.iter().filter(|pat| ctor.is_covered_by(cx, pat.ctor()).unwrap_or(false)); + for pat in relevant_patterns { + let specialized = pat.specialize(ctor, arity); + for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) { + column.expand_and_push(subpat); + } + } + specialized_columns + } +} diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 87e70d68c1b46..a8fe0cb6a1dc7 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,9 +1,7 @@ -use smallvec::SmallVec; use std::fmt; use std::iter::once; -use rustc_arena::{DroplessArena, TypedArena}; -use rustc_data_structures::captures::Captures; +use rustc_arena::DroplessArena; use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_index::{Idx, IndexVec}; @@ -20,7 +18,7 @@ use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT}; use crate::constructor::{ IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility, }; -use crate::{errors, TypeCx}; +use crate::{errors, Captures, TypeCx}; use crate::constructor::Constructor::*; @@ -28,14 +26,8 @@ use crate::constructor::Constructor::*; pub type Constructor<'p, 'tcx> = crate::constructor::Constructor>; pub type ConstructorSet<'p, 'tcx> = crate::constructor::ConstructorSet>; -pub type DeconstructedPat<'p, 'tcx> = - crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>; +pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat>; pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>; -pub type MatchCtxt<'a, 'p, 'tcx> = crate::MatchCtxt<'a, RustcMatchCheckCtxt<'p, 'tcx>>; -pub(crate) type PlaceCtxt<'a, 'p, 'tcx> = - crate::usefulness::PlaceCtxt<'a, RustcMatchCheckCtxt<'p, 'tcx>>; -pub(crate) type SplitConstructorSet<'p, 'tcx> = - crate::constructor::SplitConstructorSet>; pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>; pub type UsefulnessReport<'p, 'tcx> = crate::usefulness::UsefulnessReport<'p, RustcMatchCheckCtxt<'p, 'tcx>>; @@ -47,11 +39,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat`. #[repr(transparent)] -#[derive(derivative::Derivative)] #[derive(Clone, Copy)] -#[derivative(Debug = "transparent")] pub struct RevealedTy<'tcx>(Ty<'tcx>); +impl<'tcx> fmt::Debug for RevealedTy<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + impl<'tcx> std::ops::Deref for RevealedTy<'tcx> { type Target = Ty<'tcx>; fn deref(&self) -> &Self::Target { @@ -66,7 +62,7 @@ impl<'tcx> RevealedTy<'tcx> { } #[derive(Clone)] -pub struct RustcMatchCheckCtxt<'p, 'tcx> { +pub struct RustcMatchCheckCtxt<'p, 'tcx: 'p> { pub tcx: TyCtxt<'tcx>, pub typeck_results: &'tcx ty::TypeckResults<'tcx>, /// The module in which the match occurs. This is necessary for @@ -76,8 +72,6 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> { /// outside its module and should not be matchable with an empty match statement. pub module: DefId, pub param_env: ty::ParamEnv<'tcx>, - /// To allocate lowered patterns - pub pattern_arena: &'p TypedArena>, /// To allocate the result of `self.ctor_sub_tys()` pub dropless_arena: &'p DroplessArena, /// Lint level at the match. @@ -93,13 +87,13 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> { pub known_valid_scrutinee: bool, } -impl<'p, 'tcx> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> { +impl<'p, 'tcx: 'p> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RustcMatchCheckCtxt").finish() } } -impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { +impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> { /// Type inference occasionally gives us opaque types in places where corresponding patterns /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited /// types, we use the corresponding concrete type if possible. @@ -182,7 +176,9 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { // `field.ty()` doesn't normalize after substituting. let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.tcx.features().exhaustive_patterns && cx.is_uninhabited(ty); + let is_uninhabited = (cx.tcx.features().exhaustive_patterns + || cx.tcx.features().min_exhaustive_patterns) + && cx.is_uninhabited(ty); if is_uninhabited && (!is_visible || is_non_exhaustive) { None @@ -210,11 +206,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { /// Returns the types of the fields for a given constructor. The result must have a length of /// `ctor.arity()`. #[instrument(level = "trace", skip(self))] - pub(crate) fn ctor_sub_tys( - &self, - ctor: &Constructor<'p, 'tcx>, + pub(crate) fn ctor_sub_tys<'a>( + &'a self, + ctor: &'a Constructor<'p, 'tcx>, ty: RevealedTy<'tcx>, - ) -> &[RevealedTy<'tcx>] { + ) -> impl Iterator> + ExactSizeIterator + Captures<'a> { fn reveal_and_alloc<'a, 'tcx>( cx: &'a RustcMatchCheckCtxt<'_, 'tcx>, iter: impl Iterator>, @@ -222,7 +218,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { cx.dropless_arena.alloc_from_iter(iter.map(|ty| cx.reveal_opaque_ty(ty))) } let cx = self; - match ctor { + let slice = match ctor { Struct | Variant(_) | UnionField => match ty.kind() { ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()), ty::Adt(adt, args) => { @@ -263,7 +259,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { Or => { bug!("called `Fields::wildcards` on an `Or` ctor") } - } + }; + slice.iter().copied() } /// The number of fields for this constructor. @@ -422,7 +419,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::Alias(_, _) | ty::Param(_) @@ -457,21 +455,20 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { /// Note: the input patterns must have been lowered through /// `rustc_mir_build::thir::pattern::check_match::MatchVisitor::lower_pattern`. pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { - let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat)); let cx = self; let ty = cx.reveal_opaque_ty(pat.ty); let ctor; - let fields: &[_]; + let mut fields: Vec<_>; match &pat.kind { PatKind::AscribeUserType { subpattern, .. } | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; - fields = &[]; + fields = vec![]; } PatKind::Deref { subpattern } => { - fields = singleton(self.lower_pat(subpattern)); + fields = vec![self.lower_pat(subpattern)]; ctor = match ty.kind() { // This is a box pattern. ty::Adt(adt, ..) if adt.is_box() => Struct, @@ -483,15 +480,14 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { match ty.kind() { ty::Tuple(fs) => { ctor = Struct; - let mut wilds: SmallVec<[_; 2]> = fs + fields = fs .iter() .map(|ty| cx.reveal_opaque_ty(ty)) .map(|ty| DeconstructedPat::wildcard(ty)) .collect(); for pat in subpatterns { - wilds[pat.field.index()] = self.lower_pat(&pat.pattern); + fields[pat.field.index()] = self.lower_pat(&pat.pattern); } - fields = cx.pattern_arena.alloc_from_iter(wilds); } ty::Adt(adt, args) if adt.is_box() => { // The only legal patterns of type `Box` (outside `std`) are `_` and box @@ -513,7 +509,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { DeconstructedPat::wildcard(self.reveal_opaque_ty(args.type_at(0))) }; ctor = Struct; - fields = singleton(pat); + fields = vec![pat]; } ty::Adt(adt, _) => { ctor = match pat.kind { @@ -533,14 +529,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { ty }, ); - let mut wilds: SmallVec<[_; 2]> = - tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); + fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); for pat in subpatterns { if let Some(i) = field_id_to_id[pat.field.index()] { - wilds[i] = self.lower_pat(&pat.pattern); + fields[i] = self.lower_pat(&pat.pattern); } } - fields = cx.pattern_arena.alloc_from_iter(wilds); } _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), } @@ -552,7 +546,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { Some(b) => Bool(b), None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { @@ -568,7 +562,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Float(ty::FloatTy::F32) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { @@ -579,7 +573,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Float(ty::FloatTy::F64) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { @@ -590,7 +584,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Ref(_, t, _) if t.is_str() => { // We want a `&str` constant to behave like a `Deref` pattern, to be compatible @@ -601,16 +595,16 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { // subfields. // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); - let subpattern = DeconstructedPat::new(Str(*value), &[], ty, pat); + let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), ty, pat); ctor = Ref; - fields = singleton(subpattern) + fields = vec![subpattern] } // All constants that can be structurally matched have already been expanded // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are // opaque. _ => { ctor = Opaque(OpaqueId::new()); - fields = &[]; + fields = vec![]; } } } @@ -647,7 +641,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } _ => bug!("invalid type for range pattern: {}", ty.inner()), }; - fields = &[]; + fields = vec![]; } PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { let array_len = match ty.kind() { @@ -663,25 +657,23 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { SliceKind::FixedLen(prefix.len() + suffix.len()) }; ctor = Slice(Slice::new(array_len, kind)); - fields = cx.pattern_arena.alloc_from_iter( - prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)), - ) + fields = prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)).collect(); } PatKind::Or { .. } => { ctor = Or; let pats = expand_or_pat(pat); - fields = - cx.pattern_arena.alloc_from_iter(pats.into_iter().map(|p| self.lower_pat(p))) + fields = pats.into_iter().map(|p| self.lower_pat(p)).collect(); } PatKind::Never => { - // FIXME(never_patterns): handle `!` in exhaustiveness. This is a sane default - // in the meantime. + // A never pattern matches all the values of its type (namely none). Moreover it + // must be compatible with other constructors, since we can use `!` on a type like + // `Result` which has other constructors. Hence we lower it as a wildcard. ctor = Wildcard; - fields = &[]; + fields = vec![]; } PatKind::Error(_) => { ctor = Opaque(OpaqueId::new()); - fields = &[]; + fields = vec![]; } } DeconstructedPat::new(ctor, fields, ty, pat) @@ -766,7 +758,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p))); let kind = match pat.ctor() { Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) }, - IntRange(range) => return self.hoist_pat_range(range, pat.ty()), + IntRange(range) => return self.hoist_pat_range(range, *pat.ty()), Struct | Variant(_) | UnionField => match pat.ty().kind() { ty::Tuple(..) => PatKind::Leaf { subpatterns: subpatterns @@ -785,7 +777,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { RustcMatchCheckCtxt::variant_index_for_adt(&pat.ctor(), *adt_def); let variant = &adt_def.variant(variant_index); let subpatterns = cx - .list_variant_nonhidden_fields(pat.ty(), variant) + .list_variant_nonhidden_fields(*pat.ty(), variant) .zip(subpatterns) .map(|((field, _ty), pattern)| FieldPat { field, pattern }) .collect(); @@ -796,7 +788,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { PatKind::Leaf { subpatterns } } } - _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), pat.ty()), + _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()), }, // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to reconstruct the correct constant pattern here. However a string @@ -850,106 +842,9 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind } } - - /// Best-effort `Debug` implementation. - pub(crate) fn debug_pat( - f: &mut fmt::Formatter<'_>, - pat: &crate::pat::DeconstructedPat<'_, Self>, - ) -> fmt::Result { - let mut first = true; - let mut start_or_continue = |s| { - if first { - first = false; - "" - } else { - s - } - }; - let mut start_or_comma = || start_or_continue(", "); - - match pat.ctor() { - Struct | Variant(_) | UnionField => match pat.ty().kind() { - ty::Adt(def, _) if def.is_box() => { - // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside - // of `std`). So this branch is only reachable when the feature is enabled and - // the pattern is a box pattern. - let subpattern = pat.iter_fields().next().unwrap(); - write!(f, "box {subpattern:?}") - } - ty::Adt(..) | ty::Tuple(..) => { - let variant = - match pat.ty().kind() { - ty::Adt(adt, _) => Some(adt.variant( - RustcMatchCheckCtxt::variant_index_for_adt(pat.ctor(), *adt), - )), - ty::Tuple(_) => None, - _ => unreachable!(), - }; - - if let Some(variant) = variant { - write!(f, "{}", variant.name)?; - } - - // Without `cx`, we can't know which field corresponds to which, so we can't - // get the names of the fields. Instead we just display everything as a tuple - // struct, which should be good enough. - write!(f, "(")?; - for p in pat.iter_fields() { - write!(f, "{}", start_or_comma())?; - write!(f, "{p:?}")?; - } - write!(f, ")") - } - _ => write!(f, "_"), - }, - // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should - // be careful to detect strings here. However a string literal pattern will never - // be reported as a non-exhaustiveness witness, so we can ignore this issue. - Ref => { - let subpattern = pat.iter_fields().next().unwrap(); - write!(f, "&{:?}", subpattern) - } - Slice(slice) => { - let mut subpatterns = pat.iter_fields(); - write!(f, "[")?; - match slice.kind { - SliceKind::FixedLen(_) => { - for p in subpatterns { - write!(f, "{}{:?}", start_or_comma(), p)?; - } - } - SliceKind::VarLen(prefix_len, _) => { - for p in subpatterns.by_ref().take(prefix_len) { - write!(f, "{}{:?}", start_or_comma(), p)?; - } - write!(f, "{}", start_or_comma())?; - write!(f, "..")?; - for p in subpatterns { - write!(f, "{}{:?}", start_or_comma(), p)?; - } - } - } - write!(f, "]") - } - Bool(b) => write!(f, "{b}"), - // Best-effort, will render signed ranges incorrectly - IntRange(range) => write!(f, "{range:?}"), - F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), - F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), - Str(value) => write!(f, "{value}"), - Opaque(..) => write!(f, ""), - Or => { - for pat in pat.iter_fields() { - write!(f, "{}{:?}", start_or_continue(" | "), pat)?; - } - Ok(()) - } - Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()), - } - } } -impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { +impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { type Ty = RevealedTy<'tcx>; type Error = ErrorGuaranteed; type VariantIdx = VariantIdx; @@ -960,48 +855,60 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { fn is_exhaustive_patterns_feature_on(&self) -> bool { self.tcx.features().exhaustive_patterns } + fn is_min_exhaustive_patterns_feature_on(&self) -> bool { + self.tcx.features().min_exhaustive_patterns + } - fn ctor_arity(&self, ctor: &crate::constructor::Constructor, ty: Self::Ty) -> usize { - self.ctor_arity(ctor, ty) + fn ctor_arity(&self, ctor: &crate::constructor::Constructor, ty: &Self::Ty) -> usize { + self.ctor_arity(ctor, *ty) } - fn ctor_sub_tys( - &self, - ctor: &crate::constructor::Constructor, - ty: Self::Ty, - ) -> &[Self::Ty] { - self.ctor_sub_tys(ctor, ty) + fn ctor_sub_tys<'a>( + &'a self, + ctor: &'a crate::constructor::Constructor, + ty: &'a Self::Ty, + ) -> impl Iterator + ExactSizeIterator + Captures<'a> { + self.ctor_sub_tys(ctor, *ty) } fn ctors_for_ty( &self, - ty: Self::Ty, + ty: &Self::Ty, ) -> Result, Self::Error> { - self.ctors_for_ty(ty) + self.ctors_for_ty(*ty) } - fn debug_pat( + fn write_variant_name( f: &mut fmt::Formatter<'_>, - pat: &crate::pat::DeconstructedPat<'_, Self>, + pat: &crate::pat::DeconstructedPat, ) -> fmt::Result { - Self::debug_pat(f, pat) + if let ty::Adt(adt, _) = pat.ty().kind() { + if adt.is_box() { + write!(f, "Box")? + } else { + let variant = adt.variant(Self::variant_index_for_adt(pat.ctor(), *adt)); + write!(f, "{}", variant.name)?; + } + } + Ok(()) } - fn bug(&self, fmt: fmt::Arguments<'_>) -> ! { + + fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error { span_bug!(self.scrut_span, "{}", fmt) } fn lint_overlapping_range_endpoints( &self, - pat: &crate::pat::DeconstructedPat<'_, Self>, + pat: &crate::pat::DeconstructedPat, overlaps_on: IntRange, - overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>], + overlaps_with: &[&crate::pat::DeconstructedPat], ) { - let overlap_as_pat = self.hoist_pat_range(&overlaps_on, pat.ty()); + let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty()); let overlaps: Vec<_> = overlaps_with .iter() .map(|pat| pat.data().unwrap().span) .map(|span| errors::Overlap { range: overlap_as_pat.clone(), span }) .collect(); let pat_span = pat.data().unwrap().span; - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, self.match_lint_level, pat_span, diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index c78949942134d..33df4ebea43d7 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -548,11 +548,12 @@ //! [`ValidityConstraint::specialize`]. //! //! Having said all that, in practice we don't fully follow what's been presented in this section. -//! Under `exhaustive_patterns`, we allow omitting empty arms even in `!known_valid` places, for -//! backwards-compatibility until we have a better alternative. Without `exhaustive_patterns`, we -//! mostly treat empty types as inhabited, except specifically a non-nested `!` or empty enum. In -//! this specific case we also allow the empty match regardless of place validity, for -//! backwards-compatibility. Hopefully we can eventually deprecate this. +//! Let's call "toplevel exception" the case where the match scrutinee itself has type `!` or +//! `EmptyEnum`. First, on stable rust, we require `_` patterns for empty types in all cases apart +//! from the toplevel exception. The `exhaustive_patterns` and `min_exaustive_patterns` allow +//! omitting patterns in the cases described above. There's a final detail: in the toplevel +//! exception or with the `exhaustive_patterns` feature, we ignore place validity when checking +//! whether a pattern is required for exhaustiveness. I (Nadrieril) hope to deprecate this behavior. //! //! //! @@ -718,7 +719,7 @@ use std::fmt; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat}; -use crate::{Captures, MatchArm, MatchCtxt, TypeCx}; +use crate::{Captures, MatchArm, TypeCx}; use self::ValidityConstraint::*; @@ -729,33 +730,54 @@ pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { f() } +/// Context that provides information for usefulness checking. +pub struct UsefulnessCtxt<'a, Cx: TypeCx> { + /// The context for type information. + pub tycx: &'a Cx, +} + +impl<'a, Cx: TypeCx> Copy for UsefulnessCtxt<'a, Cx> {} +impl<'a, Cx: TypeCx> Clone for UsefulnessCtxt<'a, Cx> { + fn clone(&self) -> Self { + Self { tycx: self.tycx } + } +} + /// Context that provides information local to a place under investigation. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))] -pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> { - #[derivative(Debug = "ignore")] - pub(crate) mcx: MatchCtxt<'a, Cx>, +struct PlaceCtxt<'a, Cx: TypeCx> { + cx: &'a Cx, /// Type of the place under investigation. - pub(crate) ty: Cx::Ty, - /// Whether the place is the original scrutinee place, as opposed to a subplace of it. - pub(crate) is_scrutinee: bool, + ty: &'a Cx::Ty, } -impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { - /// A `PlaceCtxt` when code other than `is_useful` needs one. - #[cfg_attr(not(feature = "rustc"), allow(dead_code))] - pub(crate) fn new_dummy(mcx: MatchCtxt<'a, Cx>, ty: Cx::Ty) -> Self { - PlaceCtxt { mcx, ty, is_scrutinee: false } +impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {} +impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> { + fn clone(&self) -> Self { + Self { cx: self.cx, ty: self.ty } + } +} + +impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish() } +} - pub(crate) fn ctor_arity(&self, ctor: &Constructor) -> usize { - self.mcx.tycx.ctor_arity(ctor, self.ty) +impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { + fn ctor_arity(&self, ctor: &Constructor) -> usize { + self.cx.ctor_arity(ctor, self.ty) + } + fn ctor_sub_tys( + &'a self, + ctor: &'a Constructor, + ) -> impl Iterator + ExactSizeIterator + Captures<'a> { + self.cx.ctor_sub_tys(ctor, self.ty) } - pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor) -> &[Cx::Ty] { - self.mcx.tycx.ctor_sub_tys(ctor, self.ty) + fn ctors_for_ty(&self) -> Result, Cx::Error> { + self.cx.ctors_for_ty(self.ty) } - pub(crate) fn ctors_for_ty(&self) -> Result, Cx::Error> { - self.mcx.tycx.ctors_for_ty(self.ty) + fn wild_from_ctor(&self, ctor: Constructor) -> WitnessPat { + WitnessPat::wild_from_ctor(self.cx, ctor, self.ty.clone()) } } @@ -768,9 +790,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { pub enum ValidityConstraint { ValidOnly, MaybeInvalid, - /// Option for backwards compatibility: the place is not known to be valid but we allow omitting - /// `useful && !reachable` arms anyway. - MaybeInvalidButAllowOmittingArms, } impl ValidityConstraint { @@ -778,20 +797,9 @@ impl ValidityConstraint { if is_valid_only { ValidOnly } else { MaybeInvalid } } - fn allow_omitting_side_effecting_arms(self) -> Self { - match self { - MaybeInvalid | MaybeInvalidButAllowOmittingArms => MaybeInvalidButAllowOmittingArms, - // There are no side-effecting empty arms here, nothing to do. - ValidOnly => ValidOnly, - } - } - fn is_known_valid(self) -> bool { matches!(self, ValidOnly) } - fn allows_omitting_empty_arms(self) -> bool { - matches!(self, ValidOnly | MaybeInvalidButAllowOmittingArms) - } /// If the place has validity given by `self` and we read that the value at the place has /// constructor `ctor`, this computes what we can assume about the validity of the constructor @@ -814,7 +822,7 @@ impl fmt::Display for ValidityConstraint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { ValidOnly => "✓", - MaybeInvalid | MaybeInvalidButAllowOmittingArms => "?", + MaybeInvalid => "?", }; write!(f, "{s}") } @@ -824,8 +832,6 @@ impl fmt::Display for ValidityConstraint { // The three lifetimes are: // - 'p coming from the input // - Cx global compilation context -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""))] struct PatStack<'p, Cx: TypeCx> { // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. pats: SmallVec<[PatOrWild<'p, Cx>; 2]>, @@ -835,8 +841,14 @@ struct PatStack<'p, Cx: TypeCx> { relevant: bool, } +impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> { + fn clone(&self) -> Self { + Self { pats: self.pats.clone(), relevant: self.relevant } + } +} + impl<'p, Cx: TypeCx> PatStack<'p, Cx> { - fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self { + fn from_pattern(pat: &'p DeconstructedPat) -> Self { PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true } } @@ -1039,8 +1051,8 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { matrix } - fn head_ty(&self) -> Option { - self.place_ty.first().copied() + fn head_ty(&self) -> Option<&Cx::Ty> { + self.place_ty.first() } fn column_count(&self) -> usize { self.place_ty.len() @@ -1070,11 +1082,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { pcx: &PlaceCtxt<'_, Cx>, ctor: &Constructor, ctor_is_relevant: bool, - ) -> Matrix<'p, Cx> { + ) -> Result, Cx::Error> { let ctor_sub_tys = pcx.ctor_sub_tys(ctor); let arity = ctor_sub_tys.len(); - let specialized_place_ty = - ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).copied().collect(); + let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect(); let ctor_sub_validity = self.place_validity[0].specialize(ctor); let specialized_place_validity = std::iter::repeat(ctor_sub_validity) .take(arity) @@ -1087,12 +1098,12 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant, }; for (i, row) in self.rows().enumerate() { - if ctor.is_covered_by(pcx, row.head().ctor()) { + if ctor.is_covered_by(pcx.cx, row.head().ctor())? { let new_row = row.pop_head_constructor(ctor, arity, ctor_is_relevant, i); matrix.expand_and_push(new_row); } } - matrix + Ok(matrix) } } @@ -1196,10 +1207,15 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> { /// The final `Pair(Some(_), true)` is then the resulting witness. /// /// See the top of the file for more detailed explanations and examples. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] +#[derive(Debug)] struct WitnessStack(Vec>); +impl Clone for WitnessStack { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + impl WitnessStack { /// Asserts that the witness contains a single pattern, and returns it. fn single_pattern(self) -> WitnessPat { @@ -1228,9 +1244,9 @@ impl WitnessStack { /// ``` fn apply_constructor(&mut self, pcx: &PlaceCtxt<'_, Cx>, ctor: &Constructor) { let len = self.0.len(); - let arity = ctor.arity(pcx); + let arity = pcx.ctor_arity(ctor); let fields = self.0.drain((len - arity)..).rev().collect(); - let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty); + let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty.clone()); self.0.push(pat); } } @@ -1244,18 +1260,23 @@ impl WitnessStack { /// /// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single /// column, which contains the patterns that are missing for the match to be exhaustive. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] +#[derive(Debug)] struct WitnessMatrix(Vec>); +impl Clone for WitnessMatrix { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + impl WitnessMatrix { /// New matrix with no witnesses. fn empty() -> Self { - WitnessMatrix(vec![]) + WitnessMatrix(Vec::new()) } /// New matrix with one `()` witness, i.e. with no columns. fn unit_witness() -> Self { - WitnessMatrix(vec![WitnessStack(vec![])]) + WitnessMatrix(vec![WitnessStack(Vec::new())]) } /// Whether this has any witnesses. @@ -1293,20 +1314,20 @@ impl WitnessMatrix { *self = Self::empty(); } else if !report_individual_missing_ctors { // Report `_` as missing. - let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard); + let pat = pcx.wild_from_ctor(Constructor::Wildcard); self.push_pattern(pat); } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { // We need to report a `_` anyway, so listing other constructors would be redundant. // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked // up by diagnostics to add a note about why `_` is required here. - let pat = WitnessPat::wild_from_ctor(pcx, Constructor::NonExhaustive); + let pat = pcx.wild_from_ctor(Constructor::NonExhaustive); self.push_pattern(pat); } else { // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately // filled with wildcards. let mut ret = Self::empty(); for ctor in missing_ctors { - let pat = WitnessPat::wild_from_ctor(pcx, ctor.clone()); + let pat = pcx.wild_from_ctor(ctor.clone()); // Clone `self` and add `c(_, _, _)` to each of its witnesses. let mut wit_matrix = self.clone(); wit_matrix.push_pattern(pat); @@ -1340,7 +1361,7 @@ impl WitnessMatrix { /// We can however get false negatives because exhaustiveness does not explore all cases. See the /// section on relevancy at the top of the file. fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( - mcx: MatchCtxt<'_, Cx>, + mcx: UsefulnessCtxt<'_, Cx>, overlap_range: IntRange, matrix: &Matrix<'p, Cx>, specialized_matrix: &Matrix<'p, Cx>, @@ -1413,7 +1434,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( /// This is all explained at the top of the file. #[instrument(level = "debug", skip(mcx, is_top_level), ret)] fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( - mcx: MatchCtxt<'a, Cx>, + mcx: UsefulnessCtxt<'a, Cx>, matrix: &mut Matrix<'p, Cx>, is_top_level: bool, ) -> Result, Cx::Error> { @@ -1426,7 +1447,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( return Ok(WitnessMatrix::empty()); } - let Some(ty) = matrix.head_ty() else { + let Some(ty) = matrix.head_ty().cloned() else { // The base case: there are no columns in the matrix. We are morally pattern-matching on (). // A row is useful iff it has no (unguarded) rows above it. let mut useful = true; // Whether the next row is useful. @@ -1447,41 +1468,51 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( }; debug!("ty: {ty:?}"); - let pcx = &PlaceCtxt { mcx, ty, is_scrutinee: is_top_level }; + let pcx = &PlaceCtxt { cx: mcx.tycx, ty: &ty }; + let ctors_for_ty = pcx.ctors_for_ty()?; // Whether the place/column we are inspecting is known to contain valid data. let place_validity = matrix.place_validity[0]; - // For backwards compability we allow omitting some empty arms that we ideally shouldn't. - let place_validity = place_validity.allow_omitting_side_effecting_arms(); + // We treat match scrutinees of type `!` or `EmptyEnum` differently. + let is_toplevel_exception = + is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors); + // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if + // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). + let empty_arms_are_unreachable = place_validity.is_known_valid() + && (is_toplevel_exception + || mcx.tycx.is_exhaustive_patterns_feature_on() + || mcx.tycx.is_min_exhaustive_patterns_feature_on()); + // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the + // toplevel exception and `exhaustive_patterns` cases for backwards compatibility. + let can_omit_empty_arms = empty_arms_are_unreachable + || is_toplevel_exception + || mcx.tycx.is_exhaustive_patterns_feature_on(); // Analyze the constructors present in this column. let ctors = matrix.heads().map(|p| p.ctor()); - let ctors_for_ty = pcx.ctors_for_ty()?; - let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics. - let split_set = ctors_for_ty.split(pcx, ctors); + let mut split_set = ctors_for_ty.split(ctors); let all_missing = split_set.present.is_empty(); - // Build the set of constructors we will specialize with. It must cover the whole type. + // We need to iterate over a full set of constructors, so we add `Missing` to represent the + // missing ones. This is explained under "Constructor Splitting" at the top of this file. let mut split_ctors = split_set.present; - if !split_set.missing.is_empty() { - // We need to iterate over a full set of constructors, so we add `Missing` to represent the - // missing ones. This is explained under "Constructor Splitting" at the top of this file. - split_ctors.push(Constructor::Missing); - } else if !split_set.missing_empty.is_empty() && !place_validity.is_known_valid() { - // The missing empty constructors are reachable if the place can contain invalid data. + if !(split_set.missing.is_empty() + && (split_set.missing_empty.is_empty() || empty_arms_are_unreachable)) + { split_ctors.push(Constructor::Missing); } // Decide what constructors to report. + let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); let always_report_all = is_top_level && !is_integers; // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". let report_individual_missing_ctors = always_report_all || !all_missing; // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() => - // split_ctors.contains(Missing)`. The converse usually holds except in the - // `MaybeInvalidButAllowOmittingArms` backwards-compatibility case. + // split_ctors.contains(Missing)`. The converse usually holds except when + // `!place_validity.is_known_valid()`. let mut missing_ctors = split_set.missing; - if !place_validity.allows_omitting_empty_arms() { - missing_ctors.extend(split_set.missing_empty); + if !can_omit_empty_arms { + missing_ctors.append(&mut split_set.missing_empty); } let mut ret = WitnessMatrix::empty(); @@ -1492,7 +1523,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // strictly fewer rows. In that case we can sometimes skip it. See the top of the file for // details. let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty(); - let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant); + let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?; let mut witnesses = ensure_sufficient_stack(|| { compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false) })?; @@ -1544,7 +1575,7 @@ pub enum Usefulness<'p, Cx: TypeCx> { /// The arm is useful. This additionally carries a set of or-pattern branches that have been /// found to be redundant despite the overall arm being useful. Used only in the presence of /// or-patterns, otherwise it stays empty. - Useful(Vec<&'p DeconstructedPat<'p, Cx>>), + Useful(Vec<&'p DeconstructedPat>), /// The arm is redundant and can be removed without changing the behavior of the match /// expression. Redundant, @@ -1560,13 +1591,14 @@ pub struct UsefulnessReport<'p, Cx: TypeCx> { } /// Computes whether a match is exhaustive and which of its arms are useful. -#[instrument(skip(cx, arms), level = "debug")] +#[instrument(skip(tycx, arms), level = "debug")] pub fn compute_match_usefulness<'p, Cx: TypeCx>( - cx: MatchCtxt<'_, Cx>, + tycx: &Cx, arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Result, Cx::Error> { + let cx = UsefulnessCtxt { tycx }; let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?; diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index b1242f82f4fec..01c6d18c0e1be 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -1,9 +1,9 @@ -use rustc_errors::DiagnosticArgFromDisplay; +use rustc_errors::{codes::*, DiagnosticArgFromDisplay}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(privacy_field_is_private, code = "E0451")] +#[diag(privacy_field_is_private, code = E0451)] pub struct FieldIsPrivate { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ pub struct UnnamedItemIsPrivate { } #[derive(Diagnostic)] -#[diag(privacy_in_public_interface, code = "E0446")] +#[diag(privacy_in_public_interface, code = E0446)] pub struct InPublicInterface<'a> { #[primary_span] #[label] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 519303fc3aa96..a37d8822480af 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -3,10 +3,8 @@ #![feature(rustdoc_internals)] #![allow(internal_features)] #![feature(associated_type_defaults)] -#![feature(rustc_private)] #![feature(try_blocks)] #![feature(let_chains)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -24,21 +22,20 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, PatKind}; -use rustc_middle::bug; -use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; use rustc_middle::query::Providers; use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, Const, GenericParamDefKind}; use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; +use std::fmt; use std::marker::PhantomData; use std::ops::ControlFlow; -use std::{fmt, mem}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, @@ -185,6 +182,7 @@ where | ty::Foreign(def_id) | ty::FnDef(def_id, ..) | ty::Closure(def_id, ..) + | ty::CoroutineClosure(def_id, ..) | ty::Coroutine(def_id, ..) => { self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; if V::SHALLOW { @@ -935,7 +933,6 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { struct NamePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, - current_item: LocalDefId, } impl<'tcx> NamePrivacyVisitor<'tcx> { @@ -951,6 +948,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // Checks that a field in a struct constructor (expression or pattern) is accessible. fn check_field( &mut self, + hir_id: hir::HirId, // ID of the field use use_ctxt: Span, // syntax context of the field name at the use site span: Span, // span of the field pattern, e.g., `x: 0` def: ty::AdtDef<'tcx>, // definition of the struct or enum @@ -963,7 +961,6 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // definition of the field let ident = Ident::new(kw::Empty, use_ctxt); - let hir_id = self.tcx.local_def_id_to_hir_id(self.current_item); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; if !field.vis.is_accessible_from(def_id, self.tcx) { self.tcx.dcx().emit_err(FieldIsPrivate { @@ -982,33 +979,13 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { - type NestedFilter = nested_filter::All; - - /// We want to visit items in the context of their containing - /// module and so forth, so supply a crate for doing a deep walk. - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { - // Don't visit nested modules, since we run a separate visitor walk - // for each module in `effective_visibilities` - } - - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body_id: hir::BodyId) { let old_maybe_typeck_results = - self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); - let body = self.tcx.hir().body(body); - self.visit_body(body); + self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id)); + self.visit_body(self.tcx.hir().body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); - intravisit::walk_item(self, item); - self.current_item = orig_current_item; - } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); @@ -1022,17 +999,17 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let field = fields .iter() .find(|f| self.typeck_results().field_index(f.hir_id) == vf_index); - let (use_ctxt, span) = match field { - Some(field) => (field.ident.span, field.span), - None => (base.span, base.span), + let (hir_id, use_ctxt, span) = match field { + Some(field) => (field.hir_id, field.ident.span, field.span), + None => (base.hir_id, base.span, base.span), }; - self.check_field(use_ctxt, span, adt, variant_field, true); + self.check_field(hir_id, use_ctxt, span, adt, variant_field, true); } } else { for field in fields { - let use_ctxt = field.ident.span; + let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); let index = self.typeck_results().field_index(field.hir_id); - self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false); + self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false); } } } @@ -1046,9 +1023,9 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); for field in fields { - let use_ctxt = field.ident.span; + let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); let index = self.typeck_results().field_index(field.hir_id); - self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false); + self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false); } } @@ -1064,29 +1041,22 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { struct TypePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, + module_def_id: LocalModDefId, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, - current_item: LocalDefId, span: Span, } impl<'tcx> TypePrivacyVisitor<'tcx> { - /// Gets the type-checking results for the current body. - /// As this will ICE if called outside bodies, only call when working with - /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies). - #[track_caller] - fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> { - self.maybe_typeck_results - .expect("`TypePrivacyVisitor::typeck_results` called outside of body") - } - fn item_is_accessible(&self, did: DefId) -> bool { - self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx) + self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx) } // Take node-id of an expression or pattern and check its type for privacy. fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool { self.span = span; - let typeck_results = self.typeck_results(); + let typeck_results = self + .maybe_typeck_results + .unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body")); let result: ControlFlow<()> = try { self.visit(typeck_results.node_type(id))?; self.visit(typeck_results.node_args(id))?; @@ -1107,35 +1077,13 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { - type NestedFilter = nested_filter::All; - - /// We want to visit items in the context of their containing - /// module and so forth, so supply a crate for doing a deep walk. - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { - // Don't visit nested modules, since we run a separate visitor walk - // for each module in `effective_visibilities` - } - - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body_id: hir::BodyId) { let old_maybe_typeck_results = - self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); - let body = self.tcx.hir().body(body); - self.visit_body(body); + self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id)); + self.visit_body(self.tcx.hir().body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } - fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) { - match generic_arg { - hir::GenericArg::Type(t) => self.visit_ty(t), - hir::GenericArg::Infer(inf) => self.visit_infer(inf), - hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} - } - } - fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { self.span = hir_ty.span; if let Some(typeck_results) = self.maybe_typeck_results { @@ -1163,19 +1111,19 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { return; } } else { - // We don't do anything for const infers here. + // FIXME: check types of const infers here. } } else { - bug!("visit_infer without typeck_results"); + span_bug!(self.span, "`hir::InferArg` outside of a body"); } intravisit::walk_inf(self, inf); } fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) { self.span = trait_ref.path.span; - if self.maybe_typeck_results.is_none() { - // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE. - // The traits' privacy in bodies is already checked as a part of trait object types. + if self.maybe_typeck_results.is_some() { + // Privacy of traits in bodies is checked as a part of trait object types. + } else { let bounds = rustc_hir_analysis::hir_trait_to_predicates( self.tcx, trait_ref, @@ -1223,7 +1171,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { hir::ExprKind::MethodCall(segment, ..) => { // Method calls have to be checked specially. self.span = segment.ident.span; - if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) { + let typeck_results = self + .maybe_typeck_results + .unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body")); + if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() { return; } @@ -1251,9 +1202,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { Res::Def(kind, def_id) => Some((kind, def_id)), _ => None, }, - hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self - .maybe_typeck_results - .and_then(|typeck_results| typeck_results.type_dependent_def(id)), + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.type_dependent_def(id), + // FIXME: Check type-relative associated types in signatures. + None => None, + } + } }; let def = def.filter(|(kind, _)| { matches!( @@ -1307,15 +1262,6 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { intravisit::walk_local(self, local); } - - // Check types in item interfaces. - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); - let old_maybe_typeck_results = self.maybe_typeck_results.take(); - intravisit::walk_item(self, item); - self.maybe_typeck_results = old_maybe_typeck_results; - self.current_item = orig_current_item; - } } impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { @@ -1399,7 +1345,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { if self.leaks_private_dep(def_id) { - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, self.tcx.local_def_id_to_hir_id(self.item_def_id), self.tcx.def_span(self.item_def_id.to_def_id()), @@ -1456,7 +1402,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } else { lint::builtin::PRIVATE_BOUNDS }; - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( lint, self.tcx.local_def_id_to_hir_id(self.item_def_id), span, @@ -1543,7 +1489,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> { if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis { let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let span = self.tcx.def_span(def_id.to_def_id()); - self.tcx.emit_spanned_lint( + self.tcx.emit_node_span_lint( lint::builtin::UNNAMEABLE_TYPES, hir_id, span, @@ -1774,24 +1720,14 @@ pub fn provide(providers: &mut Providers) { fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { // Check privacy of names not checked in previous compilation stages. - let mut visitor = NamePrivacyVisitor { - tcx, - maybe_typeck_results: None, - current_item: module_def_id.to_local_def_id(), - }; - let (module, span, hir_id) = tcx.hir().get_module(module_def_id); - - intravisit::walk_mod(&mut visitor, module, hir_id); + let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None }; + tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor); // Check privacy of explicitly written types and traits as well as // inferred types of expressions and patterns. - let mut visitor = TypePrivacyVisitor { - tcx, - maybe_typeck_results: None, - current_item: module_def_id.to_local_def_id(), - span, - }; - intravisit::walk_mod(&mut visitor, module, hir_id); + let span = tcx.def_span(module_def_id); + let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span }; + tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor); } fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index b5e8ac4018df5..818a67a7debf6 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -4,9 +4,7 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(min_specialization)] -#![feature(never_type)] #![feature(rustc_attrs)] -#![recursion_limit = "256"] #![allow(rustc::potential_query_instability, unused_parens)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 1f09de0ed70c7..2faa4876798e0 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -818,7 +818,7 @@ impl DepGraphData { None => {} } - if let None = qcx.dep_context().sess().dcx().has_errors_or_span_delayed_bugs() { + if let None = qcx.dep_context().sess().dcx().has_errors_or_lint_errors_or_delayed_bugs() { panic!("try_mark_previous_green() - Forcing the DepNode should have set its color") } @@ -891,7 +891,7 @@ impl DepGraphData { insertion for {dep_node:?}" ); - if !side_effects.is_empty() { + if side_effects.maybe_any() { qcx.dep_context().dep_graph().with_query_deserialization(|| { self.emit_side_effects(qcx, dep_node_index, side_effects) }); diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 5829e17ec1625..9db6fac8036a9 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -1,3 +1,4 @@ +use rustc_errors::codes::*; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::Limit; use rustc_span::{Span, Symbol}; @@ -45,7 +46,7 @@ pub struct CycleUsage { } #[derive(Diagnostic)] -#[diag(query_system_cycle, code = "E0391")] +#[diag(query_system_cycle, code = E0391)] pub struct Cycle { #[primary_span] pub span: Span, diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index eecbf86c173bb..02b3c740b631b 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -93,10 +93,13 @@ pub struct QuerySideEffects { } impl QuerySideEffects { + /// Returns true if there might be side effects. #[inline] - pub fn is_empty(&self) -> bool { + pub fn maybe_any(&self) -> bool { let QuerySideEffects { diagnostics } = self; - diagnostics.is_empty() + // Use `has_capacity` so that the destructor for `self.diagnostics` can be skipped + // if `maybe_any` is known to be false. + diagnostics.has_capacity() } pub fn append(&mut self, other: QuerySideEffects) { let QuerySideEffects { diagnostics } = self; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3bb2cc5634fe8..9158ba00901c6 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -538,10 +538,9 @@ where prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - let diagnostics = diagnostics.into_inner(); - let side_effects = QuerySideEffects { diagnostics }; + let side_effects = QuerySideEffects { diagnostics: diagnostics.into_inner() }; - if std::intrinsics::unlikely(!side_effects.is_empty()) { + if std::intrinsics::unlikely(side_effects.maybe_any()) { if query.anon() { qcx.store_side_effects_for_anon_node(dep_node_index, side_effects); } else { diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index a1a353ce0574e..b6ae54010c242 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -pulldown-cmark = { version = "0.9.3", default-features = false } +pulldown-cmark = { version = "0.9.6", default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index c8ec10cad17c4..0747685c35c46 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -118,17 +118,27 @@ resolve_forward_declared_generic_param = .label = defaulted generic parameters cannot be forward declared resolve_generic_params_from_outer_item = - can't use generic parameters from outer item - .label = use of generic parameter from outer item + can't use {$is_self -> + [true] `Self` + *[false] generic parameters + } from outer item + .label = use of {$is_self -> + [true] `Self` + *[false] generic parameter + } from outer item .refer_to_type_directly = refer to the type directly here instead .suggestion = try introducing a local generic parameter here +resolve_generic_params_from_outer_item_const = a `const` is a separate item from the item that contains it + resolve_generic_params_from_outer_item_const_param = const parameter from outer item resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl` resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here +resolve_generic_params_from_outer_item_static = a `static` is a separate item from the item that contains it + resolve_generic_params_from_outer_item_ty_param = type parameter from outer item @@ -289,6 +299,12 @@ resolve_underscore_lifetime_name_cannot_be_used_here = `'_` cannot be used here .note = `'_` is a reserved lifetime name +resolve_unexpected_res_change_ty_to_const_param_sugg = + you might have meant to write a const parameter here + +resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = + if you meant to collect the rest of the slice in `{$ident}`, use the at operator + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a4e2f9e3ff8cd..7eb7c8c2bca22 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -19,7 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_code_err, Applicability}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability}; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; @@ -1029,9 +1029,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - let macro_use_import = |this: &Self, span| { + let macro_use_import = |this: &Self, span, warn_private| { this.r.arenas.alloc_import(ImportData { - kind: ImportKind::MacroUse, + kind: ImportKind::MacroUse { warn_private }, root_id: item.id, parent_scope: this.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), @@ -1048,11 +1048,25 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let allow_shadowing = self.parent_scope.expansion == LocalExpnId::ROOT; if let Some(span) = import_all { - let import = macro_use_import(self, span); + let import = macro_use_import(self, span, false); self.r.potentially_unused_imports.push(import); module.for_each_child(self, |this, ident, ns, binding| { if ns == MacroNS { - let imported_binding = this.r.import(binding, import); + let imported_binding = + if this.r.is_accessible_from(binding.vis, this.parent_scope.module) { + this.r.import(binding, import) + } else if !this.r.is_builtin_macro(binding.res()) + && !this.r.macro_use_prelude.contains_key(&ident.name) + { + // - `!r.is_builtin_macro(res)` excluding the built-in macros such as `Debug` or `Hash`. + // - `!r.macro_use_prelude.contains_key(name)` excluding macros defined in other extern + // crates such as `std`. + // FIXME: This branch should eventually be removed. + let import = macro_use_import(this, span, true); + this.r.import(binding, import) + } else { + return; + }; this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing); } }); @@ -1065,7 +1079,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { &self.parent_scope, ); if let Ok(binding) = result { - let import = macro_use_import(self, ident.span); + let import = macro_use_import(self, ident.span, false); self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); self.add_macro_use_binding( diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 0e43a35ce7389..fc72d76c3a797 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -290,7 +290,7 @@ impl Resolver<'_, '_> { || import.expect_vis().is_public() || import.span.is_dummy() => { - if let ImportKind::MacroUse = import.kind { + if let ImportKind::MacroUse { .. } = import.kind { if !import.span.is_dummy() { self.lint_buffer.buffer_lint( MACRO_USE_EXTERN_CRATE, @@ -315,7 +315,7 @@ impl Resolver<'_, '_> { maybe_unused_extern_crates.insert(id, import.span); } } - ImportKind::MacroUse => { + ImportKind::MacroUse { .. } => { let msg = "unused `#[macro_use]` import"; self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b77102c085c59..42ace9bb22fa9 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -289,12 +289,18 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { // we must create two defs. let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span); match closure.coroutine_kind { - Some(coroutine_kind) => self.create_def( - coroutine_kind.closure_id(), - kw::Empty, - DefKind::Closure, - expr.span, - ), + Some(coroutine_kind) => { + self.with_parent(closure_def, |this| { + let coroutine_def = this.create_def( + coroutine_kind.closure_id(), + kw::Empty, + DefKind::Closure, + expr.span, + ); + this.with_parent(coroutine_def, |this| visit::walk_expr(this, expr)); + }); + return; + } None => closure_def, } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4a0c522b6ec5d..d91a865e38aba 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, report_ambiguity_error, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, - DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, + codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, DiagCtxt, + Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -285,7 +285,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { use NameBindingKind::Import; let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| { !binding.span.is_dummy() - && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport) + && !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport) }; let import = match (&new_binding.kind, &old_binding.kind) { // If there are two imports where one or both have attributes then prefer removing the @@ -561,13 +561,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolution_error: ResolutionError<'a>, ) -> DiagnosticBuilder<'_> { match resolution_error { - ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => { + ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => { use errs::GenericParamsFromOuterItemLabel as Label; + let static_or_const = match def_kind { + DefKind::Static(_) => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static), + DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const), + _ => None, + }; + let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); let mut err = errs::GenericParamsFromOuterItem { span, label: None, refer_to_type_directly: None, sugg: None, + static_or_const, + is_self, }; let sm = self.tcx.sess.source_map(); @@ -1819,9 +1827,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { next_ident = source; Some(binding) } - ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => { - Some(binding) - } + ImportKind::Glob { .. } + | ImportKind::MacroUse { .. } + | ImportKind::MacroExport => Some(binding), ImportKind::ExternCrate { .. } => None, }, _ => None, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 821b1e946f31c..adc4cd911a79e 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,3 +1,4 @@ +use rustc_errors::{codes::*, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ symbol::{Ident, Symbol}, @@ -7,16 +8,16 @@ use rustc_span::{ use crate::{late::PatternSource, Res}; #[derive(Diagnostic)] -#[diag(resolve_parent_module_reset_for_binding, code = "E0637")] +#[diag(resolve_parent_module_reset_for_binding, code = E0637)] pub(crate) struct ParentModuleResetForBinding; #[derive(Diagnostic)] -#[diag(resolve_ampersand_used_without_explicit_lifetime_name, code = "E0637")] +#[diag(resolve_ampersand_used_without_explicit_lifetime_name, code = E0637)] #[note] pub(crate) struct AmpersandUsedWithoutExplicitLifetimeName(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_underscore_lifetime_name_cannot_be_used_here, code = "E0637")] +#[diag(resolve_underscore_lifetime_name_cannot_be_used_here, code = E0637)] #[note] pub(crate) struct UnderscoreLifetimeNameCannotBeUsedHere(#[primary_span] pub(crate) Span); @@ -33,7 +34,7 @@ pub(crate) struct CrateRootNamesMustBeNamedExplicitly(#[primary_span] pub(crate) pub(crate) struct ResolutionError(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_generic_params_from_outer_item, code = "E0401")] +#[diag(resolve_generic_params_from_outer_item, code = E0401)] pub(crate) struct GenericParamsFromOuterItem { #[primary_span] #[label] @@ -44,6 +45,17 @@ pub(crate) struct GenericParamsFromOuterItem { pub(crate) refer_to_type_directly: Option, #[subdiagnostic] pub(crate) sugg: Option, + #[subdiagnostic] + pub(crate) static_or_const: Option, + pub(crate) is_self: bool, +} + +#[derive(Subdiagnostic)] +pub(crate) enum GenericParamsFromOuterItemStaticOrConst { + #[note(resolve_generic_params_from_outer_item_static)] + Static, + #[note(resolve_generic_params_from_outer_item_const)] + Const, } #[derive(Subdiagnostic)] @@ -67,7 +79,7 @@ pub(crate) struct GenericParamsFromOuterItemSugg { } #[derive(Diagnostic)] -#[diag(resolve_name_is_already_used_as_generic_parameter, code = "E0403")] +#[diag(resolve_name_is_already_used_as_generic_parameter, code = E0403)] pub(crate) struct NameAlreadyUsedInParameterList { #[primary_span] #[label] @@ -78,7 +90,7 @@ pub(crate) struct NameAlreadyUsedInParameterList { } #[derive(Diagnostic)] -#[diag(resolve_method_not_member_of_trait, code = "E0407")] +#[diag(resolve_method_not_member_of_trait, code = E0407)] pub(crate) struct MethodNotMemberOfTrait { #[primary_span] #[label] @@ -102,7 +114,7 @@ pub(crate) struct AssociatedFnWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_type_not_member_of_trait, code = "E0437")] +#[diag(resolve_type_not_member_of_trait, code = E0437)] pub(crate) struct TypeNotMemberOfTrait { #[primary_span] #[label] @@ -126,7 +138,7 @@ pub(crate) struct AssociatedTypeWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_const_not_member_of_trait, code = "E0438")] +#[diag(resolve_const_not_member_of_trait, code = E0438)] pub(crate) struct ConstNotMemberOfTrait { #[primary_span] #[label] @@ -150,7 +162,7 @@ pub(crate) struct AssociatedConstWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_variable_bound_with_different_mode, code = "E0409")] +#[diag(resolve_variable_bound_with_different_mode, code = E0409)] pub(crate) struct VariableBoundWithDifferentMode { #[primary_span] #[label] @@ -161,7 +173,7 @@ pub(crate) struct VariableBoundWithDifferentMode { } #[derive(Diagnostic)] -#[diag(resolve_ident_bound_more_than_once_in_parameter_list, code = "E0415")] +#[diag(resolve_ident_bound_more_than_once_in_parameter_list, code = E0415)] pub(crate) struct IdentifierBoundMoreThanOnceInParameterList { #[primary_span] #[label] @@ -170,7 +182,7 @@ pub(crate) struct IdentifierBoundMoreThanOnceInParameterList { } #[derive(Diagnostic)] -#[diag(resolve_ident_bound_more_than_once_in_same_pattern, code = "E0416")] +#[diag(resolve_ident_bound_more_than_once_in_same_pattern, code = E0416)] pub(crate) struct IdentifierBoundMoreThanOnceInSamePattern { #[primary_span] #[label] @@ -179,7 +191,7 @@ pub(crate) struct IdentifierBoundMoreThanOnceInSamePattern { } #[derive(Diagnostic)] -#[diag(resolve_undeclared_label, code = "E0426")] +#[diag(resolve_undeclared_label, code = E0426)] pub(crate) struct UndeclaredLabel { #[primary_span] #[label] @@ -217,7 +229,7 @@ pub(crate) struct UnreachableLabelWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_self_import_can_only_appear_once_in_the_list, code = "E0430")] +#[diag(resolve_self_import_can_only_appear_once_in_the_list, code = E0430)] pub(crate) struct SelfImportCanOnlyAppearOnceInTheList { #[primary_span] #[label] @@ -225,7 +237,7 @@ pub(crate) struct SelfImportCanOnlyAppearOnceInTheList { } #[derive(Diagnostic)] -#[diag(resolve_self_import_only_in_import_list_with_non_empty_prefix, code = "E0431")] +#[diag(resolve_self_import_only_in_import_list_with_non_empty_prefix, code = E0431)] pub(crate) struct SelfImportOnlyInImportListWithNonEmptyPrefix { #[primary_span] #[label] @@ -233,7 +245,7 @@ pub(crate) struct SelfImportOnlyInImportListWithNonEmptyPrefix { } #[derive(Diagnostic)] -#[diag(resolve_cannot_capture_dynamic_environment_in_fn_item, code = "E0434")] +#[diag(resolve_cannot_capture_dynamic_environment_in_fn_item, code = E0434)] #[help] pub(crate) struct CannotCaptureDynamicEnvironmentInFnItem { #[primary_span] @@ -241,7 +253,7 @@ pub(crate) struct CannotCaptureDynamicEnvironmentInFnItem { } #[derive(Diagnostic)] -#[diag(resolve_attempt_to_use_non_constant_value_in_constant, code = "E0435")] +#[diag(resolve_attempt_to_use_non_constant_value_in_constant, code = E0435)] pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { #[primary_span] pub(crate) span: Span, @@ -283,7 +295,7 @@ pub(crate) struct AttemptToUseNonConstantValueInConstantWithoutSuggestion<'a> { } #[derive(Diagnostic)] -#[diag(resolve_self_imports_only_allowed_within, code = "E0429")] +#[diag(resolve_self_imports_only_allowed_within, code = E0429)] pub(crate) struct SelfImportsOnlyAllowedWithin { #[primary_span] pub(crate) span: Span, @@ -317,7 +329,7 @@ pub(crate) struct SelfImportsOnlyAllowedWithinMultipartSuggestion { } #[derive(Diagnostic)] -#[diag(resolve_binding_shadows_something_unacceptable, code = "E0530")] +#[diag(resolve_binding_shadows_something_unacceptable, code = E0530)] pub(crate) struct BindingShadowsSomethingUnacceptable<'a> { #[primary_span] #[label] @@ -346,7 +358,7 @@ pub(crate) struct BindingShadowsSomethingUnacceptableSuggestion { } #[derive(Diagnostic)] -#[diag(resolve_forward_declared_generic_param, code = "E0128")] +#[diag(resolve_forward_declared_generic_param, code = E0128)] pub(crate) struct ForwardDeclaredGenericParam { #[primary_span] #[label] @@ -354,7 +366,7 @@ pub(crate) struct ForwardDeclaredGenericParam { } #[derive(Diagnostic)] -#[diag(resolve_param_in_ty_of_const_param, code = "E0770")] +#[diag(resolve_param_in_ty_of_const_param, code = E0770)] pub(crate) struct ParamInTyOfConstParam { #[primary_span] #[label] @@ -376,7 +388,7 @@ pub(crate) enum ParamKindInTyOfConstParam { } #[derive(Diagnostic)] -#[diag(resolve_self_in_generic_param_default, code = "E0735")] +#[diag(resolve_self_in_generic_param_default, code = E0735)] pub(crate) struct SelfInGenericParamDefault { #[primary_span] #[label] @@ -412,7 +424,7 @@ pub(crate) enum ParamKindInNonTrivialAnonConst { } #[derive(Diagnostic)] -#[diag(resolve_unreachable_label, code = "E0767")] +#[diag(resolve_unreachable_label, code = E0767)] #[note] pub(crate) struct UnreachableLabel { #[primary_span] @@ -456,7 +468,7 @@ pub(crate) struct UnreachableLabelSubLabelUnreachable { } #[derive(Diagnostic)] -#[diag(resolve_trait_impl_mismatch, code = "{code}")] +#[diag(resolve_trait_impl_mismatch)] pub(crate) struct TraitImplMismatch { #[primary_span] #[label] @@ -466,7 +478,6 @@ pub(crate) struct TraitImplMismatch { #[label(resolve_label_trait_item)] pub(crate) trait_item_span: Span, pub(crate) trait_path: String, - pub(crate) code: String, } #[derive(Diagnostic)] @@ -496,7 +507,7 @@ pub(crate) struct BindingInNeverPattern { } #[derive(Diagnostic)] -#[diag(resolve_trait_impl_duplicate, code = "E0201")] +#[diag(resolve_trait_impl_duplicate, code = E0201)] pub(crate) struct TraitImplDuplicate { #[primary_span] #[label] @@ -519,11 +530,11 @@ pub(crate) struct Relative2018 { } #[derive(Diagnostic)] -#[diag(resolve_ancestor_only, code = "E0742")] +#[diag(resolve_ancestor_only, code = E0742)] pub(crate) struct AncestorOnly(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_expected_found, code = "E0577")] +#[diag(resolve_expected_found, code = E0577)] pub(crate) struct ExpectedFound { #[primary_span] #[label] @@ -533,7 +544,7 @@ pub(crate) struct ExpectedFound { } #[derive(Diagnostic)] -#[diag(resolve_indeterminate, code = "E0578")] +#[diag(resolve_indeterminate, code = E0578)] pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] @@ -715,7 +726,7 @@ pub(crate) struct CannotDetermineMacroResolution { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_private, code = "E0364")] +#[diag(resolve_cannot_be_reexported_private, code = E0364)] pub(crate) struct CannotBeReexportedPrivate { #[primary_span] pub(crate) span: Span, @@ -723,7 +734,7 @@ pub(crate) struct CannotBeReexportedPrivate { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_crate_public, code = "E0364")] +#[diag(resolve_cannot_be_reexported_crate_public, code = E0364)] pub(crate) struct CannotBeReexportedCratePublic { #[primary_span] pub(crate) span: Span, @@ -731,7 +742,7 @@ pub(crate) struct CannotBeReexportedCratePublic { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_private, code = "E0365")] +#[diag(resolve_cannot_be_reexported_private, code = E0365)] #[note(resolve_consider_declaring_with_pub)] pub(crate) struct CannotBeReexportedPrivateNS { #[primary_span] @@ -741,7 +752,7 @@ pub(crate) struct CannotBeReexportedPrivateNS { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_crate_public, code = "E0365")] +#[diag(resolve_cannot_be_reexported_crate_public, code = E0365)] #[note(resolve_consider_declaring_with_pub)] pub(crate) struct CannotBeReexportedCratePublicNS { #[primary_span] @@ -780,10 +791,37 @@ pub(crate) struct ItemsInTraitsAreNotImportable { } #[derive(Diagnostic)] -#[diag(resolve_is_not_directly_importable, code = "E0253")] +#[diag(resolve_is_not_directly_importable, code = E0253)] pub(crate) struct IsNotDirectlyImportable { #[primary_span] #[label] pub(crate) span: Span, pub(crate) target: Ident, } + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_unexpected_res_change_ty_to_const_param_sugg, + code = "const ", + style = "verbose" +)] +pub(crate) struct UnexpectedResChangeTyToConstParamSugg { + #[primary_span] + pub span: Span, + #[applicability] + pub applicability: Applicability, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg, + code = "{snippet}", + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg { + #[primary_span] + pub span: Span, + pub ident: Ident, + pub snippet: String, +} diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7fb9db16e9c7b..e47f2bdd4d2b1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -10,9 +10,7 @@ use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use crate::late::{ - ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind, -}; +use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::BindingKey; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; @@ -1090,7 +1088,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { | RibKind::ForwardGenericParamBan => { // Nothing to do. Continue. } - RibKind::Item(_) | RibKind::AssocItem => { + RibKind::Item(..) | RibKind::AssocItem => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -1155,7 +1153,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => { for rib in ribs { - let has_generic_params: HasGenericParams = match rib.kind { + let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal | RibKind::FnOrCoroutine | RibKind::Module(..) @@ -1213,7 +1211,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // This was an attempt to use a type parameter outside its scope. - RibKind::Item(has_generic_params) => has_generic_params, + RibKind::Item(has_generic_params, def_kind) => { + (has_generic_params, def_kind) + } RibKind::ConstParamTy => { if let Some(span) = finalize { self.report_error( @@ -1231,7 +1231,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { self.report_error( span, - ResolutionError::GenericParamsFromOuterItem(res, has_generic_params), + ResolutionError::GenericParamsFromOuterItem( + res, + has_generic_params, + def_kind, + ), ); } return Res::Err; @@ -1239,7 +1243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Res::Def(DefKind::ConstParam, _) => { for rib in ribs { - let has_generic_params = match rib.kind { + let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal | RibKind::FnOrCoroutine | RibKind::Module(..) @@ -1276,7 +1280,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { continue; } - RibKind::Item(has_generic_params) => has_generic_params, + RibKind::Item(has_generic_params, def_kind) => { + (has_generic_params, def_kind) + } RibKind::ConstParamTy => { if let Some(span) = finalize { self.report_error( @@ -1295,7 +1301,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { self.report_error( span, - ResolutionError::GenericParamsFromOuterItem(res, has_generic_params), + ResolutionError::GenericParamsFromOuterItem( + res, + has_generic_params, + def_kind, + ), ); } return Res::Err; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f846dbec2c697..30fb35238c3c7 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -17,7 +17,7 @@ use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult}; use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; use rustc_middle::metadata::Reexport; @@ -80,7 +80,11 @@ pub(crate) enum ImportKind<'a> { target: Ident, id: NodeId, }, - MacroUse, + MacroUse { + /// A field has been added indicating whether it should be reported as a lint, + /// addressing issue#119301. + warn_private: bool, + }, MacroExport, } @@ -127,7 +131,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { .field("target", target) .field("id", id) .finish(), - MacroUse => f.debug_struct("MacroUse").finish(), + MacroUse { .. } => f.debug_struct("MacroUse").finish(), MacroExport => f.debug_struct("MacroExport").finish(), } } @@ -197,7 +201,7 @@ impl<'a> ImportData<'a> { ImportKind::Single { id, .. } | ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => Some(id), - ImportKind::MacroUse | ImportKind::MacroExport => None, + ImportKind::MacroUse { .. } | ImportKind::MacroExport => None, } } @@ -207,7 +211,7 @@ impl<'a> ImportData<'a> { ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)), ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)), ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)), - ImportKind::MacroUse => Reexport::MacroUse, + ImportKind::MacroUse { .. } => Reexport::MacroUse, ImportKind::MacroExport => Reexport::MacroExport, } } @@ -1482,7 +1486,7 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String { ImportKind::Single { source, .. } => source.to_string(), ImportKind::Glob { .. } => "*".to_string(), ImportKind::ExternCrate { .. } => "".to_string(), - ImportKind::MacroUse => "#[macro_use]".to_string(), + ImportKind::MacroUse { .. } => "#[macro_use]".to_string(), ImportKind::MacroExport => "#[macro_export]".to_string(), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index abd724a6cc25c..f0b5311f1e1bb 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -16,7 +16,9 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{Applicability, DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, ErrCode, IntoDiagnosticArg, +}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -88,7 +90,7 @@ impl PatternSource { } impl IntoDiagnosticArg for PatternSource { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::Borrowed(self.descr())) } } @@ -183,7 +185,7 @@ pub(crate) enum RibKind<'a> { FnOrCoroutine, /// We passed through an item scope. Disallow upvars. - Item(HasGenericParams), + Item(HasGenericParams, DefKind), /// We're in a constant item. Can't refer to dynamic stuff. /// @@ -223,7 +225,7 @@ impl RibKind<'_> { | RibKind::MacroDefinition(_) | RibKind::ConstParamTy | RibKind::InlineAsmSym => false, - RibKind::AssocItem | RibKind::Item(_) | RibKind::ForwardGenericParamBan => true, + RibKind::AssocItem | RibKind::Item(..) | RibKind::ForwardGenericParamBan => true, } } @@ -533,21 +535,20 @@ impl<'a> PathSource<'a> { } } - fn error_code(self, has_unexpected_resolution: bool) -> String { - use rustc_errors::error_code; + fn error_code(self, has_unexpected_resolution: bool) -> ErrCode { match (self, has_unexpected_resolution) { - (PathSource::Trait(_), true) => error_code!(E0404), - (PathSource::Trait(_), false) => error_code!(E0405), - (PathSource::Type, true) => error_code!(E0573), - (PathSource::Type, false) => error_code!(E0412), - (PathSource::Struct, true) => error_code!(E0574), - (PathSource::Struct, false) => error_code!(E0422), - (PathSource::Expr(..), true) | (PathSource::Delegation, true) => error_code!(E0423), - (PathSource::Expr(..), false) | (PathSource::Delegation, false) => error_code!(E0425), - (PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532), - (PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531), - (PathSource::TraitItem(..), true) => error_code!(E0575), - (PathSource::TraitItem(..), false) => error_code!(E0576), + (PathSource::Trait(_), true) => E0404, + (PathSource::Trait(_), false) => E0405, + (PathSource::Type, true) => E0573, + (PathSource::Type, 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) => E0575, + (PathSource::TraitItem(..), false) => E0576, } } } @@ -593,9 +594,9 @@ struct DiagnosticMetadata<'ast> { /// The current trait (used to suggest). current_item: Option<&'ast Item>, - /// When processing generics and encountering a type not found, suggest introducing a type - /// param. - currently_processing_generics: bool, + /// When processing generic arguments and encountering an unresolved ident not found, + /// suggest introducing a type or const param depending on the context. + currently_processing_generic_args: bool, /// The current enclosing (non-closure) function (used for better errors). current_function: Option<(FnKind<'ast>, Span)>, @@ -868,11 +869,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); + let def_kind = self.r.local_def_kind(foreign_item.id); match foreign_item.kind { ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Item, @@ -884,7 +886,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, ForeignItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Function, @@ -894,7 +896,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, ); } ForeignItemKind::Static(..) => { - self.with_static_rib(|this| { + self.with_static_rib(def_kind, |this| { visit::walk_foreign_item(this, foreign_item); }); } @@ -1068,7 +1070,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { debug!("visit_generic_arg({:?})", arg); - let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true); + let prev = replace(&mut self.diagnostic_metadata.currently_processing_generic_args, true); match arg { GenericArg::Type(ref ty) => { // We parse const arguments as path types as we cannot distinguish them during @@ -1099,7 +1101,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, }, ); - self.diagnostic_metadata.currently_processing_generics = prev; + self.diagnostic_metadata.currently_processing_generic_args = prev; return; } } @@ -1112,7 +1114,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No)) } } - self.diagnostic_metadata.currently_processing_generics = prev; + self.diagnostic_metadata.currently_processing_generic_args = prev; } fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) { @@ -1673,13 +1675,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } else { ("`'_` cannot be used here", "`'_` is a reserved lifetime name") }; - let mut diag = rustc_errors::struct_span_code_err!( - self.r.dcx(), - lifetime.ident.span, - E0637, - "{}", - msg, - ); + let mut diag = + struct_span_code_err!(self.r.dcx(), lifetime.ident.span, E0637, "{}", msg,); diag.span_label(lifetime.ident.span, note); if elided { for rib in self.lifetime_ribs[i..].iter().rev() { @@ -1863,7 +1860,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } | LifetimeRibKind::AnonymousWarn(_) => { let sess = self.r.tcx.sess; - let mut err = rustc_errors::struct_span_code_err!( + let mut err = struct_span_code_err!( sess.dcx(), path_span, E0726, @@ -2270,10 +2267,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { debug!("resolve_adt"); + let kind = self.r.local_def_kind(item.id); self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2347,11 +2345,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let name = item.ident.name; debug!("(resolving item) resolving {} ({:?})", name, item.kind); + let def_kind = self.r.local_def_kind(item.id); match item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2364,7 +2363,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Function, @@ -2403,7 +2402,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2424,7 +2423,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2458,7 +2457,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { - self.with_static_rib(|this| { + self.with_static_rib(def_kind, |this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); }); @@ -2473,11 +2472,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(if self.r.tcx.features().generic_const_items { - HasGenericParams::Yes(generics.span) - } else { - HasGenericParams::No - }), + RibKind::Item( + if self.r.tcx.features().generic_const_items { + HasGenericParams::Yes(generics.span) + } else { + HasGenericParams::No + }, + def_kind, + ), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::ConstItem, @@ -2562,7 +2564,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let mut add_bindings_for_ns = |ns| { let parent_rib = self.ribs[ns] .iter() - .rfind(|r| matches!(r.kind, RibKind::Item(_))) + .rfind(|r| matches!(r.kind, RibKind::Item(..))) .expect("associated item outside of an item"); seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); }; @@ -2608,7 +2610,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::UnderscoreLifetime { - rustc_errors::struct_span_code_err!( + struct_span_code_err!( self.r.dcx(), param.ident.span, E0637, @@ -2622,7 +2624,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::StaticLifetime { - rustc_errors::struct_span_code_err!( + struct_span_code_err!( self.r.dcx(), param.ident.span, E0262, @@ -2697,8 +2699,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.label_ribs.pop(); } - fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) { - let kind = RibKind::Item(HasGenericParams::No); + fn with_static_rib(&mut self, def_kind: DefKind, f: impl FnOnce(&mut Self)) { + let kind = RibKind::Item(HasGenericParams::No, def_kind); self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) } @@ -2879,7 +2881,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)), LifetimeRibKind::Generics { span: generics.span, binder: item_id, @@ -3164,10 +3166,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // The method kind does not correspond to what appeared in the trait, report. let path = &self.current_trait_ref.as_ref().unwrap().1.path; let (code, kind) = match kind { - AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"), - AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"), - AssocItemKind::Type(..) => (rustc_errors::error_code!(E0325), "type"), - AssocItemKind::Delegation(..) => (rustc_errors::error_code!(E0324), "method"), + AssocItemKind::Const(..) => (E0323, "const"), + AssocItemKind::Fn(..) => (E0324, "method"), + AssocItemKind::Type(..) => (E0325, "type"), + AssocItemKind::Delegation(..) => (E0324, "method"), AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"), }; let trait_path = path_names_to_string(path); @@ -4424,35 +4426,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ExprKind::Type(ref _type_expr, ref _ty) => { visit::walk_expr(self, expr); } - // `async |x| ...` gets desugared to `|x| async {...}`, so we need to - // resolve the arguments within the proper scopes so that usages of them inside the - // closure are detected as upvars rather than normal closure arg usages. - // - // Similarly, `gen |x| ...` gets desugared to `|x| gen {...}`, so we handle that too. - ExprKind::Closure(box ast::Closure { - coroutine_kind: Some(_), - ref fn_decl, - ref body, - .. - }) => { - self.with_rib(ValueNS, RibKind::Normal, |this| { - this.with_label_rib(RibKind::FnOrCoroutine, |this| { - // Resolve arguments: - this.resolve_params(&fn_decl.inputs); - // No need to resolve return type -- - // the outer closure return type is `FnRetTy::Default`. - - // Now resolve the inner closure - { - // No need to resolve arguments: the inner closure has none. - // Resolve the return type: - visit::walk_fn_ret_ty(this, &fn_decl.output); - // Resolve the body - this.visit_expr(body); - } - }) - }); - } // For closures, RibKind::FnOrCoroutine is added in visit_fn ExprKind::Closure(box ast::Closure { binder: ClosureBinder::For { ref generic_params, span }, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 5a95f2083f666..5d712461993d8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -16,8 +16,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, SuggestionStyle, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; @@ -444,6 +444,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } self.suggest_bare_struct_literal(&mut err); + self.suggest_changing_type_to_const_param(&mut err, res, source, span); if self.suggest_pattern_match_with_let(&mut err, source, span) { // Fallback label. @@ -452,7 +453,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } self.suggest_self_or_self_ref(&mut err, path, span); - self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error); + self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error); if self.suggest_self_ty(&mut err, source, path, span) || self.suggest_self_value(&mut err, source, path, span) { @@ -491,7 +492,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { (err, candidates) } - fn detect_assoct_type_constraint_meant_as_path( + fn detect_assoc_type_constraint_meant_as_path( &self, err: &mut Diagnostic, base_error: &BaseError, @@ -699,7 +700,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.span_suggestion_verbose( span.shrink_to_lo(), msg, - "self.".to_string(), + "self.", Applicability::MachineApplicable, ); } @@ -710,7 +711,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.span_suggestion_verbose( span.shrink_to_lo(), format!("you might have meant to {}", candidate.action()), - "Self::".to_string(), + "Self::", Applicability::MachineApplicable, ); } @@ -799,7 +800,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { false, ) = (source, res, is_macro) { - if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object { + if let Some(bounds @ [first_bound, .., last_bound]) = + self.diagnostic_metadata.current_trait_object + { fallback = true; let spans: Vec = bounds .iter() @@ -807,9 +810,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .filter(|&sp| sp != base_error.span) .collect(); - let start_span = bounds[0].span(); + let start_span = first_bound.span(); // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><) - let end_span = bounds.last().unwrap().span(); + let end_span = last_bound.span(); // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar) let last_bound_span = spans.last().cloned().unwrap(); let mut multi_span: MultiSpan = spans.clone().into(); @@ -922,8 +925,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { path: &[Segment], span: Span, ) { - if let Some(err_code) = &err.code { - if err_code == &rustc_errors::error_code!(E0425) { + if let Some(err_code) = err.code { + if err_code == E0425 { for label_rib in &self.label_ribs { for (label_ident, node_id) in &label_rib.bindings { let ident = path.last().unwrap().ident; @@ -946,7 +949,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } } - } else if err_code == &rustc_errors::error_code!(E0412) { + } else if err_code == E0412 { if let Some(correct) = Self::likely_rust_type(path) { err.span_suggestion( span, @@ -970,7 +973,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if !is_self_type(path, source.namespace()) { return false; } - err.code(rustc_errors::error_code!(E0411)); + err.code(E0411); err.span_label(span, "`Self` is only available in impls, traits, and type definitions"); if let Some(item_kind) = self.diagnostic_metadata.current_item { if !item_kind.ident.span.is_dummy() { @@ -999,7 +1002,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } debug!("smart_resolve_path_fragment: E0424, source={:?}", source); - err.code(rustc_errors::error_code!(E0424)); + err.code(E0424); err.span_label( span, match source { @@ -1074,24 +1077,34 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err: &mut Diagnostic, path: &[Segment], ) { - if let Some(pat) = self.diagnostic_metadata.current_pat - && let ast::PatKind::Range(Some(start), None, range) = &pat.kind - && let ExprKind::Path(None, range_path) = &start.kind + let Some(pat) = self.diagnostic_metadata.current_pat else { return }; + let (bound, side, range) = match &pat.kind { + ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range), + ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range), + _ => return, + }; + if let ExprKind::Path(None, range_path) = &bound.kind && let [segment] = &range_path.segments[..] && let [s] = path && segment.ident == s.ident + && segment.ident.span.eq_ctxt(range.span) { - // We've encountered `[first, rest..]` where the user might have meant - // `[first, rest @ ..]` (#88404). - err.span_suggestion_verbose( - segment.ident.span.between(range.span), - format!( - "if you meant to collect the rest of the slice in `{}`, use the at operator", - segment.ident, - ), - " @ ", - Applicability::MaybeIncorrect, - ); + // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591) + // where the user might have meant `[first, rest @ ..]`. + let (span, snippet) = match side { + Side::Start => (segment.ident.span.between(range.span), " @ ".into()), + Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)), + }; + err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg { + span, + ident: segment.ident, + snippet, + }); + } + + enum Side { + Start, + End, } } @@ -1136,6 +1149,55 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } + fn suggest_changing_type_to_const_param( + &mut self, + err: &mut Diagnostic, + res: Option, + source: PathSource<'_>, + span: Span, + ) { + let PathSource::Trait(_) = source else { return }; + + // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway. + let applicability = match res { + Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => { + Applicability::MachineApplicable + } + // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic + // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the + // benefits of including them here outweighs the small number of false positives. + Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) + if self.r.tcx.features().adt_const_params => + { + Applicability::MaybeIncorrect + } + _ => return, + }; + + let Some(item) = self.diagnostic_metadata.current_item else { return }; + let Some(generics) = item.kind.generics() else { return }; + + let param = generics.params.iter().find_map(|param| { + // Only consider type params with exactly one trait bound. + if let [bound] = &*param.bounds + && let ast::GenericBound::Trait(tref, ast::TraitBoundModifiers::NONE) = bound + && tref.span == span + && param.ident.span.eq_ctxt(span) + { + Some(param.ident.span) + } else { + None + } + }); + + if let Some(param) = param { + err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg { + span: param.shrink_to_lo(), + applicability, + }); + } + } + fn suggest_pattern_match_with_let( &mut self, err: &mut Diagnostic, @@ -2419,10 +2481,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut iter = ident.chars().map(|c| c.is_uppercase()); let single_uppercase_char = matches!(iter.next(), Some(true)) && matches!(iter.next(), None); - if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char { + if !self.diagnostic_metadata.currently_processing_generic_args && !single_uppercase_char { return None; } - match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) { + match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generic_args) { (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => { // Ignore `fn main()` as we don't want to suggest `fn main()` } @@ -2567,8 +2629,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { debug!(?param.ident, ?param.ident.span, ?use_span); let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); + let deletion_span = + if param.bounds.is_empty() { deletion_span() } else { None }; - let deletion_span = deletion_span(); self.r.lint_buffer.buffer_lint_with_diagnostic( lint::builtin::SINGLE_USE_LIFETIMES, param.id, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 341c566d97fc1..16dce7e431dbf 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -15,9 +15,7 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![feature(never_type)] #![feature(rustc_attrs)] -#![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] #![allow(rustc::potential_query_instability)] #![allow(internal_features)] @@ -37,7 +35,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, Lrc}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrCode}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -55,6 +53,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt}; use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; +use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::LintBuffer; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -185,7 +184,7 @@ struct BindingError { #[derive(Debug)] enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer item. - GenericParamsFromOuterItem(Res, HasGenericParams), + GenericParamsFromOuterItem(Res, HasGenericParams, DefKind), /// Error E0403: the name is already used for a type or const parameter in this generic /// parameter list. NameAlreadyUsedInParameterList(Symbol, Span), @@ -257,7 +256,7 @@ enum ResolutionError<'a> { kind: &'static str, trait_path: String, trait_item_span: Span, - code: String, + code: ErrCode, }, /// Error E0201: multiple impl items for the same trait item. TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span }, @@ -1218,6 +1217,10 @@ impl<'tcx> Resolver<'_, 'tcx> { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } + fn local_def_kind(&self, node: NodeId) -> DefKind { + self.tcx.def_kind(self.local_def_id(node)) + } + /// Adds a definition with a parent definition. fn create_def( &mut self, @@ -1799,6 +1802,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind { + if let ImportKind::MacroUse { warn_private: true } = import.kind { + let msg = format!("macro `{ident}` is private"); + self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg); + } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. if is_lexical_scope { @@ -2069,7 +2076,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut ret = Vec::new(); for meta in attr.meta_item_list()? { match meta.lit()?.kind { - LitKind::Int(a, _) => ret.push(a as usize), + LitKind::Int(a, _) => ret.push(a.get() as usize), _ => panic!("invalid arg index"), } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1c085ddf57bf6..170cc1268c39d 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,10 +1,9 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. -use crate::errors::{ - self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope, - MacroExpectedFound, RemoveSurroundingDerive, -}; +use crate::errors::CannotDetermineMacroResolution; +use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope}; +use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy, MacroData}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -15,7 +14,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_code_err, Applicability}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, StashKey}; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; @@ -25,9 +24,8 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::RegisteredTools; use rustc_middle::ty::{TyCtxt, Visibility}; -use rustc_session::lint::builtin::{ - LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, -}; +use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE}; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; @@ -703,21 +701,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // situations should be reported as errors, so this is a bug. this.dcx().span_delayed_bug(span, "inconsistent resolution for a macro"); } - } else { + } else if this.tcx.dcx().has_errors().is_none() && this.privacy_errors.is_empty() { // It's possible that the macro was unresolved (indeterminate) and silently // expanded into a dummy fragment for recovery during expansion. // Now, post-expansion, the resolution may succeed, but we can't change the // past and need to report an error. // However, non-speculative `resolve_path` can successfully return private items // even if speculative `resolve_path` returned nothing previously, so we skip this - // less informative error if the privacy error is reported elsewhere. - if this.privacy_errors.is_empty() { - this.dcx().emit_err(CannotDetermineMacroResolution { - span, - kind: kind.descr(), - path: Segment::names_to_string(path), - }); - } + // less informative error if no other error is reported elsewhere. + + let err = this.dcx().create_err(CannotDetermineMacroResolution { + span, + kind: kind.descr(), + path: Segment::names_to_string(path), + }); + err.stash(span, StashKey::UndeterminedMacroResolution); } }; diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 352758214530e..9c34aa9395764 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -8,7 +8,6 @@ #![doc(rust_logo)] #![allow(internal_features)] #![feature(rustdoc_internals)] -#![feature(allocator_api)] #![feature(associated_type_bounds)] #![feature(const_option)] #![feature(core_intrinsics)] @@ -16,7 +15,6 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(ptr_sub_ptr)] -#![feature(slice_first_last_chunk)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e751ff13a34ca..d35f951e2aea3 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -347,6 +347,7 @@ impl SwitchWithOptPath { pub enum SymbolManglingVersion { Legacy, V0, + Hashed, } #[derive(Clone, Copy, Debug, PartialEq, Hash)] @@ -2692,6 +2693,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M match cg.symbol_mangling_version { // Stable values: None | Some(SymbolManglingVersion::V0) => {} + // Unstable values: Some(SymbolManglingVersion::Legacy) => { if !unstable_opts.unstable_options { @@ -2700,6 +2702,13 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); } } + Some(SymbolManglingVersion::Hashed) => { + if !unstable_opts.unstable_options { + early_dcx.early_fatal( + "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`", + ); + } + } } // Check for unstable values of `-C instrument-coverage`. @@ -2741,6 +2750,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); } Some(SymbolManglingVersion::V0) => {} + Some(SymbolManglingVersion::Hashed) => { + early_dcx.early_warn( + "-C instrument-coverage requires symbol mangling version `v0`, \ + but `-C symbol-mangling-version=hashed` was specified", + ); + } } } @@ -3077,7 +3092,7 @@ impl fmt::Display for CrateType { } impl IntoDiagnosticArg for CrateType { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index e19f0fd84de56..c36cec6f35327 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, + codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -19,9 +19,7 @@ pub struct FeatureGateError { impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new(dcx, level, self.explain) - .with_span(self.span) - .with_code(error_code!(E0658)) + DiagnosticBuilder::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) } } diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 805854bd5cf0c..0d6328fbb071c 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,11 +1,9 @@ #![feature(let_chains)] -#![feature(never_type)] #![feature(lazy_cell)] #![feature(option_get_or_insert_default)] #![feature(rustc_attrs)] #![feature(map_many_mut)] #![feature(iter_intersperse)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1337ade62c019..d8d201d5f244d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -224,7 +224,7 @@ top_level_options!( working_dir: RealFileName [TRACKED], color: ColorConfig [UNTRACKED], - verbose: bool [UNTRACKED], + verbose: bool [TRACKED_NO_CRATE_HASH], } ); @@ -407,7 +407,8 @@ mod desc { pub const parse_switch_with_opt_path: &str = "an optional path to the profiling data output directory"; pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; - pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; + pub const parse_symbol_mangling_version: &str = + "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; @@ -1180,6 +1181,7 @@ mod parse { *slot = match v { Some("legacy") => Some(SymbolManglingVersion::Legacy), Some("v0") => Some(SymbolManglingVersion::V0), + Some("hashed") => Some(SymbolManglingVersion::Hashed), _ => return false, }; true @@ -1504,7 +1506,7 @@ options! { "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), + "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"), target_cpu: Option = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], @@ -1986,7 +1988,7 @@ written to standard error output)"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] - verbose_internals: bool = (false, parse_bool, [UNTRACKED], + verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH], "in general, enable more debug printouts (default: no)"), #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")] verify_llvm_ir: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 16036e5be38c7..8adb0cbcc9d76 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -144,7 +144,7 @@ pub fn feature_warn_issue( let mut err = sess.parse_sess.dcx.struct_span_warn(span, explain); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false); - // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level + // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; let future_incompatible = lint.future_incompatible.as_ref().unwrap(); err.is_lint(lint.name_lower(), /* has_future_breakage */ false); @@ -258,7 +258,7 @@ impl ParseSess { } } - pub fn with_silent_emitter(fatal_note: Option) -> Self { + pub fn with_silent_emitter(fatal_note: String) -> Self { let fallback_bundle = fallback_fluent_bundle(Vec::new(), false); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let fatal_dcx = DiagCtxt::with_tty_emitter(None, fallback_bundle).disable_warnings(); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3f6c70a18d395..f6af5a4f87e07 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -14,13 +14,15 @@ use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; -use rustc_data_structures::sync::{AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread}; +use rustc_data_structures::sync::{ + AtomicU64, DynSend, DynSync, Lock, Lrc, MappedReadGuard, ReadGuard, RwLock, +}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - error_code, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, + codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrCode, ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, LazyFallbackBundle, TerminalUrl, }; use rustc_macros::HashStable_Generic; @@ -35,7 +37,6 @@ use rustc_target::spec::{ }; use std::any::Any; -use std::cell::{self, RefCell}; use std::env; use std::fmt; use std::ops::{Div, Mul}; @@ -110,7 +111,7 @@ impl Mul for Limit { } impl rustc_errors::IntoDiagnosticArg for Limit { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { self.to_string().into_diagnostic_arg() } } @@ -149,7 +150,7 @@ pub struct Session { /// Input, input file path and output file path to this compilation process. pub io: CompilerIO, - incr_comp_session: OneThread>, + incr_comp_session: RwLock, /// Used by `-Z self-profile`. pub prof: SelfProfilerRef, @@ -287,19 +288,9 @@ impl Session { pub fn finish_diagnostics(&self, registry: &Registry) { self.check_miri_unleashed_features(); self.dcx().print_error_count(registry); - self.emit_future_breakage(); - } - - fn emit_future_breakage(&self) { - if !self.opts.json_future_incompat { - return; + if self.opts.json_future_incompat { + self.dcx().emit_future_breakage_report(); } - - let diags = self.dcx().take_future_breakage_diagnostics(); - if diags.is_empty() { - return; - } - self.dcx().emit_future_breakage_report(diags); } /// Returns true if the crate is a testing one. @@ -315,13 +306,14 @@ impl Session { ) -> DiagnosticBuilder<'a> { let mut err = self.dcx().create_err(err); if err.code.is_none() { - err.code(error_code!(E0658)); + err.code(E0658); } add_feature_diagnostics(&mut err, self, feature); err } pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { + // We must include lint errors here. if let Some(reported) = self.dcx().has_errors_or_lint_errors() { let _ = self.dcx().emit_stashed_diagnostics(); Err(reported) @@ -330,20 +322,6 @@ impl Session { } } - // FIXME(matthewjasper) Remove this method, it should never be needed. - pub fn track_errors(&self, f: F) -> Result - where - F: FnOnce() -> T, - { - let old_count = self.dcx().err_count(); - let result = f(); - if self.dcx().err_count() == old_count { - Ok(result) - } else { - Err(self.dcx().delayed_bug("`self.err_count()` changed but an error was not emitted")) - } - } - /// Used for code paths of expensive computations that should only take place when /// warnings or errors are emitted. If no messages are emitted ("good path"), then /// it's likely a bug. @@ -533,9 +511,9 @@ impl Session { *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory }; } - pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> { + pub fn incr_comp_session_dir(&self) -> MappedReadGuard<'_, PathBuf> { let incr_comp_session = self.incr_comp_session.borrow(); - cell::Ref::map(incr_comp_session, |incr_comp_session| match *incr_comp_session { + ReadGuard::map(incr_comp_session, |incr_comp_session| match *incr_comp_session { IncrCompSession::NotInitialized => panic!( "trying to get session directory from `IncrCompSession`: {:?}", *incr_comp_session, @@ -548,7 +526,7 @@ impl Session { }) } - pub fn incr_comp_session_dir_opt(&self) -> Option> { + pub fn incr_comp_session_dir_opt(&self) -> Option> { self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir()) } @@ -905,7 +883,7 @@ impl Session { CodegenUnits::Default(16) } - pub fn teach(&self, code: &str) -> bool { + pub fn teach(&self, code: ErrCode) -> bool { self.opts.unstable_opts.teach && self.dcx().must_teach(code) } @@ -1176,7 +1154,7 @@ pub fn build_session( parse_sess, sysroot, io, - incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), + incr_comp_session: RwLock::new(IncrCompSession::NotInitialized), prof, code_stats: Default::default(), optimization_fuel, @@ -1522,16 +1500,25 @@ pub trait RemapFileNameExt { where Self: 'a; - fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_>; + /// Returns a possibly remapped filename based on the passed scope and remap cli options. + /// + /// One and only one scope should be passed to this method. For anything related to + /// "codegen" see the [`RemapFileNameExt::for_codegen`] method. + fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_>; + /// Return a possibly remapped filename, to be used in "codegen" related parts. fn for_codegen(&self, sess: &Session) -> Self::Output<'_>; } impl RemapFileNameExt for rustc_span::FileName { type Output<'a> = rustc_span::FileNameDisplay<'a>; - fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> { - if sess.opts.unstable_opts.remap_path_scope.contains(scopes) { + fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> { + assert!( + scope.bits().count_ones() == 1, + "one and only one scope should be passed to for_scope" + ); + if sess.opts.unstable_opts.remap_path_scope.contains(scope) { self.prefer_remapped_unconditionaly() } else { self.prefer_local() @@ -1550,8 +1537,12 @@ impl RemapFileNameExt for rustc_span::FileName { impl RemapFileNameExt for rustc_span::RealFileName { type Output<'a> = &'a Path; - fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> { - if sess.opts.unstable_opts.remap_path_scope.contains(scopes) { + fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> { + assert!( + scope.bits().count_ones() == 1, + "one and only one scope should be passed to for_scope" + ); + if sess.opts.unstable_opts.remap_path_scope.contains(scope) { self.remapped_path_if_available() } else { self.local_path_if_available() diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 5689e8f3b3d94..6bbfcff5e87cc 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -5,7 +5,7 @@ // Prefer importing stable_mir over internal rustc constructs to make this file more readable. use crate::rustc_smir::Tables; -use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; +use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy, TyCtxt}; use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; @@ -21,118 +21,120 @@ use stable_mir::{CrateItem, CrateNum, DefId}; use super::RustcInternal; -impl<'tcx> RustcInternal<'tcx> for CrateItem { - type T = rustc_span::def_id::DefId; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - self.0.internal(tables) +impl RustcInternal for CrateItem { + type T<'tcx> = rustc_span::def_id::DefId; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + self.0.internal(tables, tcx) } } -impl<'tcx> RustcInternal<'tcx> for CrateNum { - type T = rustc_span::def_id::CrateNum; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { +impl RustcInternal for CrateNum { + type T<'tcx> = rustc_span::def_id::CrateNum; + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { rustc_span::def_id::CrateNum::from_usize(*self) } } -impl<'tcx> RustcInternal<'tcx> for DefId { - type T = rustc_span::def_id::DefId; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.def_ids[*self] +impl RustcInternal for DefId { + type T<'tcx> = rustc_span::def_id::DefId; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(tables.def_ids[*self]).unwrap() } } -impl<'tcx> RustcInternal<'tcx> for GenericArgs { - type T = rustc_ty::GenericArgsRef<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables))) +impl RustcInternal for GenericArgs { + type T<'tcx> = rustc_ty::GenericArgsRef<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables, tcx))) } } -impl<'tcx> RustcInternal<'tcx> for GenericArgKind { - type T = rustc_ty::GenericArg<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - match self { - GenericArgKind::Lifetime(reg) => reg.internal(tables).into(), - GenericArgKind::Type(ty) => ty.internal(tables).into(), - GenericArgKind::Const(cnst) => ty_const(cnst, tables).into(), - } +impl RustcInternal for GenericArgKind { + type T<'tcx> = rustc_ty::GenericArg<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + let arg: rustc_ty::GenericArg<'tcx> = match self { + GenericArgKind::Lifetime(reg) => reg.internal(tables, tcx).into(), + GenericArgKind::Type(ty) => ty.internal(tables, tcx).into(), + GenericArgKind::Const(cnst) => ty_const(cnst, tables, tcx).into(), + }; + tcx.lift(arg).unwrap() } } -impl<'tcx> RustcInternal<'tcx> for Region { - type T = rustc_ty::Region<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - // Cannot recover region. Use erased instead. - tables.tcx.lifetimes.re_erased +impl RustcInternal for Region { + type T<'tcx> = rustc_ty::Region<'tcx>; + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + // Cannot recover region. Use erased for now. + tcx.lifetimes.re_erased } } -impl<'tcx> RustcInternal<'tcx> for Ty { - type T = InternalTy<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.types[*self] +impl RustcInternal for Ty { + type T<'tcx> = InternalTy<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(tables.types[*self]).unwrap() } } -impl<'tcx> RustcInternal<'tcx> for RigidTy { - type T = rustc_ty::TyKind<'tcx>; +impl RustcInternal for RigidTy { + type T<'tcx> = rustc_ty::TyKind<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { RigidTy::Bool => rustc_ty::TyKind::Bool, RigidTy::Char => rustc_ty::TyKind::Char, - RigidTy::Int(int_ty) => rustc_ty::TyKind::Int(int_ty.internal(tables)), - RigidTy::Uint(uint_ty) => rustc_ty::TyKind::Uint(uint_ty.internal(tables)), - RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables)), + RigidTy::Int(int_ty) => rustc_ty::TyKind::Int(int_ty.internal(tables, tcx)), + RigidTy::Uint(uint_ty) => rustc_ty::TyKind::Uint(uint_ty.internal(tables, tcx)), + RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables, tcx)), RigidTy::Never => rustc_ty::TyKind::Never, RigidTy::Array(ty, cnst) => { - rustc_ty::TyKind::Array(ty.internal(tables), ty_const(cnst, tables)) + rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx)) } RigidTy::Adt(def, args) => { - rustc_ty::TyKind::Adt(def.internal(tables), args.internal(tables)) + rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx)) } RigidTy::Str => rustc_ty::TyKind::Str, - RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables)), + RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables, tcx)), RigidTy::RawPtr(ty, mutability) => rustc_ty::TyKind::RawPtr(rustc_ty::TypeAndMut { - ty: ty.internal(tables), - mutbl: mutability.internal(tables), + ty: ty.internal(tables, tcx), + mutbl: mutability.internal(tables, tcx), }), RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref( - region.internal(tables), - ty.internal(tables), - mutability.internal(tables), + region.internal(tables, tcx), + ty.internal(tables, tcx), + mutability.internal(tables, tcx), ), - RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables)), + RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables, tcx)), RigidTy::FnDef(def, args) => { - rustc_ty::TyKind::FnDef(def.0.internal(tables), args.internal(tables)) + rustc_ty::TyKind::FnDef(def.0.internal(tables, tcx), args.internal(tables, tcx)) } - RigidTy::FnPtr(sig) => rustc_ty::TyKind::FnPtr(sig.internal(tables)), + RigidTy::FnPtr(sig) => rustc_ty::TyKind::FnPtr(sig.internal(tables, tcx)), RigidTy::Closure(def, args) => { - rustc_ty::TyKind::Closure(def.0.internal(tables), args.internal(tables)) + rustc_ty::TyKind::Closure(def.0.internal(tables, tcx), args.internal(tables, tcx)) } RigidTy::Coroutine(def, args, _mov) => { - rustc_ty::TyKind::Coroutine(def.0.internal(tables), args.internal(tables)) - } - RigidTy::CoroutineWitness(def, args) => { - rustc_ty::TyKind::CoroutineWitness(def.0.internal(tables), args.internal(tables)) + rustc_ty::TyKind::Coroutine(def.0.internal(tables, tcx), args.internal(tables, tcx)) } + RigidTy::CoroutineWitness(def, args) => rustc_ty::TyKind::CoroutineWitness( + def.0.internal(tables, tcx), + args.internal(tables, tcx), + ), RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic( - tables.tcx.mk_poly_existential_predicates(&predicate.internal(tables)), - region.internal(tables), - dyn_kind.internal(tables), + tcx.mk_poly_existential_predicates(&predicate.internal(tables, tcx)), + region.internal(tables, tcx), + dyn_kind.internal(tables, tcx), ), RigidTy::Tuple(tys) => { - rustc_ty::TyKind::Tuple(tables.tcx.mk_type_list(&tys.internal(tables))) + rustc_ty::TyKind::Tuple(tcx.mk_type_list(&tys.internal(tables, tcx))) } } } } -impl<'tcx> RustcInternal<'tcx> for IntTy { - type T = rustc_ty::IntTy; +impl RustcInternal for IntTy { + type T<'tcx> = rustc_ty::IntTy; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { IntTy::Isize => rustc_ty::IntTy::Isize, IntTy::I8 => rustc_ty::IntTy::I8, @@ -144,10 +146,10 @@ impl<'tcx> RustcInternal<'tcx> for IntTy { } } -impl<'tcx> RustcInternal<'tcx> for UintTy { - type T = rustc_ty::UintTy; +impl RustcInternal for UintTy { + type T<'tcx> = rustc_ty::UintTy; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { UintTy::Usize => rustc_ty::UintTy::Usize, UintTy::U8 => rustc_ty::UintTy::U8, @@ -159,10 +161,10 @@ impl<'tcx> RustcInternal<'tcx> for UintTy { } } -impl<'tcx> RustcInternal<'tcx> for FloatTy { - type T = rustc_ty::FloatTy; +impl RustcInternal for FloatTy { + type T<'tcx> = rustc_ty::FloatTy; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { FloatTy::F32 => rustc_ty::FloatTy::F32, FloatTy::F64 => rustc_ty::FloatTy::F64, @@ -170,10 +172,10 @@ impl<'tcx> RustcInternal<'tcx> for FloatTy { } } -impl<'tcx> RustcInternal<'tcx> for Mutability { - type T = rustc_ty::Mutability; +impl RustcInternal for Mutability { + type T<'tcx> = rustc_ty::Mutability; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { Mutability::Not => rustc_ty::Mutability::Not, Mutability::Mut => rustc_ty::Mutability::Mut, @@ -181,10 +183,10 @@ impl<'tcx> RustcInternal<'tcx> for Mutability { } } -impl<'tcx> RustcInternal<'tcx> for Movability { - type T = rustc_ty::Movability; +impl RustcInternal for Movability { + type T<'tcx> = rustc_ty::Movability; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { Movability::Static => rustc_ty::Movability::Static, Movability::Movable => rustc_ty::Movability::Movable, @@ -192,37 +194,42 @@ impl<'tcx> RustcInternal<'tcx> for Movability { } } -impl<'tcx> RustcInternal<'tcx> for FnSig { - type T = rustc_ty::FnSig<'tcx>; +impl RustcInternal for FnSig { + type T<'tcx> = rustc_ty::FnSig<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - rustc_ty::FnSig { - inputs_and_output: tables.tcx.mk_type_list(&self.inputs_and_output.internal(tables)), + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(rustc_ty::FnSig { + inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)), c_variadic: self.c_variadic, - unsafety: self.unsafety.internal(tables), - abi: self.abi.internal(tables), - } + unsafety: self.unsafety.internal(tables, tcx), + abi: self.abi.internal(tables, tcx), + }) + .unwrap() } } -impl<'tcx> RustcInternal<'tcx> for VariantIdx { - type T = rustc_target::abi::VariantIdx; +impl RustcInternal for VariantIdx { + type T<'tcx> = rustc_target::abi::VariantIdx; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { rustc_target::abi::VariantIdx::from(self.to_index()) } } -impl<'tcx> RustcInternal<'tcx> for VariantDef { - type T = &'tcx rustc_ty::VariantDef; +impl RustcInternal for VariantDef { + type T<'tcx> = &'tcx rustc_ty::VariantDef; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - self.adt_def.internal(tables).variant(self.idx.internal(tables)) + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + self.adt_def.internal(tables, tcx).variant(self.idx.internal(tables, tcx)) } } -fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> { - match constant.internal(tables) { +fn ty_const<'tcx>( + constant: &Const, + tables: &mut Tables<'_>, + tcx: TyCtxt<'tcx>, +) -> rustc_ty::Const<'tcx> { + match constant.internal(tables, tcx) { rustc_middle::mir::Const::Ty(c) => c, cnst => { panic!("Trying to convert constant `{constant:?}` to type constant, but found {cnst:?}") @@ -230,21 +237,33 @@ fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Cons } } -impl<'tcx> RustcInternal<'tcx> for Const { - type T = rustc_middle::mir::Const<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.constants[self.id] +impl RustcInternal for Const { + type T<'tcx> = rustc_middle::mir::Const<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + let constant = tables.constants[self.id]; + match constant { + rustc_middle::mir::Const::Ty(ty) => rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap()), + rustc_middle::mir::Const::Unevaluated(uneval, ty) => { + rustc_middle::mir::Const::Unevaluated( + tcx.lift(uneval).unwrap(), + tcx.lift(ty).unwrap(), + ) + } + rustc_middle::mir::Const::Val(const_val, ty) => { + rustc_middle::mir::Const::Val(tcx.lift(const_val).unwrap(), tcx.lift(ty).unwrap()) + } + } } } -impl<'tcx> RustcInternal<'tcx> for MonoItem { - type T = rustc_middle::mir::mono::MonoItem<'tcx>; +impl RustcInternal for MonoItem { + type T<'tcx> = rustc_middle::mir::mono::MonoItem<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { use rustc_middle::mir::mono as rustc_mono; match self { - MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables)), - MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables)), + MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables, tcx)), + MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables, tcx)), MonoItem::GlobalAsm(_) => { unimplemented!() } @@ -252,55 +271,56 @@ impl<'tcx> RustcInternal<'tcx> for MonoItem { } } -impl<'tcx> RustcInternal<'tcx> for Instance { - type T = rustc_ty::Instance<'tcx>; +impl RustcInternal for Instance { + type T<'tcx> = rustc_ty::Instance<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.instances[self.def] + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(tables.instances[self.def]).unwrap() } } -impl<'tcx> RustcInternal<'tcx> for StaticDef { - type T = rustc_span::def_id::DefId; +impl RustcInternal for StaticDef { + type T<'tcx> = rustc_span::def_id::DefId; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - self.0.internal(tables) + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + self.0.internal(tables, tcx) } } #[allow(rustc::usage_of_qualified_ty)] -impl<'tcx, T> RustcInternal<'tcx> for Binder +impl RustcInternal for Binder where - T: RustcInternal<'tcx>, - T::T: rustc_ty::TypeVisitable>, + T: RustcInternal, + for<'tcx> T::T<'tcx>: rustc_ty::TypeVisitable>, { - type T = rustc_ty::Binder<'tcx, T::T>; + type T<'tcx> = rustc_ty::Binder<'tcx, T::T<'tcx>>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { rustc_ty::Binder::bind_with_vars( - self.value.internal(tables), - tables.tcx.mk_bound_variable_kinds_from_iter( - self.bound_vars.iter().map(|bound| bound.internal(tables)), + self.value.internal(tables, tcx), + tcx.mk_bound_variable_kinds_from_iter( + self.bound_vars.iter().map(|bound| bound.internal(tables, tcx)), ), ) } } -impl<'tcx> RustcInternal<'tcx> for BoundVariableKind { - type T = rustc_ty::BoundVariableKind; +impl RustcInternal for BoundVariableKind { + type T<'tcx> = rustc_ty::BoundVariableKind; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { BoundVariableKind::Ty(kind) => rustc_ty::BoundVariableKind::Ty(match kind { BoundTyKind::Anon => rustc_ty::BoundTyKind::Anon, - BoundTyKind::Param(def, symbol) => { - rustc_ty::BoundTyKind::Param(def.0.internal(tables), Symbol::intern(symbol)) - } + BoundTyKind::Param(def, symbol) => rustc_ty::BoundTyKind::Param( + def.0.internal(tables, tcx), + Symbol::intern(symbol), + ), }), BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind { BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::BrAnon, BoundRegionKind::BrNamed(def, symbol) => rustc_ty::BoundRegionKind::BrNamed( - def.0.internal(tables), + def.0.internal(tables, tcx), Symbol::intern(symbol), ), BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::BrEnv, @@ -310,10 +330,10 @@ impl<'tcx> RustcInternal<'tcx> for BoundVariableKind { } } -impl<'tcx> RustcInternal<'tcx> for DynKind { - type T = rustc_ty::DynKind; +impl RustcInternal for DynKind { + type T<'tcx> = rustc_ty::DynKind; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { DynKind::Dyn => rustc_ty::DynKind::Dyn, DynKind::DynStar => rustc_ty::DynKind::DynStar, @@ -321,81 +341,81 @@ impl<'tcx> RustcInternal<'tcx> for DynKind { } } -impl<'tcx> RustcInternal<'tcx> for ExistentialPredicate { - type T = rustc_ty::ExistentialPredicate<'tcx>; +impl RustcInternal for ExistentialPredicate { + type T<'tcx> = rustc_ty::ExistentialPredicate<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { ExistentialPredicate::Trait(trait_ref) => { - rustc_ty::ExistentialPredicate::Trait(trait_ref.internal(tables)) + rustc_ty::ExistentialPredicate::Trait(trait_ref.internal(tables, tcx)) } ExistentialPredicate::Projection(proj) => { - rustc_ty::ExistentialPredicate::Projection(proj.internal(tables)) + rustc_ty::ExistentialPredicate::Projection(proj.internal(tables, tcx)) } ExistentialPredicate::AutoTrait(trait_def) => { - rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables)) + rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables, tcx)) } } } } -impl<'tcx> RustcInternal<'tcx> for ExistentialProjection { - type T = rustc_ty::ExistentialProjection<'tcx>; +impl RustcInternal for ExistentialProjection { + type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { rustc_ty::ExistentialProjection { - def_id: self.def_id.0.internal(tables), - args: self.generic_args.internal(tables), - term: self.term.internal(tables), + def_id: self.def_id.0.internal(tables, tcx), + args: self.generic_args.internal(tables, tcx), + term: self.term.internal(tables, tcx), } } } -impl<'tcx> RustcInternal<'tcx> for TermKind { - type T = rustc_ty::Term<'tcx>; +impl RustcInternal for TermKind { + type T<'tcx> = rustc_ty::Term<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { - TermKind::Type(ty) => ty.internal(tables).into(), - TermKind::Const(const_) => ty_const(const_, tables).into(), + TermKind::Type(ty) => ty.internal(tables, tcx).into(), + TermKind::Const(const_) => ty_const(const_, tables, tcx).into(), } } } -impl<'tcx> RustcInternal<'tcx> for ExistentialTraitRef { - type T = rustc_ty::ExistentialTraitRef<'tcx>; +impl RustcInternal for ExistentialTraitRef { + type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { rustc_ty::ExistentialTraitRef { - def_id: self.def_id.0.internal(tables), - args: self.generic_args.internal(tables), + def_id: self.def_id.0.internal(tables, tcx), + args: self.generic_args.internal(tables, tcx), } } } -impl<'tcx> RustcInternal<'tcx> for TraitRef { - type T = rustc_ty::TraitRef<'tcx>; +impl RustcInternal for TraitRef { + type T<'tcx> = rustc_ty::TraitRef<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { rustc_ty::TraitRef::new( - tables.tcx, - self.def_id.0.internal(tables), - self.args().internal(tables), + tcx, + self.def_id.0.internal(tables, tcx), + self.args().internal(tables, tcx), ) } } -impl<'tcx> RustcInternal<'tcx> for AllocId { - type T = rustc_middle::mir::interpret::AllocId; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.alloc_ids[*self] +impl RustcInternal for AllocId { + type T<'tcx> = rustc_middle::mir::interpret::AllocId; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(tables.alloc_ids[*self]).unwrap() } } -impl<'tcx> RustcInternal<'tcx> for ClosureKind { - type T = rustc_ty::ClosureKind; +impl RustcInternal for ClosureKind { + type T<'tcx> = rustc_ty::ClosureKind; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { ClosureKind::Fn => rustc_ty::ClosureKind::Fn, ClosureKind::FnMut => rustc_ty::ClosureKind::FnMut, @@ -404,17 +424,17 @@ impl<'tcx> RustcInternal<'tcx> for ClosureKind { } } -impl<'tcx> RustcInternal<'tcx> for AdtDef { - type T = rustc_ty::AdtDef<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.tcx.adt_def(self.0.internal(&mut *tables)) +impl RustcInternal for AdtDef { + type T<'tcx> = rustc_ty::AdtDef<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.adt_def(self.0.internal(tables, tcx)) } } -impl<'tcx> RustcInternal<'tcx> for Abi { - type T = rustc_target::spec::abi::Abi; +impl RustcInternal for Abi { + type T<'tcx> = rustc_target::spec::abi::Abi; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match *self { Abi::Rust => rustc_target::spec::abi::Abi::Rust, Abi::C { unwind } => rustc_target::spec::abi::Abi::C { unwind }, @@ -429,7 +449,6 @@ impl<'tcx> RustcInternal<'tcx> for Abi { Abi::PtxKernel => rustc_target::spec::abi::Abi::PtxKernel, Abi::Msp430Interrupt => rustc_target::spec::abi::Abi::Msp430Interrupt, Abi::X86Interrupt => rustc_target::spec::abi::Abi::X86Interrupt, - Abi::AmdGpuKernel => rustc_target::spec::abi::Abi::AmdGpuKernel, Abi::EfiApi => rustc_target::spec::abi::Abi::EfiApi, Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, @@ -447,10 +466,10 @@ impl<'tcx> RustcInternal<'tcx> for Abi { } } -impl<'tcx> RustcInternal<'tcx> for Safety { - type T = rustc_hir::Unsafety; +impl RustcInternal for Safety { + type T<'tcx> = rustc_hir::Unsafety; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { Safety::Unsafe => rustc_hir::Unsafety::Unsafe, Safety::Normal => rustc_hir::Unsafety::Normal, @@ -458,51 +477,51 @@ impl<'tcx> RustcInternal<'tcx> for Safety { } } -impl<'tcx> RustcInternal<'tcx> for Span { - type T = rustc_span::Span; +impl RustcInternal for Span { + type T<'tcx> = rustc_span::Span; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn internal<'tcx>(&self, tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { tables[*self] } } -impl<'tcx> RustcInternal<'tcx> for Layout { - type T = rustc_target::abi::Layout<'tcx>; +impl RustcInternal for Layout { + type T<'tcx> = rustc_target::abi::Layout<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.layouts[*self] + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(tables.layouts[*self]).unwrap() } } -impl<'tcx, T> RustcInternal<'tcx> for &T +impl RustcInternal for &T where - T: RustcInternal<'tcx>, + T: RustcInternal, { - type T = T::T; + type T<'tcx> = T::T<'tcx>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - (*self).internal(tables) + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + (*self).internal(tables, tcx) } } -impl<'tcx, T> RustcInternal<'tcx> for Option +impl RustcInternal for Option where - T: RustcInternal<'tcx>, + T: RustcInternal, { - type T = Option; + type T<'tcx> = Option>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - self.as_ref().map(|inner| inner.internal(tables)) + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + self.as_ref().map(|inner| inner.internal(tables, tcx)) } } -impl<'tcx, T> RustcInternal<'tcx> for Vec +impl RustcInternal for Vec where - T: RustcInternal<'tcx>, + T: RustcInternal, { - type T = Vec; + type T<'tcx> = Vec>; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - self.iter().map(|e| e.internal(tables)).collect() + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + self.iter().map(|e| e.internal(tables, tcx)).collect() } } diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index b99640d2f2d68..43987fcf10fc9 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -24,12 +24,38 @@ use std::ops::Index; mod internal; pub mod pretty; +/// Convert an internal Rust compiler item into its stable counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and its behavior may change at any point. +/// E.g.: Items that were previously supported, may no longer be supported, or its translation may +/// change. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { with_tables(|tables| item.stable(tables)) } -pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T { - with_tables(|tables| item.internal(tables)) +/// Convert a stable item into its internal Rust compiler counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// Not every stable item can be converted to an internal one. +/// Furthermore, items that were previously supported, may no longer be supported in newer versions. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. +pub fn internal<'tcx, S>(tcx: TyCtxt<'tcx>, item: S) -> S::T<'tcx> +where + S: RustcInternal, +{ + // The tcx argument ensures that the item won't outlive the type context. + with_tables(|tables| item.internal(tables, tcx)) } impl<'tcx> Index for Tables<'tcx> { @@ -162,12 +188,12 @@ where /// Loads the current context and calls a function with it. /// Do not nest these, as that will ICE. -pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R { +pub(crate) fn with_tables(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) -> R { assert!(TLV.is_set()); TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - let wrapper = ptr as *const TablesWrapper<'tcx>; + let wrapper = ptr as *const TablesWrapper<'_>; let mut tables = unsafe { (*wrapper).0.borrow_mut() }; f(&mut *tables) }) @@ -393,7 +419,7 @@ impl Index { - type T; - fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T; +pub trait RustcInternal { + type T<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx>; } diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 48cb164c308a7..5d02e3d6e9213 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -27,7 +27,8 @@ pub fn new_allocation<'tcx>( const_value: ConstValue<'tcx>, tables: &mut Tables<'tcx>, ) -> Allocation { - try_new_allocation(ty, const_value, tables).unwrap() + try_new_allocation(ty, const_value, tables) + .expect(&format!("Failed to convert: {const_value:?} to {ty:?}")) } #[allow(rustc::usage_of_qualified_ty)] diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index fffc454804d29..94a1fb33f99c5 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -29,7 +29,7 @@ use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, S use std::cell::RefCell; use std::iter; -use crate::rustc_internal::{internal, RustcInternal}; +use crate::rustc_internal::RustcInternal; use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables}; @@ -74,9 +74,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); - tables - .tcx - .traits(crate_num.internal(&mut *tables)) + let tcx = tables.tcx; + tcx.traits(crate_num.internal(&mut *tables, tcx)) .iter() .map(|trait_def_id| tables.trait_def(*trait_def_id)) .collect() @@ -101,9 +100,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls { let mut tables = self.0.borrow_mut(); - tables - .tcx - .trait_impls_in_crate(crate_num.internal(&mut *tables)) + let tcx = tables.tcx; + tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx)) .iter() .map(|impl_def_id| tables.impl_def(*impl_def_id)) .collect() @@ -229,57 +227,68 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn adt_kind(&self, def: AdtDef) -> AdtKind { let mut tables = self.0.borrow_mut(); - def.internal(&mut *tables).adt_kind().stable(&mut *tables) + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables) } fn adt_is_box(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); - def.internal(&mut *tables).is_box() + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).is_box() } fn adt_is_simd(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); - def.internal(&mut *tables).repr().simd() + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).repr().simd() } fn adt_is_cstr(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); - let def_id = def.0.internal(&mut *tables); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); tables.tcx.lang_items().c_str() == Some(def_id) } fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); - let def_id = def.0.internal(&mut *tables); - let sig = tables.tcx.fn_sig(def_id).instantiate(tables.tcx, args.internal(&mut *tables)); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); + let sig = + tables.tcx.fn_sig(def_id).instantiate(tables.tcx, args.internal(&mut *tables, tcx)); sig.stable(&mut *tables) } fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); - let args_ref = args.internal(&mut *tables); + let tcx = tables.tcx; + let args_ref = args.internal(&mut *tables, tcx); let sig = args_ref.as_closure().sig(); sig.stable(&mut *tables) } fn adt_variants_len(&self, def: AdtDef) -> usize { let mut tables = self.0.borrow_mut(); - def.internal(&mut *tables).variants().len() + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).variants().len() } fn variant_name(&self, def: VariantDef) -> Symbol { let mut tables = self.0.borrow_mut(); - def.internal(&mut *tables).name.to_string() + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).name.to_string() } fn variant_fields(&self, def: VariantDef) -> Vec { let mut tables = self.0.borrow_mut(); - def.internal(&mut *tables).fields.iter().map(|f| f.stable(&mut *tables)).collect() + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect() } fn eval_target_usize(&self, cnst: &Const) -> Result { let mut tables = self.0.borrow_mut(); - let mir_const = cnst.internal(&mut *tables); + let tcx = tables.tcx; + let mir_const = cnst.internal(&mut *tables, tcx); mir_const .try_eval_target_usize(tables.tcx, ParamEnv::empty()) .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) @@ -299,30 +308,36 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); - let internal_kind = kind.internal(&mut *tables); + let tcx = tables.tcx; + let internal_kind = kind.internal(&mut *tables, tcx); tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables) } fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); - let inner = ty.internal(&mut *tables); + let tcx = tables.tcx; + let inner = ty.internal(&mut *tables, tcx); ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables) } fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); - tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables) + let tcx = tables.tcx; + tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables) } fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); - let args = args.internal(&mut *tables); - let def_ty = tables.tcx.type_of(item.internal(&mut *tables)); + let tcx = tables.tcx; + let args = args.internal(&mut *tables, tcx); + let def_ty = tables.tcx.type_of(item.internal(&mut *tables, tcx)); def_ty.instantiate(tables.tcx, args).stable(&mut *tables) } fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { - internal(cnst).to_string() + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + cnst.internal(&mut *tables, tcx).to_string() } fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { @@ -337,7 +352,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); - let internal_kind = ty.internal(&mut *tables); + let tcx = tables.tcx; + let internal_kind = ty.internal(&mut *tables, tcx); let internal_ty = tables.tcx.mk_ty_from_kind(internal_kind); internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables) } @@ -407,8 +423,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { args: &stable_mir::ty::GenericArgs, ) -> Option { let mut tables = self.0.borrow_mut(); - let def_id = def.0.internal(&mut *tables); - let args_ref = args.internal(&mut *tables); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); + let args_ref = args.internal(&mut *tables, tcx); match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { Ok(Some(instance)) => Some(instance.stable(&mut *tables)), Ok(None) | Err(_) => None, @@ -417,7 +434,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); - let internal_ty = ty.internal(&mut *tables); + let tcx = tables.tcx; + let internal_ty = ty.internal(&mut *tables, tcx); let instance = Instance::resolve_drop_in_place(tables.tcx, internal_ty); instance.stable(&mut *tables) } @@ -428,8 +446,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { args: &GenericArgs, ) -> Option { let mut tables = self.0.borrow_mut(); - let def_id = def.0.internal(&mut *tables); - let args_ref = args.internal(&mut *tables); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); + let args_ref = args.internal(&mut *tables, tcx); Instance::resolve_for_fn_ptr(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) .stable(&mut *tables) } @@ -441,36 +460,47 @@ impl<'tcx> Context for TablesWrapper<'tcx> { kind: ClosureKind, ) -> Option { let mut tables = self.0.borrow_mut(); - let def_id = def.0.internal(&mut *tables); - let args_ref = args.internal(&mut *tables); - let closure_kind = kind.internal(&mut *tables); - Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables) + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); + let args_ref = args.internal(&mut *tables, tcx); + let closure_kind = kind.internal(&mut *tables, tcx); + Some( + Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind) + .stable(&mut *tables), + ) } fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; - let result = tables.tcx.const_eval_instance( + let tcx = tables.tcx; + let result = tcx.const_eval_instance( ParamEnv::reveal_all(), instance, - Some(tables.tcx.def_span(instance.def_id())), + Some(tcx.def_span(instance.def_id())), ); result .map(|const_val| { - alloc::try_new_allocation(const_ty.internal(&mut *tables), const_val, &mut *tables) + alloc::try_new_allocation( + const_ty.internal(&mut *tables, tcx), + const_val, + &mut *tables, + ) }) .map_err(|e| e.stable(&mut *tables))? } fn eval_static_initializer(&self, def: StaticDef) -> Result { let mut tables = self.0.borrow_mut(); - let def_id = def.0.internal(&mut *tables); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); tables.tcx.eval_static_initializer(def_id).stable(&mut *tables) } fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { let mut tables = self.0.borrow_mut(); - let alloc_id = alloc.internal(&mut *tables); + let tcx = tables.tcx; + let alloc_id = alloc.internal(&mut *tables, tcx); tables.tcx.global_alloc(alloc_id).stable(&mut *tables) } @@ -480,9 +510,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) -> Option { let mut tables = self.0.borrow_mut(); let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else { return None }; - let alloc_id = tables - .tcx - .vtable_allocation((ty.internal(&mut *tables), trait_ref.internal(&mut *tables))); + let tcx = tables.tcx; + let alloc_id = tables.tcx.vtable_allocation(( + ty.internal(&mut *tables, tcx), + trait_ref.internal(&mut *tables, tcx), + )); Some(alloc_id.stable(&mut *tables)) } @@ -510,14 +542,16 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn ty_layout(&self, ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); - let ty = ty.internal(&mut *tables); + let tcx = tables.tcx; + let ty = ty.internal(&mut *tables, tcx); let layout = tables.layout_of(ty)?.layout; Ok(layout.stable(&mut *tables)) } fn layout_shape(&self, id: Layout) -> LayoutShape { let mut tables = self.0.borrow_mut(); - id.internal(&mut *tables).0.stable(&mut *tables) + let tcx = tables.tcx; + id.internal(&mut *tables, tcx).0.stable(&mut *tables) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 632e97b32f520..088a836c90182 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -14,7 +14,7 @@ use stable_mir::{opaque, Opaque}; impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { type T = VariantIdx; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { VariantIdx::to_val(self.as_usize()) } } @@ -22,7 +22,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { impl<'tcx> Stable<'tcx> for rustc_abi::Endian { type T = stable_mir::target::Endian; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { rustc_abi::Endian::Little => stable_mir::target::Endian::Little, rustc_abi::Endian::Big => stable_mir::target::Endian::Big, @@ -33,7 +33,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Endian { impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { type T = TyAndLayout; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) } } } @@ -41,8 +41,8 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { type T = Layout; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.layout_id(*self) + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + tables.layout_id(tables.tcx.lift(*self).unwrap()) } } @@ -51,7 +51,7 @@ impl<'tcx> Stable<'tcx> { type T = LayoutShape; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { LayoutShape { fields: self.fields.stable(tables), variants: self.variants.stable(tables), @@ -65,7 +65,7 @@ impl<'tcx> Stable<'tcx> impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { type T = FnAbi; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { assert!(self.args.len() >= self.fixed_count as usize); assert!(!self.c_variadic || matches!(self.conv, Conv::C)); FnAbi { @@ -81,7 +81,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> { type T = ArgAbi; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { ArgAbi { ty: self.layout.ty.stable(tables), layout: self.layout.layout.stable(tables), @@ -93,7 +93,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { type T = CallConvention; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { Conv::C => CallConvention::C, Conv::Rust => CallConvention::Rust, @@ -111,7 +111,6 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { Conv::X86VectorCall => CallConvention::X86VectorCall, Conv::X86_64SysV => CallConvention::X86_64SysV, Conv::X86_64Win64 => CallConvention::X86_64Win64, - Conv::AmdGpuKernel => CallConvention::AmdGpuKernel, Conv::AvrInterrupt => CallConvention::AvrInterrupt, Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt, Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt, @@ -122,7 +121,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode { type T = PassMode; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore, rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), @@ -146,7 +145,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode { impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape { type T = FieldsShape; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive, rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count), @@ -165,7 +164,7 @@ impl<'tcx> Stable<'tcx> { type T = VariantsShape; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { rustc_abi::Variants::Single { index } => { VariantsShape::Single { index: index.stable(tables) } @@ -185,7 +184,7 @@ impl<'tcx> Stable<'tcx> impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding { type T = TagEncoding; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { rustc_abi::TagEncoding::Direct => TagEncoding::Direct, rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => { @@ -202,7 +201,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding Stable<'tcx> for rustc_abi::Abi { type T = ValueAbi; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match *self { rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited, rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), @@ -220,7 +219,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Abi { impl<'tcx> Stable<'tcx> for rustc_abi::Size { type T = Size; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { self.bytes_usize() } } @@ -228,7 +227,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Size { impl<'tcx> Stable<'tcx> for rustc_abi::Align { type T = Align; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { self.bytes() } } @@ -236,7 +235,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Align { impl<'tcx> Stable<'tcx> for rustc_abi::Scalar { type T = Opaque; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { opaque(self) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/error.rs b/compiler/rustc_smir/src/rustc_smir/convert/error.rs index 6c582b799f867..8298450f741fb 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/error.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/error.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::LayoutError; impl<'tcx> Stable<'tcx> for LayoutError<'tcx> { type T = stable_mir::Error; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { stable_mir::Error::new(format!("{self:?}")) } } @@ -16,7 +16,7 @@ impl<'tcx> Stable<'tcx> for LayoutError<'tcx> { impl<'tcx> Stable<'tcx> for AllocError { type T = stable_mir::Error; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { stable_mir::Error::new(format!("{self:?}")) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index a9fd23d8143f7..777dcec45048b 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -13,7 +13,7 @@ use crate::rustc_smir::{alloc, Stable, Tables}; impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { type T = stable_mir::mir::Body; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::mir::Body::new( self.basic_blocks .iter() @@ -44,7 +44,7 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> { type T = stable_mir::mir::VarDebugInfo; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::mir::VarDebugInfo { name: self.name.to_string(), source_info: self.source_info.stable(tables), @@ -57,21 +57,21 @@ impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> { impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { Statement { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) } } } impl<'tcx> Stable<'tcx> for mir::SourceInfo { type T = stable_mir::mir::SourceInfo; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::mir::SourceInfo { span: self.span.stable(tables), scope: self.scope.into() } } } impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> { type T = stable_mir::mir::VarDebugInfoFragment; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { VarDebugInfoFragment { ty: self.ty.stable(tables), projection: self.projection.iter().map(|e| e.stable(tables)).collect(), @@ -81,7 +81,7 @@ impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> { impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> { type T = stable_mir::mir::VarDebugInfoContents; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { mir::VarDebugInfoContents::Place(place) => { stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables)) @@ -100,7 +100,7 @@ impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> { impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { type T = stable_mir::mir::StatementKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { mir::StatementKind::Assign(assign) => stable_mir::mir::StatementKind::Assign( assign.0.stable(tables), @@ -158,7 +158,7 @@ impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { type T = stable_mir::mir::Rvalue; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::Rvalue::*; match self { Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)), @@ -214,7 +214,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { impl<'tcx> Stable<'tcx> for mir::Mutability { type T = stable_mir::mir::Mutability; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_hir::Mutability::*; match *self { Not => stable_mir::mir::Mutability::Not, @@ -225,7 +225,7 @@ impl<'tcx> Stable<'tcx> for mir::Mutability { impl<'tcx> Stable<'tcx> for mir::BorrowKind { type T = stable_mir::mir::BorrowKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::BorrowKind::*; match *self { Shared => stable_mir::mir::BorrowKind::Shared, @@ -237,7 +237,7 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind { impl<'tcx> Stable<'tcx> for mir::MutBorrowKind { type T = stable_mir::mir::MutBorrowKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::MutBorrowKind::*; match *self { Default => stable_mir::mir::MutBorrowKind::Default, @@ -249,7 +249,7 @@ impl<'tcx> Stable<'tcx> for mir::MutBorrowKind { impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { type T = stable_mir::mir::NullOp; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::NullOp::*; match self { SizeOf => stable_mir::mir::NullOp::SizeOf, @@ -263,7 +263,7 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { impl<'tcx> Stable<'tcx> for mir::CastKind { type T = stable_mir::mir::CastKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::CastKind::*; match self { PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress, @@ -283,7 +283,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind { impl<'tcx> Stable<'tcx> for mir::FakeReadCause { type T = stable_mir::mir::FakeReadCause; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::FakeReadCause::*; match self { ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard, @@ -299,7 +299,7 @@ impl<'tcx> Stable<'tcx> for mir::FakeReadCause { impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { type T = stable_mir::mir::Operand; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::Operand::*; match self { Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables)), @@ -312,7 +312,7 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { type T = stable_mir::mir::Constant; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::mir::Constant { span: self.span.stable(tables), user_ty: self.user_ty.map(|u| u.as_usize()).or(None), @@ -323,7 +323,7 @@ impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { type T = stable_mir::mir::Place; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::mir::Place { local: self.local.as_usize(), projection: self.projection.iter().map(|e| e.stable(tables)).collect(), @@ -333,7 +333,7 @@ impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { type T = stable_mir::mir::ProjectionElem; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::ProjectionElem::*; match self { Deref => stable_mir::mir::ProjectionElem::Deref, @@ -368,21 +368,21 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { type T = stable_mir::mir::UserTypeProjection; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { UserTypeProjection { base: self.base.as_usize(), projection: opaque(&self.projs) } } } impl<'tcx> Stable<'tcx> for mir::Local { type T = stable_mir::mir::Local; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { self.as_usize() } } impl<'tcx> Stable<'tcx> for mir::RetagKind { type T = stable_mir::mir::RetagKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::RetagKind; match self { RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry, @@ -395,7 +395,7 @@ impl<'tcx> Stable<'tcx> for mir::RetagKind { impl<'tcx> Stable<'tcx> for mir::UnwindAction { type T = stable_mir::mir::UnwindAction; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::UnwindAction; match self { UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue, @@ -409,7 +409,7 @@ impl<'tcx> Stable<'tcx> for mir::UnwindAction { impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> { type T = stable_mir::mir::NonDivergingIntrinsic; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::NonDivergingIntrinsic; use stable_mir::mir::CopyNonOverlapping; match self { @@ -441,7 +441,7 @@ impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> { impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { type T = stable_mir::mir::AssertMessage; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::AssertKind; match self { AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck { @@ -480,7 +480,7 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { impl<'tcx> Stable<'tcx> for mir::BinOp { type T = stable_mir::mir::BinOp; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::BinOp; match self { BinOp::Add => stable_mir::mir::BinOp::Add, @@ -511,7 +511,7 @@ impl<'tcx> Stable<'tcx> for mir::BinOp { impl<'tcx> Stable<'tcx> for mir::UnOp { type T = stable_mir::mir::UnOp; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::UnOp; match self { UnOp::Not => stable_mir::mir::UnOp::Not, @@ -522,7 +522,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp { impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { type T = stable_mir::mir::AggregateKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { mir::AggregateKind::Array(ty) => { stable_mir::mir::AggregateKind::Array(ty.stable(tables)) @@ -550,13 +550,16 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { tables.tcx.coroutine_movability(*def_id).stable(tables), ) } + mir::AggregateKind::CoroutineClosure(..) => { + todo!("FIXME(async_closures): Lower these to SMIR") + } } } } impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { type T = stable_mir::mir::InlineAsmOperand; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::InlineAsmOperand; let (in_value, out_place) = match self { @@ -576,7 +579,7 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { type T = stable_mir::mir::Terminator; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::mir::Terminator; Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) } } @@ -584,7 +587,7 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { type T = stable_mir::mir::TerminatorKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::mir::TerminatorKind; match self { mir::TerminatorKind::Goto { target } => { @@ -661,7 +664,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> { type T = Allocation; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { self.inner().stable(tables) } } @@ -669,7 +672,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> { impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { type T = stable_mir::ty::Allocation; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { alloc::allocation_filter( self, alloc_range(rustc_target::abi::Size::ZERO, self.size()), @@ -680,7 +683,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { impl<'tcx> Stable<'tcx> for mir::interpret::AllocId { type T = stable_mir::mir::alloc::AllocId; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { tables.create_alloc_id(*self) } } @@ -688,7 +691,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::AllocId { impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { type T = GlobalAlloc; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { mir::interpret::GlobalAlloc::Function(instance) => { GlobalAlloc::Function(instance.stable(tables)) @@ -707,7 +710,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { type T = stable_mir::ty::Const; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match *self { mir::Const::Ty(c) => c.stable(tables), mir::Const::Unevaluated(unev_const, ty) => { @@ -718,18 +721,20 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { promoted: unev_const.promoted.map(|u| u.as_u32()), }); let ty = ty.stable(tables); - let id = tables.intern_const(*self); + let id = tables.intern_const(tables.tcx.lift(*self).unwrap()); Const::new(kind, ty, id) } mir::Const::Val(mir::ConstValue::ZeroSized, ty) => { let ty = ty.stable(tables); - let id = tables.intern_const(*self); + let id = tables.intern_const(tables.tcx.lift(*self).unwrap()); Const::new(ConstantKind::ZeroSized, ty, id) } mir::Const::Val(val, ty) => { + let ty = tables.tcx.lift(ty).unwrap(); + let val = tables.tcx.lift(val).unwrap(); let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables)); let ty = ty.stable(tables); - let id = tables.intern_const(*self); + let id = tables.intern_const(tables.tcx.lift(*self).unwrap()); Const::new(kind, ty, id) } } @@ -739,7 +744,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled { type T = Error; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { Error::new(format!("{self:?}")) } } @@ -747,7 +752,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled { impl<'tcx> Stable<'tcx> for MonoItem<'tcx> { type T = stable_mir::mir::mono::MonoItem; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::mir::mono::MonoItem as StableMonoItem; match self { MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)), diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 2446671770ecb..41b0a84dd80f1 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -11,7 +11,7 @@ mod ty; impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety { type T = stable_mir::mir::Safety; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe, rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal, @@ -21,14 +21,14 @@ impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety { impl<'tcx> Stable<'tcx> for FieldIdx { type T = usize; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { self.as_usize() } } impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource { type T = stable_mir::mir::CoroutineSource; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_hir::CoroutineSource; match self { CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block, @@ -40,7 +40,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource { impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { type T = stable_mir::mir::CoroutineKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_hir::{CoroutineDesugaring, CoroutineKind}; match *self { CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => { @@ -71,7 +71,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { impl<'tcx> Stable<'tcx> for rustc_span::Symbol { type T = stable_mir::Symbol; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { self.to_string() } } @@ -79,7 +79,7 @@ impl<'tcx> Stable<'tcx> for rustc_span::Symbol { impl<'tcx> Stable<'tcx> for rustc_span::Span { type T = stable_mir::ty::Span; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { tables.create_span(*self) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index c0ecbfb991413..959a17d24b7ce 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -11,7 +11,7 @@ use crate::rustc_smir::{alloc, Stable, Tables}; impl<'tcx> Stable<'tcx> for ty::AliasKind { type T = stable_mir::ty::AliasKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::Projection => stable_mir::ty::AliasKind::Projection, ty::Inherent => stable_mir::ty::AliasKind::Inherent, @@ -23,7 +23,7 @@ impl<'tcx> Stable<'tcx> for ty::AliasKind { impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> { type T = stable_mir::ty::AliasTy; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::AliasTy { args, def_id, .. } = self; stable_mir::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables) } } @@ -32,7 +32,7 @@ impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> { impl<'tcx> Stable<'tcx> for ty::DynKind { type T = stable_mir::ty::DynKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::Dyn => stable_mir::ty::DynKind::Dyn, ty::DynStar => stable_mir::ty::DynKind::DynStar, @@ -43,7 +43,7 @@ impl<'tcx> Stable<'tcx> for ty::DynKind { impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> { type T = stable_mir::ty::ExistentialPredicate; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::ExistentialPredicate::*; match self { ty::ExistentialPredicate::Trait(existential_trait_ref) => { @@ -60,7 +60,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> { impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { type T = stable_mir::ty::ExistentialTraitRef; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::ExistentialTraitRef { def_id, args } = self; stable_mir::ty::ExistentialTraitRef { def_id: tables.trait_def(*def_id), @@ -72,7 +72,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> { type T = stable_mir::ty::TermKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::TermKind; match self { ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)), @@ -87,7 +87,7 @@ impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> { impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { type T = stable_mir::ty::ExistentialProjection; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::ExistentialProjection { def_id, args, term } = self; stable_mir::ty::ExistentialProjection { def_id: tables.trait_def(*def_id), @@ -99,7 +99,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion { type T = stable_mir::mir::PointerCoercion; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::ty::adjustment::PointerCoercion; match self { PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer, @@ -118,7 +118,7 @@ impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion { impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex { type T = usize; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { self.as_usize() } } @@ -126,7 +126,7 @@ impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex { impl<'tcx> Stable<'tcx> for ty::AdtKind { type T = AdtKind; - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { ty::AdtKind::Struct => AdtKind::Struct, ty::AdtKind::Union => AdtKind::Union, @@ -138,7 +138,7 @@ impl<'tcx> Stable<'tcx> for ty::AdtKind { impl<'tcx> Stable<'tcx> for ty::FieldDef { type T = stable_mir::ty::FieldDef; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::ty::FieldDef { def: tables.create_def_id(self.did), name: self.name.stable(tables), @@ -148,7 +148,7 @@ impl<'tcx> Stable<'tcx> for ty::FieldDef { impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { type T = stable_mir::ty::GenericArgs; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect()) } } @@ -156,7 +156,7 @@ impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> { type T = stable_mir::ty::GenericArgKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::GenericArgKind; match self { ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)), @@ -172,7 +172,7 @@ where { type T = stable_mir::ty::Binder; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::Binder; Binder { @@ -192,7 +192,7 @@ where { type T = stable_mir::ty::EarlyBinder; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::EarlyBinder; EarlyBinder { value: self.as_ref().skip_binder().stable(tables) } @@ -201,7 +201,7 @@ where impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { type T = stable_mir::ty::FnSig; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_target::spec::abi; use stable_mir::ty::{Abi, FnSig}; @@ -223,7 +223,6 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { abi::Abi::PtxKernel => Abi::PtxKernel, abi::Abi::Msp430Interrupt => Abi::Msp430Interrupt, abi::Abi::X86Interrupt => Abi::X86Interrupt, - abi::Abi::AmdGpuKernel => Abi::AmdGpuKernel, abi::Abi::EfiApi => Abi::EfiApi, abi::Abi::AvrInterrupt => Abi::AvrInterrupt, abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, @@ -245,7 +244,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { impl<'tcx> Stable<'tcx> for ty::BoundTyKind { type T = stable_mir::ty::BoundTyKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::BoundTyKind; match self { @@ -260,7 +259,7 @@ impl<'tcx> Stable<'tcx> for ty::BoundTyKind { impl<'tcx> Stable<'tcx> for ty::BoundRegionKind { type T = stable_mir::ty::BoundRegionKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::BoundRegionKind; match self { @@ -276,7 +275,7 @@ impl<'tcx> Stable<'tcx> for ty::BoundRegionKind { impl<'tcx> Stable<'tcx> for ty::BoundVariableKind { type T = stable_mir::ty::BoundVariableKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::BoundVariableKind; match self { @@ -294,7 +293,7 @@ impl<'tcx> Stable<'tcx> for ty::BoundVariableKind { impl<'tcx> Stable<'tcx> for ty::IntTy { type T = IntTy; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::IntTy::Isize => IntTy::Isize, ty::IntTy::I8 => IntTy::I8, @@ -309,7 +308,7 @@ impl<'tcx> Stable<'tcx> for ty::IntTy { impl<'tcx> Stable<'tcx> for ty::UintTy { type T = UintTy; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::UintTy::Usize => UintTy::Usize, ty::UintTy::U8 => UintTy::U8, @@ -324,7 +323,7 @@ impl<'tcx> Stable<'tcx> for ty::UintTy { impl<'tcx> Stable<'tcx> for ty::FloatTy { type T = FloatTy; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::FloatTy::F32 => FloatTy::F32, ty::FloatTy::F64 => FloatTy::F64, @@ -334,14 +333,14 @@ impl<'tcx> Stable<'tcx> for ty::FloatTy { impl<'tcx> Stable<'tcx> for Ty<'tcx> { type T = stable_mir::ty::Ty; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - tables.intern_ty(*self) + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + tables.intern_ty(tables.tcx.lift(*self).unwrap()) } } impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { type T = stable_mir::ty::TyKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { ty::Bool => TyKind::RigidTy(RigidTy::Bool), ty::Char => TyKind::RigidTy(RigidTy::Char), @@ -384,6 +383,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { tables.closure_def(*def_id), generic_args.stable(tables), )), + ty::CoroutineClosure(..) => todo!("FIXME(async_closures): Lower these to SMIR"), ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine( tables.coroutine_def(*def_id), generic_args.stable(tables), @@ -414,17 +414,22 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { type T = stable_mir::ty::Const; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let kind = match self.kind() { ty::Value(val) => { - let const_val = tables.tcx.valtree_to_const_val((self.ty(), val)); + let val = match val { + ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), + ty::ValTree::Branch(branch) => { + ty::ValTree::Branch(tables.tcx.lift(branch).unwrap()) + } + }; + let ty = tables.tcx.lift(self.ty()).unwrap(); + let const_val = tables.tcx.valtree_to_const_val((ty, val)); if matches!(const_val, mir::ConstValue::ZeroSized) { ConstantKind::ZeroSized } else { stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( - self.ty(), - const_val, - tables, + ty, const_val, tables, )) } } @@ -443,14 +448,14 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { ty::ExprCt(_) => unimplemented!(), }; let ty = self.ty().stable(tables); - let id = tables.intern_const(mir::Const::Ty(*self)); + let id = tables.intern_const(mir::Const::Ty(tables.tcx.lift(*self).unwrap())); Const::new(kind, ty, id) } } impl<'tcx> Stable<'tcx> for ty::ParamConst { type T = stable_mir::ty::ParamConst; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use stable_mir::ty::ParamConst; ParamConst { index: self.index, name: self.name.to_string() } } @@ -458,7 +463,7 @@ impl<'tcx> Stable<'tcx> for ty::ParamConst { impl<'tcx> Stable<'tcx> for ty::ParamTy { type T = stable_mir::ty::ParamTy; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use stable_mir::ty::ParamTy; ParamTy { index: self.index, name: self.name.to_string() } } @@ -466,7 +471,7 @@ impl<'tcx> Stable<'tcx> for ty::ParamTy { impl<'tcx> Stable<'tcx> for ty::BoundTy { type T = stable_mir::ty::BoundTy; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::BoundTy; BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) } } @@ -474,7 +479,7 @@ impl<'tcx> Stable<'tcx> for ty::BoundTy { impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { type T = stable_mir::ty::TraitSpecializationKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use stable_mir::ty::TraitSpecializationKind; match self { @@ -489,7 +494,7 @@ impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { impl<'tcx> Stable<'tcx> for ty::TraitDef { type T = stable_mir::ty::TraitDecl; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::opaque; use stable_mir::ty::TraitDecl; @@ -514,7 +519,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef { impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> { type T = stable_mir::ty::TraitRef; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::TraitRef; TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables)).unwrap() @@ -524,7 +529,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> Stable<'tcx> for ty::Generics { type T = stable_mir::ty::Generics; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::Generics; let params: Vec<_> = self.params.iter().map(|param| param.stable(tables)).collect(); @@ -549,7 +554,7 @@ impl<'tcx> Stable<'tcx> for ty::Generics { impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { type T = stable_mir::ty::GenericParamDefKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use stable_mir::ty::GenericParamDefKind; match self { ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, @@ -566,7 +571,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef { type T = stable_mir::ty::GenericParamDef; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { GenericParamDef { name: self.name.to_string(), def_id: tables.generic_def(self.def_id), @@ -580,7 +585,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef { impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> { type T = stable_mir::ty::PredicateKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::ty::PredicateKind; match self { PredicateKind::Clause(clause_kind) => { @@ -614,7 +619,7 @@ impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> { impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { type T = stable_mir::ty::ClauseKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::ty::ClauseKind; match *self { ClauseKind::Trait(trait_object) => { @@ -650,7 +655,7 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { impl<'tcx> Stable<'tcx> for ty::ClosureKind { type T = stable_mir::ty::ClosureKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::ty::ClosureKind::*; match self { Fn => stable_mir::ty::ClosureKind::Fn, @@ -663,7 +668,7 @@ impl<'tcx> Stable<'tcx> for ty::ClosureKind { impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> { type T = stable_mir::ty::SubtypePredicate; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::SubtypePredicate { a, b, a_is_expected: _ } = self; stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) } } @@ -672,7 +677,7 @@ impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> { impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> { type T = stable_mir::ty::CoercePredicate; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::CoercePredicate { a, b } = self; stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) } } @@ -681,7 +686,7 @@ impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> { impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection { type T = stable_mir::ty::AliasRelationDirection; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::ty::AliasRelationDirection::*; match self { Equate => stable_mir::ty::AliasRelationDirection::Equate, @@ -693,7 +698,7 @@ impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection { impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> { type T = stable_mir::ty::TraitPredicate; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::TraitPredicate { trait_ref, polarity } = self; stable_mir::ty::TraitPredicate { trait_ref: trait_ref.stable(tables), @@ -709,7 +714,7 @@ where { type T = stable_mir::ty::OutlivesPredicate; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::OutlivesPredicate(a, b) = self; stable_mir::ty::OutlivesPredicate(a.stable(tables), b.stable(tables)) } @@ -718,7 +723,7 @@ where impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> { type T = stable_mir::ty::ProjectionPredicate; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::ProjectionPredicate { projection_ty, term } = self; stable_mir::ty::ProjectionPredicate { projection_ty: projection_ty.stable(tables), @@ -730,7 +735,7 @@ impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> { impl<'tcx> Stable<'tcx> for ty::ImplPolarity { type T = stable_mir::ty::ImplPolarity; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { use rustc_middle::ty::ImplPolarity::*; match self { Positive => stable_mir::ty::ImplPolarity::Positive, @@ -743,7 +748,7 @@ impl<'tcx> Stable<'tcx> for ty::ImplPolarity { impl<'tcx> Stable<'tcx> for ty::Region<'tcx> { type T = stable_mir::ty::Region; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { Region { kind: self.kind().stable(tables) } } } @@ -751,7 +756,7 @@ impl<'tcx> Stable<'tcx> for ty::Region<'tcx> { impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> { type T = stable_mir::ty::RegionKind; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::{BoundRegion, EarlyParamRegion, RegionKind}; match self { ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion { @@ -782,8 +787,8 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> { impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { type T = stable_mir::mir::mono::Instance; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - let def = tables.instance_def(*self); + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + let def = tables.instance_def(tables.tcx.lift(*self).unwrap()); let kind = match self.def { ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item, ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, @@ -794,6 +799,8 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrAddrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) @@ -805,7 +812,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { impl<'tcx> Stable<'tcx> for ty::Variance { type T = stable_mir::mir::Variance; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::Variance::Bivariant => stable_mir::mir::Variance::Bivariant, ty::Variance::Contravariant => stable_mir::mir::Variance::Contravariant, @@ -818,7 +825,7 @@ impl<'tcx> Stable<'tcx> for ty::Variance { impl<'tcx> Stable<'tcx> for ty::Movability { type T = stable_mir::ty::Movability; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::Movability::Static => stable_mir::ty::Movability::Static, ty::Movability::Movable => stable_mir::ty::Movability::Movable, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index e1ee40c0b60ee..bd02e52794c0c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -102,11 +102,11 @@ pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind { } /// Trait used to convert between an internal MIR type to a Stable MIR type. -pub trait Stable<'tcx> { +pub trait Stable<'cx> { /// The stable representation of the type implementing Stable. type T; /// Converts an object to the equivalent Stable MIR representation. - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T; + fn stable(&self, tables: &mut Tables<'_>) -> Self::T; } impl<'tcx, T> Stable<'tcx> for &T @@ -115,7 +115,7 @@ where { type T = T::T; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { (*self).stable(tables) } } @@ -126,7 +126,7 @@ where { type T = Option; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { self.as_ref().map(|value| value.stable(tables)) } } @@ -138,7 +138,7 @@ where { type T = Result; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { Ok(val) => Ok(val.stable(tables)), Err(error) => Err(error.stable(tables)), @@ -151,7 +151,7 @@ where T: Stable<'tcx>, { type T = Vec; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { self.iter().map(|e| e.stable(tables)).collect() } } @@ -162,7 +162,7 @@ where U: Stable<'tcx>, { type T = (T::T, U::T); - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { (self.0.stable(tables), self.1.stable(tables)) } } @@ -172,7 +172,7 @@ where T: Stable<'tcx>, { type T = RangeInclusive; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { RangeInclusive::new(self.start().stable(tables), self.end().stable(tables)) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 3d26efec5a654..527938daae410 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1154,6 +1154,8 @@ pub enum DesugaringKind { Await, ForLoop, WhileLoop, + /// `async Fn()` bound modifier + BoundModifier, } impl DesugaringKind { @@ -1169,6 +1171,7 @@ impl DesugaringKind { DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop => "`for` loop", DesugaringKind::WhileLoop => "`while` loop", + DesugaringKind::BoundModifier => "trait bound modifier", } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 65702f76fdac7..ea6766ea583be 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2105,7 +2105,7 @@ fn remove_bom(src: &mut String, normalized_pos: &mut Vec) { /// Replaces `\r\n` with `\n` in-place in `src`. /// -/// Returns error if there's a lone `\r` in the string. +/// Leaves any occurrences of lone `\r` unchanged. fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) { if !src.as_bytes().contains(&b'\r') { return; diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 5788d11ed43ca..51f8aa04e8a7f 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -1,5 +1,7 @@ use super::*; +use rustc_data_structures::sync::FreezeLock; + fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string()); @@ -263,53 +265,6 @@ fn t10() { ); } -/// Returns the span corresponding to the `n`th occurrence of `substring` in `source_text`. -trait SourceMapExtension { - fn span_substr( - &self, - file: &Lrc, - source_text: &str, - substring: &str, - n: usize, - ) -> Span; -} - -impl SourceMapExtension for SourceMap { - fn span_substr( - &self, - file: &Lrc, - source_text: &str, - substring: &str, - n: usize, - ) -> Span { - eprintln!( - "span_substr(file={:?}/{:?}, substring={:?}, n={})", - file.name, file.start_pos, substring, n - ); - let mut i = 0; - let mut hi = 0; - loop { - let offset = source_text[hi..].find(substring).unwrap_or_else(|| { - panic!( - "source_text `{}` does not have {} occurrences of `{}`, only {}", - source_text, n, substring, i - ); - }); - let lo = hi + offset; - hi = lo + substring.len(); - if i == n { - let span = Span::with_root_ctxt( - BytePos(lo as u32 + file.start_pos.0), - BytePos(hi as u32 + file.start_pos.0), - ); - assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); - return span; - } - i += 1; - } - } -} - // Takes a unix-style path and returns a platform specific path. fn path(p: &str) -> PathBuf { path_str(p).into() diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ef5b32e8fd872..acb6d6288ac1d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -167,6 +167,9 @@ symbols! { Break, C, CStr, + CallFuture, + CallMutFuture, + CallOnceFuture, Capture, Center, Cleanup, @@ -246,17 +249,7 @@ symbols! { MutexGuard, N, NonNull, - NonZeroI128, - NonZeroI16, - NonZeroI32, - NonZeroI64, - NonZeroI8, - NonZeroU128, - NonZeroU16, - NonZeroU32, - NonZeroU64, - NonZeroU8, - NonZeroUsize, + NonZero, None, Normal, Ok, @@ -310,7 +303,6 @@ symbols! { Some, SpanCtxt, String, - StructuralEq, StructuralPartialEq, SubdiagnosticMessage, Sync, @@ -329,6 +321,7 @@ symbols! { TyCtxt, TyKind, Unknown, + Upvars, Vec, VecDeque, Wrapper, @@ -425,9 +418,17 @@ symbols! { assume, assume_init, async_await, + async_call, + async_call_mut, + async_call_once, async_closure, + async_fn, async_fn_in_trait, + async_fn_kind_helper, + async_fn_mut, + async_fn_once, async_fn_track_caller, + async_fn_traits, async_for_loop, async_iterator, async_iterator_poll_next, @@ -600,6 +601,7 @@ symbols! { core_panic_macro, coroutine, coroutine_clone, + coroutine_resume, coroutine_state, coroutines, cosf32, @@ -909,6 +911,7 @@ symbols! { io_stderr, io_stdout, irrefutable_let_patterns, + is_val_statically_known, isa_attribute, isize, issue, @@ -1022,11 +1025,13 @@ symbols! { min_const_fn, min_const_generics, min_const_unsafe_fn, + min_exhaustive_patterns, min_specialization, min_type_alias_impl_trait, minnumf32, minnumf64, mips_target_feature, + mir_assume, mir_basic_block, mir_call, mir_cast_transmute, @@ -1153,6 +1158,7 @@ symbols! { offset, offset_of, offset_of_enum, + offset_of_nested, ok_or_else, omit_gdb_pretty_printer_section, on, @@ -1615,7 +1621,6 @@ symbols! { struct_variant, structural_match, structural_peq, - structural_teq, sub, sub_assign, sub_with_overflow, diff --git a/compiler/rustc_symbol_mangling/src/hashed.rs b/compiler/rustc_symbol_mangling/src/hashed.rs new file mode 100644 index 0000000000000..d4cd6161ac040 --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/hashed.rs @@ -0,0 +1,43 @@ +use crate::v0; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; +use rustc_hir::def_id::CrateNum; +use rustc_middle::ty::{Instance, TyCtxt}; + +use std::fmt::Write; + +pub(super) fn mangle<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, + full_mangling_name: impl FnOnce() -> String, +) -> String { + // The symbol of a generic function may be scattered in multiple downstream dylibs. + // If the symbol of a generic function still contains `crate name`, hash conflicts between the + // generic funcion and other symbols of the same `crate` cannot be detected in time during + // construction. This symbol conflict is left over until it occurs during run time. + // In this case, `instantiating-crate name` is used to replace `crate name` can completely + // eliminate the risk of the preceding potential hash conflict. + let crate_num = + if let Some(krate) = instantiating_crate { krate } else { instance.def_id().krate }; + + let mut symbol = "_RNxC".to_string(); + v0::push_ident(tcx.crate_name(crate_num).as_str(), &mut symbol); + + let hash = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + full_mangling_name().hash_stable(&mut hcx, &mut hasher); + hasher.finish::().as_u64() + }); + + push_hash64(hash, &mut symbol); + + symbol +} + +// The hash is encoded based on `base-62` and the final terminator `_` is removed because it does +// not help prevent hash collisions +fn push_hash64(hash: u64, output: &mut String) { + let hash = v0::encode_integer_62(hash); + let hash_len = hash.len(); + let _ = write!(output, "{hash_len}H{}", &hash[..hash_len - 1]); +} diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 4a5f58443bc29..646649293fc76 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -64,16 +64,29 @@ pub(super) fn mangle<'tcx>( ) .unwrap(); - if let ty::InstanceDef::ThreadLocalShim(..) = instance.def { - let _ = printer.write_str("{{tls-shim}}"); - } - - if let ty::InstanceDef::VTableShim(..) = instance.def { - let _ = printer.write_str("{{vtable-shim}}"); - } - - if let ty::InstanceDef::ReifyShim(..) = instance.def { - let _ = printer.write_str("{{reify-shim}}"); + match instance.def { + ty::InstanceDef::ThreadLocalShim(..) => { + printer.write_str("{{tls-shim}}").unwrap(); + } + ty::InstanceDef::VTableShim(..) => { + printer.write_str("{{vtable-shim}}").unwrap(); + } + ty::InstanceDef::ReifyShim(..) => { + printer.write_str("{{reify-shim}}").unwrap(); + } + // FIXME(async_closures): This shouldn't be needed when we fix + // `Instance::ty`/`Instance::def_id`. + ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } + | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { + ty::ClosureKind::Fn => unreachable!(), + ty::ClosureKind::FnMut => { + printer.write_str("{{fn-mut-shim}}").unwrap(); + } + ty::ClosureKind::FnOnce => { + printer.write_str("{{fn-once-shim}}").unwrap(); + } + }, + _ => {} } printer.path.finish(hash) @@ -211,6 +224,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args), // The `pretty_print_type` formatting of array size depends on @@ -281,7 +295,11 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { // Similar to `pretty_path_qualified`, but for the other // types that are printed as paths (see `print_type` above). match self_ty.kind() { - ty::FnDef(..) | ty::Alias(..) | ty::Closure(..) | ty::Coroutine(..) + ty::FnDef(..) + | ty::Alias(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) if trait_ref.is_none() => { self.print_type(self_ty) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 8c035ba948b15..362aaca63642e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -91,8 +91,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![feature(never_type)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -111,6 +109,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; +mod hashed; mod legacy; mod v0; @@ -265,6 +264,9 @@ fn compute_symbol_name<'tcx>( let symbol = match mangling_version { SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || { + v0::mangle(tcx, instance, instantiating_crate) + }), }; debug_assert!( diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 0cc82ac7506cb..9d1b92e106803 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -628,7 +628,9 @@ fn encode_ty<'tcx>( } // Function types - ty::FnDef(def_id, args) | ty::Closure(def_id, args) => { + ty::FnDef(def_id, args) + | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) => { // u[IE], where is , // as vendor extended type. let mut s = String::new(); @@ -895,6 +897,10 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, options)); } + ty::CoroutineClosure(def_id, args) => { + ty = Ty::new_coroutine_closure(tcx, *def_id, transform_args(tcx, args, options)); + } + ty::Coroutine(def_id, args) => { ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options)); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index e89a640767f22..530221555c52e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -46,6 +46,13 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), + ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } + | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { + ty::ClosureKind::Fn => unreachable!(), + ty::ClosureKind::FnMut => Some("fn_mut"), + ty::ClosureKind::FnOnce => Some("fn_once"), + }, + _ => None, }; @@ -116,10 +123,7 @@ impl<'tcx> SymbolMangler<'tcx> { /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. fn push_integer_62(&mut self, x: u64) { - if let Some(x) = x.checked_sub(1) { - base_n::push_str(x as u128, 62, &mut self.out); - } - self.push("_"); + push_integer_62(x, &mut self.out) } /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: @@ -138,45 +142,7 @@ impl<'tcx> SymbolMangler<'tcx> { } fn push_ident(&mut self, ident: &str) { - let mut use_punycode = false; - for b in ident.bytes() { - match b { - b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} - 0x80..=0xff => use_punycode = true, - _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), - } - } - - let punycode_string; - let ident = if use_punycode { - self.push("u"); - - // FIXME(eddyb) we should probably roll our own punycode implementation. - let mut punycode_bytes = match punycode::encode(ident) { - Ok(s) => s.into_bytes(), - Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), - }; - - // Replace `-` with `_`. - if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { - *c = b'_'; - } - - // FIXME(eddyb) avoid rechecking UTF-8 validity. - punycode_string = String::from_utf8(punycode_bytes).unwrap(); - &punycode_string - } else { - ident - }; - - let _ = write!(self.out, "{}", ident.len()); - - // Write a separating `_` if necessary (leading digit or `_`). - if let Some('_' | '0'..='9') = ident.chars().next() { - self.push("_"); - } - - self.push(ident); + push_ident(ident, &mut self.out) } fn path_append_ns( @@ -427,6 +393,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) | ty::Coroutine(def_id, args) => { self.print_def_path(def_id, args)?; } @@ -836,3 +803,62 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { Ok(()) } } +/// Push a `_`-terminated base 62 integer, using the format +/// specified in the RFC as ``, that is: +/// * `x = 0` is encoded as just the `"_"` terminator +/// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, +/// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. +pub(crate) fn push_integer_62(x: u64, output: &mut String) { + if let Some(x) = x.checked_sub(1) { + base_n::push_str(x as u128, 62, output); + } + output.push('_'); +} + +pub(crate) fn encode_integer_62(x: u64) -> String { + let mut output = String::new(); + push_integer_62(x, &mut output); + output +} + +pub(crate) fn push_ident(ident: &str, output: &mut String) { + let mut use_punycode = false; + for b in ident.bytes() { + match b { + b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} + 0x80..=0xff => use_punycode = true, + _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), + } + } + + let punycode_string; + let ident = if use_punycode { + output.push('u'); + + // FIXME(eddyb) we should probably roll our own punycode implementation. + let mut punycode_bytes = match punycode::encode(ident) { + Ok(s) => s.into_bytes(), + Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), + }; + + // Replace `-` with `_`. + if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { + *c = b'_'; + } + + // FIXME(eddyb) avoid rechecking UTF-8 validity. + punycode_string = String::from_utf8(punycode_bytes).unwrap(); + &punycode_string + } else { + ident + }; + + let _ = write!(output, "{}", ident.len()); + + // Write a separating `_` if necessary (leading digit or `_`). + if let Some('_' | '0'..='9') = ident.chars().next() { + output.push('_'); + } + + output.push_str(ident); +} diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 1c83039047e05..db721212f8e91 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -705,7 +705,6 @@ pub enum Conv { X86_64SysV, X86_64Win64, - AmdGpuKernel, AvrInterrupt, AvrNonBlockingInterrupt, @@ -887,7 +886,6 @@ impl FromStr for Conv { "X86VectorCall" => Ok(Conv::X86VectorCall), "X86_64SysV" => Ok(Conv::X86_64SysV), "X86_64Win64" => Ok(Conv::X86_64Win64), - "AmdGpuKernel" => Ok(Conv::AmdGpuKernel), "AvrInterrupt" => Ok(Conv::AvrInterrupt), "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt), "RiscvInterrupt(machine)" => { diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index c613514908141..f3aecaaab984f 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -110,7 +110,6 @@ impl ToJson for crate::abi::call::Conv { Self::X86VectorCall => "X86VectorCall", Self::X86_64SysV => "X86_64SysV", Self::X86_64Win64 => "X86_64Win64", - Self::AmdGpuKernel => "AmdGpuKernel", Self::AvrInterrupt => "AvrInterrupt", Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt", Self::RiscvInterrupt { kind } => { diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 257c6777996fc..bffb3681f1309 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -11,12 +11,10 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(assert_matches)] -#![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(min_specialization)] -#![feature(never_type)] #![feature(rustc_attrs)] #![feature(step_trait)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index 1a0aa6f0c4a2e..6231787bb9fdb 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -44,7 +44,6 @@ pub enum Abi { PtxKernel, Msp430Interrupt, X86Interrupt, - AmdGpuKernel, EfiApi, AvrInterrupt, AvrNonBlockingInterrupt, @@ -121,7 +120,6 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" }, AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" }, AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" }, - AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel" }, AbiData { abi: Abi::EfiApi, name: "efiapi" }, AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" }, AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" }, @@ -237,10 +235,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_x86_interrupt, explain: "x86-interrupt ABI is experimental and subject to change", }), - "amdgpu-kernel" => Err(AbiDisabled::Unstable { - feature: sym::abi_amdgpu_kernel, - explain: "amdgpu-kernel ABI is experimental and subject to change", - }), "avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable { feature: sym::abi_avr_interrupt, explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change", @@ -295,22 +289,21 @@ impl Abi { PtxKernel => 19, Msp430Interrupt => 20, X86Interrupt => 21, - AmdGpuKernel => 22, - EfiApi => 23, - AvrInterrupt => 24, - AvrNonBlockingInterrupt => 25, - CCmseNonSecureCall => 26, - Wasm => 27, + EfiApi => 22, + AvrInterrupt => 23, + AvrNonBlockingInterrupt => 24, + CCmseNonSecureCall => 25, + Wasm => 26, // Cross-platform ABIs - System { unwind: false } => 28, - System { unwind: true } => 29, - RustIntrinsic => 30, - RustCall => 31, - PlatformIntrinsic => 32, - Unadjusted => 33, - RustCold => 34, - RiscvInterruptM => 35, - RiscvInterruptS => 36, + System { unwind: false } => 27, + System { unwind: true } => 28, + RustIntrinsic => 29, + RustCall => 30, + PlatformIntrinsic => 31, + Unadjusted => 32, + RustCold => 33, + RiscvInterruptM => 34, + RiscvInterruptS => 35, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/base/dragonfly.rs b/compiler/rustc_target/src/spec/base/dragonfly.rs index de2be78179699..3c1846696f7a4 100644 --- a/compiler/rustc_target/src/spec/base/dragonfly.rs +++ b/compiler/rustc_target/src/spec/base/dragonfly.rs @@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, + has_thread_local: true, default_dwarf_version: 2, ..Default::default() } diff --git a/compiler/rustc_target/src/spec/base/freebsd.rs b/compiler/rustc_target/src/spec/base/freebsd.rs index 80b3da8a752d2..c772754aa8ddc 100644 --- a/compiler/rustc_target/src/spec/base/freebsd.rs +++ b/compiler/rustc_target/src/spec/base/freebsd.rs @@ -9,6 +9,7 @@ pub fn opts() -> TargetOptions { crt_static_respected: true, position_independent_executables: true, relro_level: RelroLevel::Full, + has_thread_local: true, abi_return_struct_as_int: true, default_dwarf_version: 2, ..Default::default() diff --git a/compiler/rustc_target/src/spec/base/netbsd.rs b/compiler/rustc_target/src/spec/base/netbsd.rs index be94ea234658f..495e3d10fbccd 100644 --- a/compiler/rustc_target/src/spec/base/netbsd.rs +++ b/compiler/rustc_target/src/spec/base/netbsd.rs @@ -9,6 +9,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, + has_thread_local: true, use_ctors_section: true, default_dwarf_version: 2, ..Default::default() diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 87ade9e58cf45..4b4d2aca26e4a 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -38,9 +38,6 @@ pub fn options() -> TargetOptions { // supposed to be imported and have all other symbols generate errors if // they remain undefined. concat!($prefix, "--allow-undefined"), - // Rust code should never have warnings, and warnings are often - // indicative of bugs, let's prevent them. - concat!($prefix, "--fatal-warnings"), // 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 diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 5d74ebebdf3ff..6c698c5b01dd5 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1597,6 +1597,7 @@ supported_targets! { ("x86_64-unikraft-linux-musl", x86_64_unikraft_linux_musl), ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), + ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf), ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), @@ -2456,7 +2457,6 @@ impl Target { Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", PtxKernel => self.arch == "nvptx64", Msp430Interrupt => self.arch == "msp430", - AmdGpuKernel => self.arch == "amdgcn", RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]), AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr", Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]), diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index 13f8b6b5a0a05..a221538b9022f 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: ios_sim_llvm_target(arch).into(), pointer_width: 32, data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:128-n8:16:32-S128" + i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(64), ..opts("ios", arch) }, diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs index 3ebf4bcf5231d..ea8b919e7480d 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { llvm_target: "i586-pc-unknown".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: TargetOptions { diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs index 8375fa4c0c0fb..574dc658b78c5 100644 --- a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { llvm_target: "i586-unknown-netbsdelf".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: TargetOptions { mcount: "__mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index 59069fe4e3a92..25617b4436cb6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { llvm_target: macos_llvm_target(Arch::I686).into(), pointer_width: 32, data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:128-n8:16:32-S128" + i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), arch: arch.target_arch(), options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs index 79471040f0da2..12ebf0c72f839 100644 --- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { llvm_target: "i686-linux-android".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: TargetOptions { supported_sanitizers: SanitizerSet::ADDRESS, ..base }, diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs index 8d4a39b581143..1181803441437 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-gnu".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:32-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs index bb410cd8caf2f..f4e33b8817887 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-gnu".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:32-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs index 5abc3017bf80c..9f1c8f4676cb3 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs @@ -25,7 +25,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:128-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs index 927b2ab877ddf..d90f481c68cf4 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-freebsd".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs index bc7fd6fbc68cd..330a390c9817d 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-haiku".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs index 6884e078c27e5..c32f7177c1a09 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-hurd-gnu".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs index 3b7be48dbbc56..9bc38a72f4d39 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-linux-gnu".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs index ef58b4fb45881..4a82e0986c72b 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs @@ -25,7 +25,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-linux-musl".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs index 5f3afbe5afdcd..ea72656607e4a 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-netbsdelf".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: TargetOptions { mcount: "__mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs index f44584a10be53..945dc0f896709 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-openbsd".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs index 25315e19cddb8..37d57c1cdf304 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs @@ -80,7 +80,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-windows-gnu".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:32-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs index ec211a710eb07..0830033dc23d1 100644 --- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-gnu".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:32-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs index 7cca2fc6b9f71..534dd6ee54fbb 100644 --- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:128-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index 5b91682e168ab..35ad81dc052bb 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -25,7 +25,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".into(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:128-n8:16:32-a:0:32-S32" + i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs index ee501c5165e0e..30c2295e40210 100644 --- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { llvm_target: "i686-unknown-linux-gnu".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 0f05e7c475a83..cb24e740c86f2 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, Target, TargetOptions}; +use crate::spec::{base, CodeModel, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -7,6 +7,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), arch: "loongarch64".into(), options: TargetOptions { + code_model: Some(CodeModel::Medium), cpu: "generic".into(), features: "+f,+d".into(), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 3b1ea8e206f1c..f448017a2a58d 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Small), + code_model: Some(CodeModel::Medium), ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index ab9300ef9c723..d636c9599a7be 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Small), + code_model: Some(CodeModel::Medium), ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index 06e8f1837637f..0be32cbd77165 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -1,4 +1,6 @@ -use crate::spec::{base, CodeModel, Target, TargetOptions}; +use std::borrow::Cow; + +use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -12,6 +14,7 @@ pub fn target() -> Target { features: "+m,+a,+f,+d,+c".into(), llvm_abiname: "ilp32d".into(), max_atomic_width: Some(32), + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index 722703d2384fe..cfa9990dac9bd 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -1,4 +1,6 @@ -use crate::spec::{base, CodeModel, Target, TargetOptions}; +use std::borrow::Cow; + +use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -12,6 +14,7 @@ pub fn target() -> Target { features: "+m,+a,+f,+d,+c".into(), llvm_abiname: "ilp32d".into(), max_atomic_width: Some(32), + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_musl::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs new file mode 100644 index 0000000000000..bf819de413311 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs @@ -0,0 +1,36 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel}; +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + os: "zkvm".into(), + vendor: "risc0".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + + // Some crates (*cough* crossbeam) assume you have 64 bit + // atomics if the target name is not in a hardcoded list. + // Since zkvm is singlethreaded and all operations are + // atomic, I guess we can just say we support 64-bit + // atomics. + max_atomic_width: Some(64), + atomic_cas: true, + + features: "+m".into(), + executables: true, + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + singlethread: true, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 40e447dbb8362..762197d7217c7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -1,4 +1,6 @@ -use crate::spec::{base, CodeModel, SanitizerSet, Target, TargetOptions}; +use std::borrow::Cow; + +use crate::spec::{base, CodeModel, SanitizerSet, SplitDebuginfo, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -13,6 +15,7 @@ pub fn target() -> Target { llvm_abiname: "lp64d".into(), supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::android::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs index c0969d4e11eb9..e71929a190479 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs @@ -1,4 +1,6 @@ -use crate::spec::{base, CodeModel, Target, TargetOptions}; +use std::borrow::Cow; + +use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -12,6 +14,7 @@ pub fn target() -> Target { features: "+m,+a,+f,+d,+c".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs index 656e260d094d8..8ea28d6b162cc 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs @@ -1,4 +1,6 @@ -use crate::spec::{base, CodeModel, Target, TargetOptions}; +use std::borrow::Cow; + +use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -12,6 +14,7 @@ pub fn target() -> Target { features: "+m,+a,+f,+d,+c".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_musl::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index 394f02ecac495..e9e874297d39b 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -5,10 +5,7 @@ use crate::spec::{ pub fn target() -> Target { // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. let pre_link_args = LinkArgs::new(); - let post_link_args = TargetOptions::link_args( - LinkerFlavor::EmCc, - &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], - ); + let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]); let opts = TargetOptions { os: "emscripten".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 59df3937ea6ff..356c67218681e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -17,8 +17,8 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), pointer_width: 64, - data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index d0e2ac44a2a26..55165ea4ec68c 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -9,8 +9,8 @@ pub fn target() -> Target { Target { llvm_target: ios_sim_llvm_target(arch).into(), pointer_width: 64, - data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index 8ef4b88b8b1cf..ff21e48933324 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -12,8 +12,8 @@ pub fn target() -> Target { Target { llvm_target: llvm_target.into(), pointer_width: 64, - data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index 17efd437f2fc8..20b0161255314 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -6,8 +6,8 @@ pub fn target() -> Target { Target { llvm_target: tvos_sim_llvm_target(arch).into(), pointer_width: 64, - data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), ..opts("tvos", arch) }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index b1f72ee2f2124..806a58e980be6 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -6,8 +6,8 @@ pub fn target() -> Target { Target { llvm_target: watchos_sim_llvm_target(arch).into(), pointer_width: 64, - data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), ..opts("watchos", arch) }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs index f4117edc3ff5d..c38a1a08536b9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs @@ -75,8 +75,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-elf".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: opts, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs index 0e6d41abc9b40..30b1ee73630e8 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs @@ -16,8 +16,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-linux-android".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: TargetOptions { supported_sanitizers: SanitizerSet::ADDRESS, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs index 93aec4c425a2c..0ef015973998a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs @@ -4,8 +4,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-unknown".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: TargetOptions { cpu: "x86-64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs index f15ad8dda63bc..ade4dd6d43190 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs @@ -13,8 +13,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-solaris".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs index 6d3e072705176..9e964d248bf8f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs @@ -16,8 +16,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs index a56ebfa585e2e..1facf9450cd2a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs @@ -11,8 +11,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs index 3a4da91c2443f..357261073a8f7 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs @@ -10,8 +10,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-msvc".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs index e6159fca3aeaf..6c9d114754873 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs @@ -5,8 +5,8 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-linux-musl".into(), pointer_width: 64, arch: "x86_64".into(), - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), options: TargetOptions { cpu: "x86-64".into(), plt_by_default: false, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs index 80adb8fa2d951..ce682bb800560 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs @@ -11,8 +11,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-dragonfly".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs index fa32103536708..6d6940e7891cd 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs @@ -14,8 +14,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-freebsd".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } 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 5b19ed1b5ff15..50139e5c1d833 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 @@ -12,8 +12,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-fuchsia".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs index 0f927be962bfb..c00c689f7ef79 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs @@ -13,8 +13,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-haiku".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs index df191f515bd68..fb46848ba8c0b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs @@ -5,8 +5,8 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-hermit".into(), pointer_width: 64, arch: "x86_64".into(), - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), options: TargetOptions { cpu: "x86-64".into(), features: "+rdrnd,+rdseed".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs index eb2b13cb5c26b..3e3f4921322c4 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs @@ -13,8 +13,8 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "x86_64-pc-solaris".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs index 7b86fe738b1e3..646623668c6cb 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs @@ -10,8 +10,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-l4re-uclibc".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index bf10f7e5d2de3..2296b58f45dc0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -19,8 +19,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs index 1856c6afd52be..d4b6519262e98 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-linux-gnux32".into(), pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:128-n8:16:32:64-S128" + i64:64-i128:128-f80:128-n8:16:32:64-S128" .into(), arch: "x86_64".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs index 8dc5503e336a6..c71dc65670c28 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs @@ -18,8 +18,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs index 35862656aa2fd..c25105f6e35cf 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs @@ -18,8 +18,8 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "x86_64-unknown-linux-musl".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs index e2cee0513babf..466498acb0b7b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs @@ -19,8 +19,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-netbsd".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: TargetOptions { mcount: "__mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index 8f7655d8ccd35..ceded7790a643 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -30,8 +30,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-none-elf".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: opts, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs index 1133b50f3d223..b542a569bbd23 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs @@ -12,8 +12,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-openbsd".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs index c1f573112920d..550b7a3d28231 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs @@ -11,8 +11,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-redox".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index 5abfb8162f709..95847e57a0fb0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -32,8 +32,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-windows".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs index a46d3a0e27bce..c2981ddbad69b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs @@ -15,8 +15,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs index a3bc27aa0650e..3f0702c7ad60e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs @@ -9,8 +9,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-msvc".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 5a59839ebc68d..fd26b6e8caead 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -10,8 +10,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-win7-windows-msvc".into(), pointer_width: 64, - data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs index 765239bdd39c2..f7a78b48f95d6 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs @@ -12,8 +12,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".into(), pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index 0c731e369ebc2..e0e4cb93e31e1 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -35,8 +35,8 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), pointer_width: 64, - data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), + data_layout: + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 5f5de57dd1d87..c350a37975d23 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -201,6 +201,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("avx512dq", Unstable(sym::avx512_target_feature)), ("avx512er", Unstable(sym::avx512_target_feature)), ("avx512f", Unstable(sym::avx512_target_feature)), + ("avx512fp16", Unstable(sym::avx512_target_feature)), ("avx512ifma", Unstable(sym::avx512_target_feature)), ("avx512pf", Unstable(sym::avx512_target_feature)), ("avx512vbmi", Unstable(sym::avx512_target_feature)), diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 5eff52afbca2b..7894f8dd98fff 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee, - IntoDiagnostic, Level, SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + EmissionGuarantee, IntoDiagnostic, Level, SubdiagnosticMessage, }; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; @@ -25,7 +25,7 @@ pub struct UnableToConstructConstantValue<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = E0232)] pub struct EmptyOnClauseInOnUnimplemented { #[primary_span] #[label] @@ -33,7 +33,7 @@ pub struct EmptyOnClauseInOnUnimplemented { } #[derive(Diagnostic)] -#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = E0232)] pub struct InvalidOnClauseInOnUnimplemented { #[primary_span] #[label] @@ -41,7 +41,7 @@ pub struct InvalidOnClauseInOnUnimplemented { } #[derive(Diagnostic)] -#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = E0232)] #[note] pub struct NoValueInOnUnimplemented { #[primary_span] @@ -59,17 +59,13 @@ pub struct NegativePositiveConflict<'tcx> { impl IntoDiagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] - fn into_diagnostic( - self, - dcx: &DiagCtxt, - level: Level, - ) -> rustc_errors::DiagnosticBuilder<'_, G> { + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::trait_selection_negative_positive_conflict); diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string())); diag.span(self.impl_span); - diag.code(rustc_errors::error_code!(E0751)); + diag.code(E0751); match self.negative_impl_span { Ok(span) => { diag.span_label(span, fluent::trait_selection_negative_implementation_here); @@ -132,7 +128,7 @@ impl AddToDiagnostic for AdjustSignatureBorrow { } #[derive(Diagnostic)] -#[diag(trait_selection_closure_kind_mismatch, code = "E0525")] +#[diag(trait_selection_closure_kind_mismatch, code = E0525)] pub struct ClosureKindMismatch { #[primary_span] #[label] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 552c28c05868c..5ec45212bc791 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,7 +20,6 @@ #![feature(extract_if)] #![feature(let_chains)] #![feature(option_take_if)] -#![feature(if_let_guard)] #![feature(never_type)] #![feature(type_alias_impl_trait)] #![feature(min_specialization)] @@ -40,6 +39,7 @@ extern crate smallvec; pub mod errors; pub mod infer; +pub mod regions; pub mod solve; pub mod traits; diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs new file mode 100644 index 0000000000000..756db7cc2063f --- /dev/null +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -0,0 +1,41 @@ +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{InferCtxt, RegionResolutionError}; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; + +pub trait InferCtxtRegionExt<'tcx> { + /// Resolve regions, using the deep normalizer to normalize any type-outlives + /// obligations in the process. This is in `rustc_trait_selection` because + /// we need to normalize. + /// + /// Prefer this method over `resolve_regions_with_normalize`, unless you are + /// doing something specific for normalization. + fn resolve_regions( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + ) -> Vec>; +} + +impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { + fn resolve_regions( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + ) -> Vec> { + self.resolve_regions_with_normalize(outlives_env, |ty, origin| { + let ty = self.resolve_vars_if_possible(ty); + + if self.next_trait_solver() { + crate::solve::deeply_normalize( + self.at( + &ObligationCause::dummy_with_span(origin.span()), + outlives_env.param_env, + ), + ty, + ) + .map_err(|_| NoSolution) + } else { + Ok(ty) + } + }) + } +} diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index caf9470b4c646..7052fd776b0f2 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -182,6 +182,22 @@ pub(super) trait GoalKind<'tcx>: kind: ty::ClosureKind, ) -> QueryResult<'tcx>; + /// An async closure is known to implement the `AsyncFn` family of traits + /// where `A` is given by the signature of the type. + fn consider_builtin_async_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + kind: ty::ClosureKind, + ) -> QueryResult<'tcx>; + + /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which + /// is used internally to delay computation for async closures until after + /// upvar analysis is performed in HIR typeck. + fn consider_builtin_async_fn_kind_helper_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, @@ -253,17 +269,6 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>; - - /// Consider the `Unsize` candidate corresponding to coercing a sized type - /// into a `dyn Trait`. - /// - /// This is computed separately from the rest of the `Unsize` candidates - /// since it is only done once per self type, and not once per - /// *normalization step* (in `assemble_candidates_via_self_ty`). - fn consider_unsize_to_dyn_candidate( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -271,64 +276,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, ) -> Vec> { - debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); - if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { - return vec![ambig]; - } - - let mut candidates = self.assemble_candidates_via_self_ty(goal, 0); - - self.assemble_unsize_to_dyn_candidate(goal, &mut candidates); - - self.assemble_blanket_impl_candidates(goal, &mut candidates); - - self.assemble_param_env_candidates(goal, &mut candidates); - - self.assemble_coherence_unknowable_candidates(goal, &mut candidates); - - candidates - } - - /// `?0: Trait` is ambiguous, because it may be satisfied via a builtin rule, - /// object bound, alias bound, etc. We are unable to determine this until we can at - /// least structurally resolve the type one layer. - /// - /// It would also require us to consider all impls of the trait, which is both pretty - /// bad for perf and would also constrain the self type if there is just a single impl. - fn assemble_self_ty_infer_ambiguity_response>( - &mut self, - goal: Goal<'tcx, G>, - ) -> Option> { - if goal.predicate.self_ty().is_ty_var() { - debug!("adding self_ty_infer_ambiguity_response"); + let dummy_candidate = |this: &mut EvalCtxt<'_, 'tcx>, certainty| { let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); - let result = self - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - .unwrap(); - let mut dummy_probe = self.inspect.new_probe(); + let result = this.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(); + let mut dummy_probe = this.inspect.new_probe(); dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) }); - self.inspect.finish_probe(dummy_probe); - Some(Candidate { source, result }) - } else { - None + this.inspect.finish_probe(dummy_probe); + vec![Candidate { source, result }] + }; + + let Some(normalized_self_ty) = + self.try_normalize_ty(goal.param_env, goal.predicate.self_ty()) + else { + debug!("overflow while evaluating self type"); + return dummy_candidate(self, Certainty::OVERFLOW); + }; + + if normalized_self_ty.is_ty_var() { + debug!("self type has been normalized to infer"); + return dummy_candidate(self, Certainty::AMBIGUOUS); } - } - /// Assemble candidates which apply to the self type. This only looks at candidate which - /// apply to the specific self type and ignores all others. - /// - /// Returns `None` if the self type is still ambiguous. - fn assemble_candidates_via_self_ty>( - &mut self, - goal: Goal<'tcx, G>, - num_steps: usize, - ) -> Vec> { + let goal = + goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty)); debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); - if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { - return vec![ambig]; - } - let mut candidates = Vec::new(); + let mut candidates = vec![]; self.assemble_non_blanket_impl_candidates(goal, &mut candidates); @@ -338,61 +311,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_object_bound_candidates(goal, &mut candidates); - self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates, num_steps); - candidates - } + self.assemble_blanket_impl_candidates(goal, &mut candidates); - /// If the self type of a goal is an alias we first try to normalize the self type - /// and compute the candidates for the normalized self type in case that succeeds. - /// - /// These candidates are used in addition to the ones with the alias as a self type. - /// We do this to simplify both builtin candidates and for better performance. - /// - /// We generate the builtin candidates on the fly by looking at the self type, e.g. - /// add `FnPtr` candidates if the self type is a function pointer. Handling builtin - /// candidates while the self type is still an alias seems difficult. This is similar - /// to `try_structurally_resolve_type` during hir typeck (FIXME once implemented). - /// - /// Looking at all impls for some trait goal is prohibitively expensive. We therefore - /// only look at implementations with a matching self type. Because of this function, - /// we can avoid looking at all existing impls if the self type is an alias. - #[instrument(level = "debug", skip_all)] - fn assemble_candidates_after_normalizing_self_ty>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>, - num_steps: usize, - ) { - let tcx = self.tcx(); - let &ty::Alias(_, alias) = goal.predicate.self_ty().kind() else { return }; - - candidates.extend(self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { - if tcx.recursion_limit().value_within_limit(num_steps) { - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = - goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() }); - ecx.add_goal(GoalSource::Misc, normalizes_to_goal); - if let Err(NoSolution) = ecx.try_evaluate_added_goals() { - debug!("self type normalization failed"); - return vec![]; - } - let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - debug!(?normalized_ty, "self type normalized"); - // NOTE: Alternatively we could call `evaluate_goal` here and only - // have a `Normalized` candidate. This doesn't work as long as we - // use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - ecx.assemble_candidates_via_self_ty(goal, num_steps + 1) - } else { - match ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) { - Ok(result) => vec![Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }], - Err(NoSolution) => vec![], - } - } - })); + self.assemble_param_env_candidates(goal, &mut candidates); + + self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + + candidates } #[instrument(level = "debug", skip_all)] @@ -431,7 +356,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::Never | ty::Tuple(_) => { @@ -500,24 +426,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] - fn assemble_unsize_to_dyn_candidate>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>, - ) { - let tcx = self.tcx(); - if tcx.lang_items().unsize_trait() == Some(goal.predicate.trait_def_id(tcx)) { - match G::consider_unsize_to_dyn_candidate(self, goal) { - Ok(result) => candidates.push(Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }), - Err(NoSolution) => (), - } - } - } - #[instrument(level = "debug", skip_all)] fn assemble_blanket_impl_candidates>( &mut self, @@ -569,6 +477,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) + } else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) { + G::consider_builtin_async_fn_trait_candidates(self, goal, kind) + } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + G::consider_builtin_async_fn_kind_helper_candidate(self, goal) } else if lang_items.tuple_trait() == Some(trait_def_id) { G::consider_builtin_tuple_candidate(self, goal) } else if lang_items.pointee_trait() == Some(trait_def_id) { @@ -647,6 +559,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::FnPtr(_) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never @@ -803,6 +716,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::FnPtr(_) | ty::Alias(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 274a75a125c58..d02578c484649 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,12 +1,14 @@ //! Code which is used by built-in goals that match "structurally", such a auto //! traits, `Copy`/`Clone`. use rustc_data_structures::fx::FxHashMap; +use rustc_hir::LangItem; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +use rustc_span::sym; use crate::solve::EvalCtxt; @@ -57,6 +59,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), + ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]), + ty::Coroutine(_, args) => { let coroutine_args = args.as_coroutine(); Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()]) @@ -128,6 +132,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => Ok(vec![]), @@ -193,6 +198,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), + ty::CoroutineClosure(..) => Err(NoSolution), + ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { @@ -267,6 +274,131 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } Ok(Some(closure_args.sig().map_bound(|sig| (sig.inputs()[0], sig.output())))) } + + // Coroutine-closures don't implement `Fn` traits the normal way. + ty::CoroutineClosure(..) => Err(NoSolution), + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::Dynamic(_, _, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected type `{self_ty}`") + } + } +} + +// Returns a binder of the tupled inputs types, output type, and coroutine type +// from a builtin coroutine-closure type. If we don't yet know the closure kind of +// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper` +// which enforces the closure is actually callable with the given trait. When we +// know the kind already, we can short-circuit this check. +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + goal_kind: ty::ClosureKind, + env_region: ty::Region<'tcx>, +) -> Result< + (ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option>), + NoSolution, +> { + match *self_ty.kind() { + ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + + if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + Ok(( + args.coroutine_closure_sig().map_bound(|sig| { + let coroutine_ty = sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + goal_kind, + env_region, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ); + (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) + }), + None, + )) + } else { + let async_fn_kind_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + let upvars_projection_def_id = tcx + .associated_items(async_fn_kind_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) + .next() + .unwrap() + .def_id; + // When we don't know the closure kind (and therefore also the closure's upvars, + // which are computed at the same time), we must delay the computation of the + // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait + // goal functions similarly to the old `ClosureKind` predicate, and ensures that + // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars` + // will project to the right upvars for the generator, appending the inputs and + // coroutine upvars respecting the closure kind. + Ok(( + args.coroutine_closure_sig().map_bound(|sig| { + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + let coroutine_ty = sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ); + (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) + }), + Some( + ty::TraitRef::new( + tcx, + async_fn_kind_trait_def_id, + [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], + ) + .to_predicate(tcx), + ), + )) + } + } + + ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution), + ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c847425ebf46a..f08622816ec28 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -11,7 +11,7 @@ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use super::eval_ctxt::GenerateProofTree; -use super::{Certainty, InferCtxtEvalExt}; +use super::{Certainty, Goal, InferCtxtEvalExt}; /// A trait engine using the new trait solver. /// @@ -43,6 +43,21 @@ impl<'tcx> FulfillmentCtxt<'tcx> { ); FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() } } + + fn inspect_evaluated_obligation( + &self, + infcx: &InferCtxt<'tcx>, + obligation: &PredicateObligation<'tcx>, + result: &Result<(bool, Certainty, Vec>>), NoSolution>, + ) { + if let Some(inspector) = infcx.obligation_inspector.get() { + let result = match result { + Ok((_, c, _)) => Ok(*c), + Err(NoSolution) => Err(NoSolution), + }; + (inspector)(infcx, &obligation, result); + } + } } impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { @@ -100,65 +115,66 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty, nested_goals) = - match infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0 { - Ok(result) => result, - Err(NoSolution) => { - errors.push(FulfillmentError { - obligation: obligation.clone(), - code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { - FulfillmentErrorCode::ProjectionError( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::NormalizesTo(..) => { - FulfillmentErrorCode::ProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::ProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::SubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::SubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::SelectionError( - SelectionError::Unimplemented, - ) - } - ty::PredicateKind::ConstEquate(..) => { - bug!("unexpected goal: {goal:?}") - } - }, - root_obligation: obligation, - }); - continue; - } - }; + let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0; + self.inspect_evaluated_obligation(infcx, &obligation, &result); + let (changed, certainty, nested_goals) = match result { + Ok(result) => result, + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { + FulfillmentErrorCode::ProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::NormalizesTo(..) => { + FulfillmentErrorCode::ProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::ProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::SubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::SubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::SelectionError( + SelectionError::Unimplemented, + ) + } + ty::PredicateKind::ConstEquate(..) => { + bug!("unexpected goal: {goal:?}") + } + }, + root_obligation: obligation, + }); + continue; + } + }; // Push any nested goals that we get from unifying our canonical response // with our obligation onto the fulfillment context. self.obligations.extend(nested_goals.into_iter().map(|goal| { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 7c8f885a1f24c..6984f0ba69473 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -288,11 +288,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// Normalize a type when it is structually matched on. /// - /// For self types this is generally already handled through - /// `assemble_candidates_after_normalizing_self_ty`, so anything happening - /// in [`EvalCtxt::assemble_candidates_via_self_ty`] does not have to normalize - /// the self type. It is required when structurally matching on any other - /// arguments of a trait goal, e.g. when assembling builtin unsize candidates. + /// In nearly all cases this function must be used before matching on a type. + /// Not doing so is likely to be incomplete and therefore unsound during + /// coherence. #[instrument(level = "debug", skip(self), ret)] fn try_normalize_ty( &mut self, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index ccee6f8eb29b9..47ba549022d9b 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -366,6 +366,119 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) } + fn consider_builtin_async_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + goal_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); + + let env_region = match goal_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), + // Doesn't matter what this region is + ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, + }; + let (tupled_inputs_and_output_and_coroutine, nested_preds) = + structural_traits::extract_tupled_inputs_and_output_from_async_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + env_region, + )?; + let output_is_sized_pred = + tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| { + ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) + }); + + let pred = tupled_inputs_and_output_and_coroutine + .map_bound(|(inputs, output, coroutine)| { + let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) { + sym::CallOnceFuture => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + ), + coroutine.into(), + ), + sym::CallMutFuture | sym::CallFuture => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [ + ty::GenericArg::from(goal.predicate.self_ty()), + inputs.into(), + env_region.into(), + ], + ), + coroutine.into(), + ), + sym::Output => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()], + ), + output.into(), + ), + name => bug!("no such associated type: {name}"), + }; + ty::ProjectionPredicate { projection_ty, term } + }) + .to_predicate(tcx); + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + Self::consider_implied_clause( + ecx, + goal, + pred, + [goal.with(tcx, output_is_sized_pred)] + .into_iter() + .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))), + ) + } + + fn consider_builtin_async_fn_kind_helper_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let [ + closure_fn_kind_ty, + goal_kind_ty, + borrow_region, + tupled_inputs_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + ] = **goal.predicate.alias.args + else { + bug!(); + }; + + let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { + // We don't need to worry about the self type being an infer var. + return Err(NoSolution); + }; + let Some(goal_kind) = goal_kind_ty.expect_ty().to_opt_closure_kind() else { + return Err(NoSolution); + }; + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + + let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( + ecx.tcx(), + goal_kind, + tupled_inputs_ty.expect_ty(), + tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty.expect_ty(), + borrow_region.expect_region(), + ); + + ecx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), upvars_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn consider_builtin_tuple_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -391,6 +504,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Coroutine(..) | ty::CoroutineWitness(..) @@ -603,13 +717,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } - fn consider_unsize_to_dyn_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - bug!("`Unsize` does not have an associated type: {:?}", goal) - } - fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -634,6 +741,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Coroutine(..) | ty::CoroutineWitness(..) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs index 6d5728797d1ef..9f91c02c1ab60 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs @@ -1,7 +1,7 @@ //! Computes a normalizes-to (projection) goal for inherent associated types, //! `#![feature(lazy_type_alias)]` and `#![feature(type_alias_impl_trait)]`. //! -//! Since a weak alias is not ambiguous, this just computes the `type_of` of +//! Since a weak alias is never ambiguous, this just computes the `type_of` of //! the alias and registers the where-clauses of the type alias. use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult}; use rustc_middle::ty; diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index be07927568446..fd09a6b671dad 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -303,6 +303,66 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) } + fn consider_builtin_async_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + goal_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + + let tcx = ecx.tcx(); + let (tupled_inputs_and_output_and_coroutine, nested_preds) = + structural_traits::extract_tupled_inputs_and_output_from_async_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + // This region doesn't matter because we're throwing away the coroutine type + tcx.lifetimes.re_static, + )?; + let output_is_sized_pred = + tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| { + ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) + }); + + let pred = tupled_inputs_and_output_and_coroutine + .map_bound(|(inputs, _, _)| { + ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + }) + .to_predicate(tcx); + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + Self::consider_implied_clause( + ecx, + goal, + pred, + [goal.with(tcx, output_is_sized_pred)] + .into_iter() + .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))), + ) + } + + fn consider_builtin_async_fn_kind_helper_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { + bug!(); + }; + + let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { + // We don't need to worry about the self type being an infer var. + return Err(NoSolution); + }; + let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(); + if closure_kind.extends(goal_kind) { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } + fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -490,53 +550,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(certainty) } - fn consider_unsize_to_dyn_candidate( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| { - let a_ty = goal.predicate.self_ty(); - // We need to normalize the b_ty since it's destructured as a `dyn Trait`. - let Some(b_ty) = - ecx.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1)) - else { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); - }; - - let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { - return Err(NoSolution); - }; - - let tcx = ecx.tcx(); - - // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { - return Err(NoSolution); - } - - // Check that the type implements all of the predicates of the trait object. - // (i.e. the principal, all of the associated types match, and any auto traits) - ecx.add_goals( - GoalSource::ImplWhereBound, - b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), - ); - - // The type must be `Sized` to be unsized. - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - ecx.add_goal( - GoalSource::ImplWhereBound, - goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), - ); - } else { - return Err(NoSolution); - } - - // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - } - /// ```ignore (builtin impl example) /// trait Trait { /// fn foo(&self); @@ -588,8 +601,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal, a_data, a_region, b_data, b_region, ), - // `T` -> `dyn Trait` unsizing is handled separately in `consider_unsize_to_dyn_candidate` - (_, &ty::Dynamic(..)) => vec![], + // `T` -> `dyn Trait` unsizing. + (_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( + ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data), + BuiltinImplSource::Misc, + ), // `[T; N]` -> `[T]` unsizing (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single( @@ -691,6 +707,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { responses } + fn consider_builtin_unsize_to_dyn_candidate( + &mut self, + goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, + b_data: &'tcx ty::List>, + b_region: ty::Region<'tcx>, + ) -> QueryResult<'tcx> { + let tcx = self.tcx(); + let Goal { predicate: (a_ty, _), .. } = goal; + + // Can only unsize to an object-safe trait. + if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { + return Err(NoSolution); + } + + // Check that the type implements all of the predicates of the trait object. + // (i.e. the principal, all of the associated types match, and any auto traits) + self.add_goals( + GoalSource::ImplWhereBound, + b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + + // The type must be `Sized` to be unsized. + if let Some(sized_def_id) = tcx.lang_items().sized_trait() { + self.add_goal( + GoalSource::ImplWhereBound, + goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), + ); + } else { + return Err(NoSolution); + } + + // The type must outlive the lifetime of the `dyn` we're unsizing into. + self.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn consider_builtin_upcast_to_principal( &mut self, goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, @@ -958,7 +1010,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index c43447585746a..81c72fc4b7b03 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } let outlives_env = OutlivesEnvironment::new(full_env); - infcx.process_registered_region_obligations(&outlives_env); + let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty)); let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone(); @@ -513,6 +513,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } while !vid_map.is_empty() { + #[allow(rustc::potential_query_instability)] let target = *vid_map.keys().next().expect("Keys somehow empty"); let deps = vid_map.remove(&target).expect("Entry somehow missing"); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ecbb92ca5b996..4b20de2621924 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -6,6 +6,7 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::InferOk; +use crate::regions::InferCtxtRegionExt; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; @@ -862,7 +863,7 @@ where } } ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Closure(did, ..) | ty::Coroutine(did, ..) => { + ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => { if self.def_id_is_local(did) { ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) } else { diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 013a50f9fa1c8..caf950037fdfd 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use super::FulfillmentContext; use super::TraitEngine; +use crate::regions::InferCtxtRegionExt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::NormalizeExt; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 864580afe623b..ca43436848bae 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -1,7 +1,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::Node; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 532e2cb36e3cc..972da180a3365 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_ast::AttrKind; use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::GenericArgsRef; @@ -359,7 +359,7 @@ impl IgnoredDiagnosticOption { option_name: &'static str, ) { if let (Some(new_item), Some(old_item)) = (new, old) { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), new_item, @@ -491,7 +491,7 @@ impl<'tcx> OnUnimplementedDirective { } if is_diagnostic_namespace_variant { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), vec![item.span()], @@ -629,7 +629,7 @@ impl<'tcx> OnUnimplementedDirective { AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span), }; - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), report_span, @@ -640,14 +640,14 @@ impl<'tcx> OnUnimplementedDirective { } else if is_diagnostic_namespace_variant { match &attr.kind { AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, MalformedOnUnimplementedAttrLint::new(attr.span), ); } - _ => tcx.emit_spanned_lint( + _ => tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, @@ -776,7 +776,7 @@ impl<'tcx> OnUnimplementedFormatString { s if generics.params.iter().any(|param| param.name == s) => (), s => { if self.is_diagnostic_namespace_variant { - tcx.emit_spanned_lint( + tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), self.span, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 0e33e9cd790d0..243f583aed825 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -7,13 +7,13 @@ use super::{ use crate::errors; use crate::infer::InferCtxt; -use crate::traits::{NormalizeExt, ObligationCtxt}; +use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt}; use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - error_code, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; @@ -1288,7 +1288,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion_verbose( obligation.cause.span.shrink_to_hi(), "consider using clone here", - ".clone()".to_string(), + ".clone()", Applicability::MaybeIncorrect, ); return true; @@ -1432,20 +1432,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> bool { let span = obligation.cause.span; - let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = - obligation.cause.code() - { - parent_code - } else if let ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() - { - obligation.cause.code() - } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = - span.ctxt().outer_expn_data().kind - { - obligation.cause.code() - } else { - return false; + let code = match obligation.cause.code() { + ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => parent_code, + c @ ObligationCauseCode::ItemObligation(_) + | c @ ObligationCauseCode::ExprItemObligation(..) => c, + c if matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Desugaring(DesugaringKind::ForLoop) + ) => + { + c + } + _ => return false, }; // List of traits for which it would be nonsensical to suggest borrowing. @@ -2014,7 +2012,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; }; - err.code(error_code!(E0746)); + err.code(E0746); err.primary_message("return type cannot have an unboxed trait object"); err.children.clear(); @@ -2719,7 +2717,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let (trait_name, trait_verb) = if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; - err.clear_code(); + err.code = None; err.primary_message(format!( "{future_or_coroutine} cannot be {trait_verb} between threads safely" )); @@ -2973,7 +2971,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::RustCall => { if let Some(pred) = predicate.to_opt_poly_trait_pred() - && Some(pred.def_id()) == self.tcx.lang_items().sized_trait() + && Some(pred.def_id()) == tcx.lang_items().sized_trait() { err.note("argument required to be sized due to `extern \"rust-call\"` ABI"); } @@ -3011,35 +3009,44 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } } - let descr = format!("required by a bound in `{item_name}`"); - if span.is_visible(sm) { - let msg = format!("required by this bound in `{short_item_name}`"); - multispan.push_span_label(span, msg); - err.span_note(multispan, descr); - if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() - && let ty::ClauseKind::Trait(trait_pred) = clause - { - let def_id = trait_pred.def_id(); - let visible_item = if let Some(local) = def_id.as_local() { - // Check for local traits being reachable. - let vis = &self.tcx.resolutions(()).effective_visibilities; - // Account for non-`pub` traits in the root of the local crate. - let is_locally_reachable = self.tcx.parent(def_id).is_crate_root(); - vis.is_reachable(local) || is_locally_reachable - } else { - // Check for foreign traits being reachable. - self.tcx.visible_parent_map(()).get(&def_id).is_some() - }; - if Some(def_id) == self.tcx.lang_items().sized_trait() - && let Some(hir::Node::TraitItem(hir::TraitItem { - ident, - kind: hir::TraitItemKind::Type(bounds, None), - .. - })) = tcx.hir().get_if_local(item_def_id) - // Do not suggest relaxing if there is an explicit `Sized` obligation. - && !bounds.iter() - .filter_map(|bound| bound.trait_ref()) - .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait()) + let mut a = "a"; + let mut this = "this bound"; + let mut note = None; + let mut help = None; + if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() + && let ty::ClauseKind::Trait(trait_pred) = clause + { + let def_id = trait_pred.def_id(); + let visible_item = if let Some(local) = def_id.as_local() { + // Check for local traits being reachable. + let vis = &tcx.resolutions(()).effective_visibilities; + // Account for non-`pub` traits in the root of the local crate. + let is_locally_reachable = tcx.parent(def_id).is_crate_root(); + vis.is_reachable(local) || is_locally_reachable + } else { + // Check for foreign traits being reachable. + tcx.visible_parent_map(()).get(&def_id).is_some() + }; + if Some(def_id) == tcx.lang_items().sized_trait() { + // Check if this is an implicit bound, even in foreign crates. + if tcx + .generics_of(item_def_id) + .params + .iter() + .any(|param| tcx.def_span(param.def_id) == span) + { + a = "an implicit `Sized`"; + this = "the implicit `Sized` requirement on this type parameter"; + } + if let Some(hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Type(bounds, None), + .. + })) = tcx.hir().get_if_local(item_def_id) + // Do not suggest relaxing if there is an explicit `Sized` obligation. + && !bounds.iter() + .filter_map(|bound| bound.trait_ref()) + .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait()) { let (span, separator) = if let [.., last] = bounds { (last.span().shrink_to_hi(), " +") @@ -3053,59 +3060,69 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Applicability::MachineApplicable, ); } - if let DefKind::Trait = tcx.def_kind(item_def_id) - && !visible_item - { - err.note(format!( - "`{short_item_name}` is a \"sealed trait\", because to implement \ - it you also need to implement `{}`, which is not accessible; \ - this is usually done to force you to use one of the provided \ - types that already implement it", - with_no_trimmed_paths!(tcx.def_path_str(def_id)), - )); - let impls_of = tcx.trait_impls_of(def_id); - let impls = impls_of - .non_blanket_impls() - .values() - .flatten() - .chain(impls_of.blanket_impls().iter()) + } + if let DefKind::Trait = tcx.def_kind(item_def_id) + && !visible_item + { + note = Some(format!( + "`{short_item_name}` is a \"sealed trait\", because to implement it \ + you also need to implement `{}`, which is not accessible; this is \ + usually done to force you to use one of the provided types that \ + already implement it", + with_no_trimmed_paths!(tcx.def_path_str(def_id)), + )); + let impls_of = tcx.trait_impls_of(def_id); + let impls = impls_of + .non_blanket_impls() + .values() + .flatten() + .chain(impls_of.blanket_impls().iter()) + .collect::>(); + if !impls.is_empty() { + let len = impls.len(); + let mut types = impls + .iter() + .map(|t| { + with_no_trimmed_paths!(format!( + " {}", + tcx.type_of(*t).instantiate_identity(), + )) + }) .collect::>(); - if !impls.is_empty() { - let len = impls.len(); - let mut types = impls - .iter() - .map(|t| { - with_no_trimmed_paths!(format!( - " {}", - tcx.type_of(*t).instantiate_identity(), - )) - }) - .collect::>(); - let post = if types.len() > 9 { - types.truncate(8); - format!("\nand {} others", len - 8) - } else { - String::new() - }; - err.help(format!( - "the following type{} implement{} the trait:\n{}{post}", - pluralize!(len), - if len == 1 { "s" } else { "" }, - types.join("\n"), - )); - } + let post = if types.len() > 9 { + types.truncate(8); + format!("\nand {} others", len - 8) + } else { + String::new() + }; + help = Some(format!( + "the following type{} implement{} the trait:\n{}{post}", + pluralize!(len), + if len == 1 { "s" } else { "" }, + types.join("\n"), + )); } } + }; + let descr = format!("required by {a} bound in `{item_name}`"); + if span.is_visible(sm) { + let msg = format!("required by {this} in `{short_item_name}`"); + multispan.push_span_label(span, msg); + err.span_note(multispan, descr); } else { err.span_note(tcx.def_span(item_def_id), descr); } + if let Some(note) = note { + err.note(note); + } + if let Some(help) = help { + err.help(help); + } } ObligationCauseCode::Coercion { source, target } => { let mut file = None; - let source = - self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file); - let target = - self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file); + let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file); + let target = tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -3152,9 +3169,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ], Applicability::MachineApplicable, ); + } else { + // FIXME: we may suggest array::repeat instead + err.help("consider using `core::array::from_fn` to initialize the array"); + err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information"); } - if self.tcx.sess.is_nightly_build() + if tcx.sess.is_nightly_build() && matches!(is_constable, IsConstable::Fn | IsConstable::Ctor) { err.help( @@ -3164,8 +3185,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::VariableType(hir_id) => { - let parent_node = self.tcx.hir().parent_id(hir_id); - match self.tcx.opt_hir_node(parent_node) { + let parent_node = tcx.hir().parent_id(hir_id); + match tcx.opt_hir_node(parent_node) { Some(Node::Local(hir::Local { ty: Some(ty), .. })) => { err.span_suggestion_verbose( ty.span.shrink_to_lo(), @@ -3203,7 +3224,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all local variables must have a statically known size"); } } - if !self.tcx.features().unsized_locals { + if !tcx.features().unsized_locals { err.help("unsized locals are gated as an unstable feature"); } } @@ -3245,7 +3266,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion_verbose( span, "you can use `impl Trait` as the argument type", - "impl ".to_string(), + "impl ", Applicability::MaybeIncorrect, ); let sugg = if !needs_parens { @@ -3285,12 +3306,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all function arguments must have a statically known size"); } if tcx.sess.opts.unstable_features.is_nightly_build() - && !self.tcx.features().unsized_fn_params + && !tcx.features().unsized_fn_params { err.help("unsized fn params are gated as an unstable feature"); } } - ObligationCauseCode::SizedReturnType => { + ObligationCauseCode::SizedReturnType | ObligationCauseCode::SizedCallReturnType => { err.note("the return type of a function must have a statically known size"); } ObligationCauseCode::SizedYieldType => { @@ -3354,7 +3375,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "all values captured by value by a closure must have a statically known size", ); let hir::ExprKind::Closure(closure) = - self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind + tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind else { bug!("expected closure in SizedClosureCapture obligation"); }; @@ -3365,7 +3386,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => { - let what = match self.tcx.coroutine_kind(coroutine_def_id) { + let what = match tcx.coroutine_kind(coroutine_def_id) { None | Some(hir::CoroutineKind::Coroutine(_)) | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => { @@ -3416,10 +3437,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 'print: { if !is_upvar_tys_infer_tuple { let mut file = None; - let ty_str = self.tcx.short_ty_string(ty, &mut file); + let ty_str = tcx.short_ty_string(ty, &mut file); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { - ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { + ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { Some(ident) => err.span_note(ident.span, msg), None => err.note(msg), }, @@ -3442,7 +3463,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { break 'print; } - err.span_note(self.tcx.def_span(def_id), msg) + err.span_note(tcx.def_span(def_id), msg) } ty::CoroutineWitness(def_id, args) => { use std::fmt::Write; @@ -3459,7 +3480,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note(msg.trim_end_matches(", ").to_string()) } ty::Coroutine(def_id, _) => { - let sp = self.tcx.def_span(def_id); + let sp = tcx.def_span(def_id); // Special-case this to say "async block" instead of `[static coroutine]`. let kind = tcx.coroutine_kind(def_id).unwrap(); @@ -3471,7 +3492,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } ty::Closure(def_id, _) => err.span_note( - self.tcx.def_span(def_id), + tcx.def_span(def_id), "required because it's used within this closure", ), ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"), @@ -3515,14 +3536,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); let mut file = None; - let self_ty = - self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); - let msg = format!( - "required for `{self_ty}` to implement `{}`", - parent_trait_pred.print_modifiers_and_trait_path() - ); + let self_ty_str = + tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); + let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); + let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; - match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) { + match tcx.hir().get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Trait(is_auto, ..), ident, @@ -3534,7 +3553,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_note(ident.span, msg); } Some(Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), + kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }), .. })) => { let mut spans = Vec::with_capacity(2); @@ -3561,6 +3580,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } err.span_note(spans, msg); + point_at_assoc_type_restriction( + tcx, + err, + &self_ty_str, + &trait_name, + predicate, + &generics, + &data, + ); } _ => { err.note(msg); @@ -3614,9 +3642,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { pluralize!(count) )); let mut file = None; - let self_ty = self - .tcx - .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); + let self_ty = + tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3674,10 +3701,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { multispan.push_span_label(span, "required by this bound"); err.span_note( multispan, - format!( - "required by a bound on the type alias `{}`", - self.infcx.tcx.item_name(def_id) - ), + format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)), ); } ObligationCauseCode::FunctionArgumentObligation { @@ -3708,25 +3732,23 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }); } ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { - let item_name = self.tcx.item_name(trait_item_def_id); + let item_name = tcx.item_name(trait_item_def_id); let msg = format!( "the requirement `{predicate}` appears on the `impl`'s {kind} \ `{item_name}` but not on the corresponding trait's {kind}", ); - let sp = self - .tcx + let sp = tcx .opt_item_ident(trait_item_def_id) .map(|i| i.span) - .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id)); + .unwrap_or_else(|| tcx.def_span(trait_item_def_id)); let mut assoc_span: MultiSpan = sp.into(); assoc_span.push_span_label( sp, format!("this trait's {kind} doesn't have the requirement `{predicate}`"), ); - if let Some(ident) = self - .tcx + if let Some(ident) = tcx .opt_associated_item(trait_item_def_id) - .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx))) + .and_then(|i| tcx.opt_item_ident(i.container_id(tcx))) { assoc_span.push_span_label(ident.span, "in this trait"); } @@ -4816,6 +4838,29 @@ fn hint_missing_borrow<'tcx>( } } +/// Collect all the paths that reference `Self`. +/// Used to suggest replacing associated types with an explicit type in `where` clauses. +#[derive(Debug)] +pub struct SelfVisitor<'v> { + pub paths: Vec<&'v hir::Ty<'v>>, + pub name: Option, +} + +impl<'v> Visitor<'v> for SelfVisitor<'v> { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + if let hir::TyKind::Path(path) = ty.kind + && let hir::QPath::TypeRelative(inner_ty, segment) = path + && (Some(segment.ident.name) == self.name || self.name.is_none()) + && let hir::TyKind::Path(inner_path) = inner_ty.kind + && let hir::QPath::Resolved(None, inner_path) = inner_path + && let Res::SelfTyAlias { .. } = inner_path.res + { + self.paths.push(ty); + } + hir::intravisit::walk_ty(self, ty); + } +} + /// Collect all the returned expressions within the input expression. /// Used to point at the return spans when we want to suggest some change to them. #[derive(Default)] @@ -4952,16 +4997,27 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( _ => None, }; + let pred = obligation.predicate; + let (_, base) = obligation.cause.code().peel_derives_with_predicate(); + let post = if let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder() + && let ty::ClauseKind::Trait(pred) = clause + && let Some(base) = base + && base.skip_binder() != pred + { + format!(", which is required by `{base}`") + } else { + String::new() + }; match ty_desc { Some(desc) => format!( - "{}the trait `{}` is not implemented for {} `{}`", + "{}the trait `{}` is not implemented for {} `{}`{post}", pre_message, trait_predicate.print_modifiers_and_trait_path(), desc, tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None), ), None => format!( - "{}the trait `{}` is not implemented for `{}`", + "{}the trait `{}` is not implemented for `{}`{post}", pre_message, trait_predicate.print_modifiers_and_trait_path(), tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None), @@ -5060,6 +5116,134 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( Some(sugg) } +/// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain +/// they are not allowed and if possible suggest alternatives. +fn point_at_assoc_type_restriction( + tcx: TyCtxt<'_>, + err: &mut Diagnostic, + self_ty_str: &str, + trait_name: &str, + predicate: ty::Predicate<'_>, + generics: &hir::Generics<'_>, + data: &ImplDerivedObligationCause<'_>, +) { + let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else { + return; + }; + let ty::ClauseKind::Projection(proj) = clause else { + return; + }; + let name = tcx.item_name(proj.projection_ty.def_id); + let mut predicates = generics.predicates.iter().peekable(); + let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None; + while let Some(pred) = predicates.next() { + let hir::WherePredicate::BoundPredicate(pred) = pred else { + continue; + }; + let mut bounds = pred.bounds.iter().peekable(); + while let Some(bound) = bounds.next() { + let Some(trait_ref) = bound.trait_ref() else { + continue; + }; + if bound.span() != data.span { + continue; + } + if let hir::TyKind::Path(path) = pred.bounded_ty.kind + && let hir::QPath::TypeRelative(ty, segment) = path + && segment.ident.name == name + && let hir::TyKind::Path(inner_path) = ty.kind + && let hir::QPath::Resolved(None, inner_path) = inner_path + && let Res::SelfTyAlias { .. } = inner_path.res + { + // The following block is to determine the right span to delete for this bound + // that will leave valid code after the suggestion is applied. + let span = if pred.origin == hir::PredicateOrigin::WhereClause + && generics + .predicates + .iter() + .filter(|p| { + matches!( + p, + hir::WherePredicate::BoundPredicate(p) + if hir::PredicateOrigin::WhereClause == p.origin + ) + }) + .count() + == 1 + { + // There's only one `where` bound, that needs to be removed. Remove the whole + // `where` clause. + generics.where_clause_span + } else if let Some(hir::WherePredicate::BoundPredicate(next)) = predicates.peek() + && pred.origin == next.origin + { + // There's another bound, include the comma for the current one. + pred.span.until(next.span) + } else if let Some(prev) = prev + && pred.origin == prev.origin + { + // Last bound, try to remove the previous comma. + prev.span.shrink_to_hi().to(pred.span) + } else if pred.origin == hir::PredicateOrigin::WhereClause { + pred.span.with_hi(generics.where_clause_span.hi()) + } else { + pred.span + }; + + err.span_suggestion_verbose( + span, + "associated type for the current `impl` cannot be restricted in `where` \ + clauses, remove this bound", + "", + Applicability::MaybeIncorrect, + ); + } + if let Some(new) = + tcx.associated_items(data.impl_or_alias_def_id).find_by_name_and_kind( + tcx, + Ident::with_dummy_span(name), + ty::AssocKind::Type, + data.impl_or_alias_def_id, + ) + { + // The associated type is specified in the `impl` we're + // looking at. Point at it. + let span = tcx.def_span(new.def_id); + err.span_label( + span, + format!( + "associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \ + here", + ), + ); + // Search for the associated type `Self::{name}`, get + // its type and suggest replacing the bound with it. + let mut visitor = SelfVisitor { paths: vec![], name: Some(name) }; + visitor.visit_trait_ref(trait_ref); + for path in visitor.paths { + err.span_suggestion_verbose( + path.span, + "replace the associated type with the type specified in this `impl`", + tcx.type_of(new.def_id).skip_binder(), + Applicability::MachineApplicable, + ); + } + } else { + let mut visitor = SelfVisitor { paths: vec![], name: None }; + visitor.visit_trait_ref(trait_ref); + let span: MultiSpan = + visitor.paths.iter().map(|p| p.span).collect::>().into(); + err.span_note( + span, + "associated types for the current `impl` cannot be restricted in `where` \ + clauses", + ); + } + } + prev = Some(pred); + } +} + fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec) { let mut refs = vec![]; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 149dcffe333de..1ac0f172ef4c3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -19,8 +19,8 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, StashKey, Style, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, StashKey, StringPart, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -99,7 +99,7 @@ pub trait TypeErrCtxtExt<'tcx> { obligation: PredicateObligation<'tcx>, root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, - ); + ) -> ErrorGuaranteed; fn emit_specialized_closure_kind_error( &self, @@ -107,7 +107,10 @@ pub trait TypeErrCtxtExt<'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option; - fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool; + fn fn_arg_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> Result<(), ErrorGuaranteed>; fn try_conversion_context( &self, @@ -142,6 +145,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ( span, predicates + .0 .iter() .map(|&predicate| ErrorDescriptor { predicate, index: None }) .collect(), @@ -208,10 +212,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } + let mut reported = None; + for from_expansion in [false, true] { for (error, suppressed) in iter::zip(&errors, &is_suppressed) { if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { - self.report_fulfillment_error(error); + let guar = self.report_fulfillment_error(error); + reported = Some(guar); // We want to ignore desugarings here: spans are equivalent even // if one is the result of a desugaring and the other is not. let mut span = error.obligation.cause.span; @@ -222,13 +229,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.reported_trait_errors .borrow_mut() .entry(span) - .or_default() + .or_insert_with(|| (vec![], guar)) + .0 .push(error.obligation.predicate); } } } - self.dcx().delayed_bug("expected fulfillment errors") + // It could be that we don't report an error because we have seen an `ErrorReported` from another source. + // We should probably be able to fix most of these, but some are delayed bugs that get a proper error + // after this function. + reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) } /// Reports that an overflow has occurred and halts compilation. We @@ -374,7 +385,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { mut obligation: PredicateObligation<'tcx>, root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, - ) { + ) -> ErrorGuaranteed { let tcx = self.tcx; if tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() @@ -384,10 +395,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let mut span = obligation.cause.span; - // FIXME: statically guarantee this by tainting after the diagnostic is emitted - self.set_tainted_by_errors( - tcx.dcx().span_delayed_bug(span, "`report_selection_error` did not emit an error"), - ); let mut err = match *error { SelectionError::Unimplemented => { @@ -412,21 +419,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { kind: _, } = *obligation.cause.code() { - self.report_extra_impl_obligation( + return self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, &format!("`{}`", obligation.predicate), ) - .emit(); - return; + .emit() } // Report a const-param specific error if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives() { - self.report_const_param_not_wf(ty, &obligation).emit(); - return; + return self.report_const_param_not_wf(ty, &obligation).emit(); } let bound_predicate = obligation.predicate.kind(); @@ -436,22 +441,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_predicate = self.resolve_vars_if_possible(trait_predicate); let trait_ref = trait_predicate.to_poly_trait_ref(); - if let Some(_guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) { - return; + if let Some(guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) { + return guar; } // FIXME(effects) let predicate_is_const = false; - if self.dcx().has_errors().is_some() - && trait_predicate.references_error() + if let Err(guar) = trait_predicate.error_reported() { - return; + return guar; } - if self.fn_arg_obligation(&obligation) { - // Silence redundant errors on binding acccess that are already - // reported on the binding definition (#56607). - return; + // Silence redundant errors on binding acccess that are already + // reported on the binding definition (#56607). + if let Err(guar) = self.fn_arg_obligation(&obligation) { + return guar; } let mut file = None; let (post_message, pre_message, type_def) = self @@ -515,7 +519,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref, span, ) { - GetSafeTransmuteErrorAndReason::Silent => return, + GetSafeTransmuteErrorAndReason::Silent => return self.dcx().span_delayed_bug(span, "silent safe transmute error"), GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation, @@ -576,8 +580,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { have_alt_message, ) { self.note_obligation_cause(&mut err, &obligation); - err.emit(); - return; + return err.emit(); } file_note.map(|note| err.note(note)); @@ -680,13 +683,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) { - err.emit(); - return; + return err.emit(); } if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) { - err.emit(); - return; + return err.emit(); } if is_unsize { @@ -776,8 +777,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Some(sym::Debug | sym::Display) ) { - err.emit(); - return; + return err.emit(); } err @@ -912,8 +912,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found_trait_ref, expected_trait_ref, ) { - Some(err) => err, - None => return, + Ok(err) => err, + Err(guar) => return guar, } } @@ -934,15 +934,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => { match self.report_not_const_evaluatable_error(&obligation, span) { - Some(err) => err, - None => return, + Ok(err) => err, + Err(guar) => return guar, } } // Already reported in the query. - SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) | + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) | // Already reported. - Overflow(OverflowError::Error(_)) => return, + Overflow(OverflowError::Error(guar)) => return guar, Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); @@ -951,7 +951,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.note_obligation_cause(&mut err, &obligation); self.point_at_returns_when_relevant(&mut err, &obligation); - err.emit(); + err.emit() } fn emit_specialized_closure_kind_error( @@ -959,9 +959,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option { - if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind() + let self_ty = trait_ref.self_ty().skip_binder(); + if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind() && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - && let Some(found_kind) = self.closure_kind(closure_args) + && let Some(found_kind) = self.closure_kind(self_ty) && !found_kind.extends(expected_kind) && let sig = closure_args.as_closure().sig() && self.can_sub( @@ -986,7 +987,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool { + fn fn_arg_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> Result<(), ErrorGuaranteed> { if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() && let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id) @@ -996,12 +1000,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { hir::Path { res: hir::def::Res::Local(hir_id), .. }, )) = arg.kind && let Some(Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id) - && let Some(preds) = self.reported_trait_errors.borrow().get(&pat.span) + && let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span) && preds.contains(&obligation.predicate) { - return true; + return Err(*guar); } - false + Ok(()) } /// When the `E` of the resulting `Result` in an expression `foo().bar().baz()?`, @@ -1323,13 +1327,13 @@ pub(super) trait InferCtxtPrivExt<'tcx> { // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>); + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed; fn report_projection_error( &self, obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, - ); + ) -> ErrorGuaranteed; fn maybe_detailed_projection_msg( &self, @@ -1395,7 +1399,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, ) -> PredicateObligation<'tcx>; - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>); + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed; fn predicate_can_apply( &self, @@ -1512,13 +1516,13 @@ pub(super) trait InferCtxtPrivExt<'tcx> { span: Span, found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> Option>; + ) -> Result, ErrorGuaranteed>; fn report_not_const_evaluatable_error( &self, obligation: &PredicateObligation<'tcx>, span: Span, - ) -> Option>; + ) -> Result, ErrorGuaranteed>; } impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { @@ -1564,7 +1568,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) { + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() == DumpSolverProofTree::OnError { @@ -1572,31 +1576,29 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } match error.code { - FulfillmentErrorCode::SelectionError(ref selection_error) => { - self.report_selection_error( + FulfillmentErrorCode::SelectionError(ref selection_error) => self + .report_selection_error( error.obligation.clone(), &error.root_obligation, selection_error, - ); - } + ), FulfillmentErrorCode::ProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e); + self.report_projection_error(&error.obligation, e) } FulfillmentErrorCode::Ambiguity { overflow: false } => { - self.maybe_report_ambiguity(&error.obligation); + self.maybe_report_ambiguity(&error.obligation) } FulfillmentErrorCode::Ambiguity { overflow: true } => { - self.report_overflow_no_abort(error.obligation.clone()); + self.report_overflow_no_abort(error.obligation.clone()) } - FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => { - self.report_mismatched_types( + FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self + .report_mismatched_types( &error.obligation.cause, expected_found.expected, expected_found.found, *err, ) - .emit(); - } + .emit(), FulfillmentErrorCode::ConstEquateError(ref expected_found, ref err) => { let mut diag = self.report_mismatched_consts( &error.obligation.cause, @@ -1620,11 +1622,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &mut Default::default(), ); } - diag.emit(); - } - FulfillmentErrorCode::Cycle(ref cycle) => { - self.report_overflow_obligation_cycle(cycle); + diag.emit() } + FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle), } } @@ -1633,11 +1633,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, - ) { + ) -> ErrorGuaranteed { let predicate = self.resolve_vars_if_possible(obligation.predicate); - if predicate.references_error() { - return; + if let Err(e) = predicate.error_reported() { + return e; } self.probe(|_| { @@ -1802,8 +1802,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false, ); self.note_obligation_cause(&mut diag, obligation); - diag.emit(); - }); + diag.emit() + }) } fn maybe_detailed_projection_msg( @@ -1876,6 +1876,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Coroutine(..) => Some(18), ty::Foreign(..) => Some(19), ty::CoroutineWitness(..) => Some(20), + ty::CoroutineClosure(..) => Some(21), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } @@ -1925,45 +1926,50 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { match kind { hir::ClosureKind::Closure => "a closure", - hir::ClosureKind::Coroutine(kind) => match kind { - hir::CoroutineKind::Coroutine(_) => "a coroutine", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) => "an async block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Fn, - ) => "an async function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure, - ) => "an async closure", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Block, - ) => "an async gen block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Fn, - ) => "an async gen function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Closure, - ) => "an async gen closure", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Block, - ) => "a gen block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Fn, - ) => "a gen function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Closure, - ) => "a gen closure", - }, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + )) => "an async block", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + )) => "an async function", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { + "an async closure" + } + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Block, + )) => "an async gen block", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + )) => "an async gen function", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => { + "an async gen closure" + } + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + )) => "a gen block", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + )) => "a gen function", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => "a gen closure", } } @@ -2059,11 +2065,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }); err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), - ("is".to_string(), Style::Highlight), - (" implemented for `".to_string(), Style::NoStyle), - (cand.self_ty().to_string(), Style::Highlight), - ("`".to_string(), Style::NoStyle), + StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::highlighted("is"), + StringPart::normal(" implemented for `"), + StringPart::highlighted(cand.self_ty().to_string()), + StringPart::normal("`"), ]); if let [TypeError::Sorts(exp_found)] = &terrs[..] { @@ -2095,12 +2101,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => (" implemented for `", ""), }; err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), - ("is".to_string(), Style::Highlight), - (desc.to_string(), Style::NoStyle), - (cand.self_ty().to_string(), Style::Highlight), - ("`".to_string(), Style::NoStyle), - (mention_castable.to_string(), Style::NoStyle), + StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::highlighted("is"), + StringPart::normal(desc), + StringPart::highlighted(cand.self_ty().to_string()), + StringPart::normal("`"), + StringPart::normal(mention_castable), ]); return true; } @@ -2341,7 +2347,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) { + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a @@ -2361,8 +2367,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_ref = bound_predicate.rebind(data.trait_ref); debug!(?trait_ref); - if predicate.references_error() { - return; + if let Err(e) = predicate.error_reported() { + return e; } // This is kind of a hack: it frequently happens that some earlier @@ -2381,17 +2387,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // check upstream for type errors and don't add the obligations to // begin with in those cases. if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { - if let None = self.tainted_by_errors() { - let err = self.emit_inference_failure_err( - obligation.cause.body_id, - span, - trait_ref.self_ty().skip_binder().into(), - ErrorCode::E0282, - false, - ); - err.stash(span, StashKey::MaybeForgetReturn); + match self.tainted_by_errors() { + None => { + let err = self.emit_inference_failure_err( + obligation.cause.body_id, + span, + trait_ref.self_ty().skip_binder().into(), + ErrorCode::E0282, + false, + ); + err.stash(span, StashKey::MaybeForgetReturn); + return self.dcx().delayed_bug("stashed error never reported"); + } + Some(e) => return e, } - return; } // Typically, this ambiguity should only happen if @@ -2450,19 +2459,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { - if self.tainted_by_errors().is_some() && subst.is_none() { + if let Some(e) = self.tainted_by_errors() + && subst.is_none() + { // If `subst.is_none()`, then this is probably two param-env // candidates or impl candidates that are equal modulo lifetimes. // Therefore, if we've already emitted an error, just skip this // one, since it's not particularly actionable. err.cancel(); - return; + return e; } self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate); } else { - if self.tainted_by_errors().is_some() { + if let Some(e) = self.tainted_by_errors() { err.cancel(); - return; + return e; } err.note(format!("cannot satisfy `{predicate}`")); let impl_candidates = self @@ -2493,7 +2504,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expr_finder.visit_expr(self.tcx.hir().body(body_id).value); if let Some(hir::Expr { - kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), + kind: + hir::ExprKind::Call( + hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), + .. + }, + _, + ) + | hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. }) = expr_finder.result && let [ @@ -2529,7 +2548,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { corresponding `impl` type", ), ); - err.code(rustc_errors::error_code!(E0790)); + err.code(E0790); if let Some(local_def_id) = data.trait_ref.def_id.as_local() && let Some(hir::Node::Item(hir::Item { @@ -2605,11 +2624,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { // Same hacky approach as above to avoid deluging user // with error messages. - if arg.references_error() - || self.dcx().has_errors().is_some() - || self.tainted_by_errors().is_some() - { - return; + + if let Err(e) = arg.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; } self.emit_inference_failure_err( @@ -2622,12 +2642,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::PredicateKind::Subtype(data) => { - if data.references_error() - || self.dcx().has_errors().is_some() - || self.tainted_by_errors().is_some() - { - // no need to overload user in such cases - return; + if let Err(e) = data.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; } let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated @@ -2641,8 +2660,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { - if predicate.references_error() || self.tainted_by_errors().is_some() { - return; + if let Err(e) = predicate.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; } let subst = data .projection_ty @@ -2673,8 +2695,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { - if predicate.references_error() || self.tainted_by_errors().is_some() { - return; + if let Err(e) = predicate.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; } let subst = data.walk().find(|g| g.is_non_region_infer()); if let Some(subst) = subst { @@ -2699,8 +2724,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } _ => { - if self.dcx().has_errors().is_some() || self.tainted_by_errors().is_some() { - return; + if let Some(e) = self.tainted_by_errors() { + return e; } struct_span_code_err!( self.dcx(), @@ -2713,7 +2738,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; self.note_obligation_cause(&mut err, obligation); - err.emit(); + err.emit() } fn annotate_source_of_ambiguity( @@ -3162,7 +3187,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ItemObligation(def_id) if self.tcx.is_fn_trait(*def_id) => { - err.code(rustc_errors::error_code!(E0059)); + err.code(E0059); err.primary_message(format!( "type parameter to bare `{}` trait must be a tuple", self.tcx.def_path_str(*def_id) @@ -3433,16 +3458,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span: Span, found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> Option> { + ) -> Result, ErrorGuaranteed> { let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); - if expected_trait_ref.self_ty().references_error() { - return None; - } + expected_trait_ref.self_ty().error_reported()?; let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else { - return None; + return Err(self.dcx().delayed_bug("bound vars outside binder")); }; let found_did = match *found_trait_ty.kind() { @@ -3456,7 +3479,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if !self.reported_signature_mismatch.borrow_mut().insert((span, found_span)) { // We check closures twice, with obligations flowing in different directions, // but we want to complain about them only once. - return None; + return Err(self.dcx().span_delayed_bug(span, "already_reported")); } let mut not_tupled = false; @@ -3485,7 +3508,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // This shouldn't be common unless manually implementing one of the // traits manually, but don't make it more confusing when it does // happen. - Some( + Ok( if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().coroutine_trait() && not_tupled { @@ -3534,9 +3557,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, span: Span, - ) -> Option> { + ) -> Result, ErrorGuaranteed> { if !self.tcx.features().generic_const_exprs { - self.dcx() + let guar = self + .dcx() .struct_span_err(span, "constant expression depends on a generic parameter") // FIXME(const_generics): we should suggest to the user how they can resolve this // issue. However, this is currently not actually possible @@ -3546,7 +3570,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // be reachable. .with_note("this may fail depending on what value the parameter takes") .emit(); - return None; + return Err(guar); } match obligation.predicate.kind().skip_binder() { @@ -3561,13 +3585,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { )), _ => err.help("consider adding a `where` bound using this expression"), }; - Some(err) + Ok(err) } ty::ConstKind::Expr(_) => { let err = self .dcx() .struct_span_err(span, format!("unconstrained generic constant `{ct}`")); - Some(err) + Ok(err) } _ => { bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 0cd376fcbbdc8..93f9c2333f0c0 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -1,5 +1,6 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. +use crate::regions::InferCtxtRegionExt; use crate::traits::{self, ObligationCause, ObligationCtxt}; use hir::LangItem; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 080ad7bd549c8..a7f6021d57a96 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -25,6 +25,7 @@ pub mod wf; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::regions::InferCtxtRegionExt; use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 6e68dee76a24c..3289dfe343e1a 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -161,7 +161,7 @@ fn lint_object_unsafe_trait( ) { // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. // It's also hard to get a use site span, so we use the method definition span. - tcx.struct_span_lint_hir( + tcx.node_span_lint( WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index abbc2066eac16..955c81eee6be3 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1833,10 +1833,28 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( lang_items.fn_trait(), lang_items.fn_mut_trait(), lang_items.fn_once_trait(), + lang_items.async_fn_trait(), + lang_items.async_fn_mut_trait(), + lang_items.async_fn_once_trait(), ].contains(&Some(trait_ref.def_id)) { true - }else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { + } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { + // FIXME(async_closures): Validity constraints here could be cleaned up. + if obligation.predicate.args.type_at(0).is_ty_var() + || obligation.predicate.args.type_at(4).is_ty_var() + || obligation.predicate.args.type_at(5).is_ty_var() + { + candidate_set.mark_ambiguous(); + true + } else if obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() + && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() + { + true + } else { + false + } + } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { match self_ty.kind() { ty::Bool | ty::Char @@ -1854,6 +1872,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::FnPtr(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never @@ -1903,6 +1922,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::FnPtr(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never @@ -2059,6 +2079,10 @@ fn confirm_select_candidate<'cx, 'tcx>( } else { confirm_fn_pointer_candidate(selcx, obligation, data) } + } else if selcx.tcx().async_fn_trait_kind_from_def_id(trait_def_id).is_some() { + confirm_async_closure_candidate(selcx, obligation, data) + } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + confirm_async_fn_kind_helper_candidate(selcx, obligation, data) } else { confirm_builtin_candidate(selcx, obligation, data) } @@ -2419,6 +2443,173 @@ fn confirm_callable_candidate<'cx, 'tcx>( confirm_param_env_candidate(selcx, obligation, predicate, true) } +fn confirm_async_closure_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + mut nested: Vec>, +) -> Progress<'tcx> { + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else { + unreachable!( + "expected coroutine-closure self type for coroutine-closure candidate, found {self_ty}" + ) + }; + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + + let tcx = selcx.tcx(); + let goal_kind = + tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap(); + + let async_fn_kind_helper_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + nested.push(obligation.with( + tcx, + ty::TraitRef::new( + tcx, + async_fn_kind_helper_trait_def_id, + [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], + ), + )); + + let env_region = match goal_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2), + ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, + }; + + let upvars_projection_def_id = tcx + .associated_items(async_fn_kind_helper_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) + .next() + .unwrap() + .def_id; + + // FIXME(async_closures): Confirmation is kind of a mess here. Ideally, + // we'd short-circuit when we know that the goal_kind >= closure_kind, and not + // register a nested predicate or create a new projection ty here. But I'm too + // lazy to make this more efficient atm, and we can always tweak it later, + // since all this does is make the solver do more work. + // + // The code duplication due to the different length args is kind of weird, too. + // + // See the logic in `structural_traits` in the new solver to understand a bit + // more clearly how this *should* look. + let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| { + let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) { + sym::CallOnceFuture => { + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + let coroutine_ty = sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ); + ( + ty::AliasTy::new( + tcx, + obligation.predicate.def_id, + [self_ty, sig.tupled_inputs_ty], + ), + coroutine_ty.into(), + ) + } + sym::CallMutFuture | sym::CallFuture => { + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + let coroutine_ty = sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ); + ( + ty::AliasTy::new( + tcx, + obligation.predicate.def_id, + [ + ty::GenericArg::from(self_ty), + sig.tupled_inputs_ty.into(), + env_region.into(), + ], + ), + coroutine_ty.into(), + ) + } + sym::Output => ( + ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty]), + sig.return_ty.into(), + ), + name => bug!("no such associated type: {name}"), + }; + ty::ProjectionPredicate { projection_ty, term } + }); + + confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true) + .with_addl_obligations(nested) +} + +fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + nested: Vec>, +) -> Progress<'tcx> { + let [ + // We already checked that the goal_kind >= closure_kind + _closure_kind_ty, + goal_kind_ty, + borrow_region, + tupled_inputs_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + ] = **obligation.predicate.args + else { + bug!(); + }; + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new( + selcx.tcx(), + obligation.predicate.def_id, + obligation.predicate.args, + ), + term: ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( + selcx.tcx(), + goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(), + tupled_inputs_ty.expect_ty(), + tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty.expect_ty(), + borrow_region.expect_region(), + ) + .into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) + .with_addl_obligations(nested) +} + fn confirm_param_env_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 138bc6129f7c7..6c8834f11f1eb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -48,7 +48,11 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // (T1..Tn) and closures have same properties as T1..Tn -- // check if *all* of them are trivial. ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), + ty::Closure(_, args) => trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()), + ty::CoroutineClosure(_, args) => { + trivial_dropck_outlives(tcx, args.as_coroutine_closure().tupled_upvars_ty()) + } ty::Adt(def, _) => { if Some(def.did()) == tcx.lang_items().manually_drop() { @@ -232,20 +236,16 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( Ok::<_, NoSolution>(()) })?, - ty::Closure(_, args) => { - if !args.as_closure().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - - tcx.dcx().span_delayed_bug( - span, - format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), - ); - return Err(NoSolution); + ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in args.as_closure().upvar_tys() { + dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?; } + Ok::<_, NoSolution>(()) + })?, + ty::CoroutineClosure(_, args) => { rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in args.as_closure().upvar_tys() { + for ty in args.as_coroutine_closure().upvar_tys() { dtorck_constraint_for_ty_inner( tcx, param_env, @@ -283,15 +283,6 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // derived from lifetimes attached to the upvars and resume // argument, and we *do* incorporate those here. let args = args.as_coroutine(); - if !args.is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - tcx.dcx().span_delayed_bug( - span, - format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",), - ); - return Err(NoSolution); - } // While we conservatively assume that all coroutines require drop // to avoid query cycles during MIR building, we can check the actual 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 957de925dd377..fb09f094d37ae 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 @@ -141,6 +141,13 @@ where infcx: &InferCtxt<'tcx>, span: Span, ) -> Result, ErrorGuaranteed> { + // In the new trait solver, query type ops are performed locally. This + // is because query type ops currently use the old canonicalizer, and + // that doesn't preserve things like opaques which have been registered + // during MIR typeck. Even after the old canonicalizer is gone, it's + // probably worthwhile just keeping this run-locally logic, since we + // probably don't gain much from caching here given the new solver does + // caching internally. if infcx.next_trait_solver() { return Ok(scrape_region_constraints( infcx, 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 342b12ba49848..2258e7961038b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -9,10 +9,13 @@ use hir::def_id::DefId; use hir::LangItem; use rustc_hir as hir; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use crate::traits; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::util; use super::BuiltinImplConditions; @@ -114,10 +117,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_iterator_candidates(obligation, &mut candidates); } else if lang_items.async_iterator_trait() == Some(def_id) { self.assemble_async_iterator_candidates(obligation, &mut candidates); + } else if lang_items.async_fn_kind_helper() == Some(def_id) { + self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates); } + // FIXME: Put these into `else if` blocks above, since they're built-in. self.assemble_closure_candidates(obligation, &mut candidates); + self.assemble_async_closure_candidates(obligation, &mut candidates); self.assemble_fn_pointer_candidates(obligation, &mut candidates); + self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_from_object_ty(obligation, &mut candidates); } @@ -303,11 +311,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - match *obligation.self_ty().skip_binder().kind() { - ty::Closure(def_id, closure_args) => { + let self_ty = obligation.self_ty().skip_binder(); + match *self_ty.kind() { + ty::Closure(def_id, _) => { let is_const = self.tcx().is_const_fn_raw(def_id); debug!(?kind, ?obligation, "assemble_unboxed_candidates"); - match self.infcx.closure_kind(closure_args) { + match self.infcx.closure_kind(self_ty) { Some(closure_kind) => { debug!(?closure_kind, "assemble_unboxed_candidates"); if closure_kind.extends(kind) { @@ -331,6 +340,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_async_closure_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let Some(goal_kind) = + self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()) + else { + return; + }; + + match *obligation.self_ty().skip_binder().kind() { + ty::CoroutineClosure(_, args) => { + if let Some(closure_kind) = + args.as_coroutine_closure().kind_ty().to_opt_closure_kind() + && !closure_kind.extends(goal_kind) + { + return; + } + candidates.vec.push(AsyncClosureCandidate); + } + ty::Infer(ty::TyVar(_)) => { + candidates.ambiguous = true; + } + _ => {} + } + } + + fn assemble_async_fn_kind_helper_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = obligation.self_ty().skip_binder(); + let target_kind_ty = obligation.predicate.skip_binder().trait_ref.args.type_at(1); + + // `to_opt_closure_kind` is kind of ICEy when it sees non-int types. + if !(self_ty.is_integral() || self_ty.is_ty_var()) { + return; + } + if !(target_kind_ty.is_integral() || self_ty.is_ty_var()) { + return; + } + + // Check that the self kind extends the goal kind. If it does, + // then there's nothing else to check. + if let Some(closure_kind) = self_ty.to_opt_closure_kind() + && let Some(goal_kind) = target_kind_ty.to_opt_closure_kind() + { + if closure_kind.extends(goal_kind) { + candidates.vec.push(AsyncFnKindHelperCandidate); + } + } + } + /// Implements one of the `Fn()` family for a fn pointer. fn assemble_fn_pointer_candidates( &mut self, @@ -485,7 +549,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Slice(_) | ty::RawPtr(_) | ty::Ref(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -620,7 +685,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(..) | ty::FnDef(..) | ty::FnPtr(_) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Never | ty::Tuple(_) @@ -723,6 +789,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Temporary migration for #89190 + fn need_migrate_deref_output_trait_object( + &mut self, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: &ObligationCause<'tcx>, + ) -> Option> { + let tcx = self.tcx(); + if tcx.features().trait_upcasting { + return None; + } + + // + let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); + + let obligation = + traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref)); + if !self.infcx.predicate_may_hold(&obligation) { + return None; + } + + self.infcx.probe(|_| { + let ty = traits::normalize_projection_type( + self, + param_env, + ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args), + cause.clone(), + 0, + // We're *intentionally* throwing these away, + // since we don't actually use them. + &mut vec![], + ) + .ty() + .unwrap(); + + if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None } + }) + } + /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -780,6 +885,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal_a = a_data.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( + source, + obligation.param_env, + &obligation.cause, + ) { + if deref_trait_ref.def_id() == target_trait_did { + return; + } + } for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() @@ -949,6 +1063,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Slice(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Tuple(_) | ty::CoroutineWitness(..) => { @@ -1025,7 +1140,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -1088,6 +1204,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Placeholder(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 74f388e53a3c9..c9d06b0f67521 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -83,6 +83,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) } + AsyncClosureCandidate => { + let vtable_closure = self.confirm_async_closure_candidate(obligation)?; + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) + } + + // No nested obligations or confirmation process. The checks that we do in + // candidate assembly are sufficient. + AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]), + CoroutineCandidate => { let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?; ImplSource::Builtin(BuiltinImplSource::Misc, vtable_coroutine) @@ -869,6 +878,49 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(nested) } + #[instrument(skip(self), level = "debug")] + fn confirm_async_closure_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + // Okay to skip binder because the args on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let ty::CoroutineClosure(closure_def_id, args) = *self_ty.kind() else { + bug!("async closure candidate for non-coroutine-closure {:?}", obligation); + }; + + let trait_ref = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, sig.tupled_inputs_ty], + ) + }); + + let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + + let goal_kind = + self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); + nested.push(obligation.with( + self.tcx(), + ty::TraitRef::from_lang_item( + self.tcx(), + LangItem::AsyncFnKindHelper, + obligation.cause.span, + [ + args.as_coroutine_closure().kind_ty(), + Ty::from_closure_kind(self.tcx(), goal_kind), + ], + ), + )); + + debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); + + Ok(nested) + } + /// In the case of closure types and fn pointers, /// we currently treat the input type parameters on the trait as /// outputs. This means that when we have a match we have only diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6a6adcbb680ea..7f41c73b72f0d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1864,6 +1864,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -1894,6 +1896,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(_) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -1930,6 +1934,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -1946,6 +1952,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -2054,6 +2062,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ImplCandidate(_) | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -2066,6 +2076,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitAliasCandidate, ImplCandidate(_) | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -2106,6 +2118,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { @@ -2227,6 +2240,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + // FIXME(async_closures): These are never clone, for now. + ty::CoroutineClosure(_, _) => None, + ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { // Fallback to whatever user-defined impls exist in this case. None @@ -2305,6 +2321,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { t.rebind(vec![ty]) } + ty::CoroutineClosure(_, args) => { + let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); + t.rebind(vec![ty]) + } + ty::Coroutine(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b37d9714ddd8c..de08e7d2f0384 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 crate::traits::{ self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, }; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{error_code, DelayDm, Diagnostic}; +use rustc_errors::{codes::*, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; @@ -387,7 +387,7 @@ fn report_conflicting_impls<'tcx>( let impl_span = tcx.def_span(impl_def_id); // Work to be done after we've built the DiagnosticBuilder. We have to define it - // now because the struct_lint methods don't return back the DiagnosticBuilder + // now because the lint emit methods don't return back the DiagnosticBuilder // that's passed in. fn decorate<'tcx>( tcx: TyCtxt<'tcx>, @@ -449,7 +449,7 @@ fn report_conflicting_impls<'tcx>( || tcx.orphan_check_impl(impl_def_id).is_ok() { let mut err = tcx.dcx().struct_span_err(impl_span, msg); - err.code(error_code!(E0119)); + err.code(E0119); decorate(tcx, &overlap, impl_span, &mut err); err.emit() } else { @@ -462,7 +462,7 @@ fn report_conflicting_impls<'tcx>( FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS, FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; - tcx.struct_span_lint_hir( + tcx.node_span_lint( lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 868a8a3e8b85f..89459f377dd2b 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -39,7 +39,7 @@ pub fn search_for_structural_match_violation<'tcx>( /// This implements the traversal over the structure of a given type to try to /// find instances of ADTs (specifically structs or enums) that do not implement -/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`). +/// `StructuralPartialEq`. struct Search<'tcx> { span: Span, @@ -79,6 +79,9 @@ impl<'tcx> TypeVisitor> for Search<'tcx> { ty::Closure(..) => { return ControlFlow::Break(ty); } + ty::CoroutineClosure(..) => { + return ControlFlow::Break(ty); + } ty::Coroutine(..) | ty::CoroutineWitness(..) => { return ControlFlow::Break(ty); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0f8d9c6bf4bdb..b4f13ee95a652 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -727,6 +727,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); } + ty::CoroutineClosure(did, args) => { + // See the above comments. The same apply to coroutine-closures. + walker.skip_current_subtree(); + self.compute(args.as_coroutine_closure().tupled_upvars_ty().into()); + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + } + ty::FnPtr(_) => { // let the loop iterate into the argument/return // types appearing in the fn signature diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index dfa5814219bc2..c7916ec60bba2 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -2,7 +2,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -#![feature(let_chains)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 4b55963201717..c80389a3a4d52 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,4 +1,5 @@ -#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)] +#![feature(alloc_layout_extra)] +#![feature(never_type)] #![allow(dead_code, unused_variables)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 333aec1d38d7f..0542ef4ecf902 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -101,6 +101,49 @@ fn fn_sig_for_fn_abi<'tcx>( bound_vars, ) } + ty::CoroutineClosure(def_id, args) => { + let sig = args.as_coroutine_closure().coroutine_closure_sig(); + let bound_vars = tcx.mk_bound_variable_kinds_from_iter( + sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::BrEnv, + }; + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + + // When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`, + // make sure we respect the `target_kind` in that shim. + // FIXME(async_closures): This shouldn't be needed, and we should be populating + // a separate def-id for these bodies. + let mut kind = args.as_coroutine_closure().kind(); + if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def { + kind = target_kind; + } + + let env_ty = + tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region); + + let sig = sig.skip_binder(); + ty::Binder::bind_with_vars( + tcx.mk_fn_sig( + iter::once(env_ty).chain([sig.tupled_inputs_ty]), + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(def_id), + kind, + env_region, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ), + sig.c_variadic, + sig.unsafety, + sig.abi, + ), + bound_vars, + ) + } ty::Coroutine(did, args) => { let coroutine_kind = tcx.coroutine_kind(did).unwrap(); let sig = args.as_coroutine().sig(); @@ -112,6 +155,40 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; + + let mut ty = ty; + // When this `Closure` comes from a `CoroutineKindShim`, + // make sure we respect the `target_kind` in that shim. + // FIXME(async_closures): This shouldn't be needed, and we should be populating + // a separate def-id for these bodies. + if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def { + // Grab the parent coroutine-closure. It has the same args for the purposes + // of substitution, so this will be okay to do. + let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx + .instantiate_and_normalize_erasing_regions( + args, + param_env, + tcx.type_of(tcx.parent(did)), + ) + .kind() + else { + bug!("CoroutineKindShim comes from calling a coroutine-closure"); + }; + let coroutine_closure_args = coroutine_closure_args.as_coroutine_closure(); + ty = tcx.instantiate_bound_regions_with_erased( + coroutine_closure_args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine_given_kind_and_upvars( + tcx, + coroutine_closure_args.parent_args(), + did, + target_kind, + tcx.lifetimes.re_erased, + coroutine_closure_args.tupled_upvars_ty(), + coroutine_closure_args.coroutine_captures_by_ref_ty(), + ) + }), + ); + } let env_ty = Ty::new_mut_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); @@ -258,7 +335,6 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { PtxKernel => Conv::PtxKernel, Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, AvrInterrupt => Conv::AvrInterrupt, AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }, diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 947d4bbe86e1c..bfbb45f0cb501 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -1,5 +1,6 @@ //! Errors emitted by ty_utils +use rustc_errors::codes::*; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; @@ -113,7 +114,7 @@ pub struct DuplicateArg<'tcx> { } #[derive(Diagnostic)] -#[diag(ty_utils_impl_trait_not_param, code = "E0792")] +#[diag(ty_utils_impl_trait_not_param, code = E0792)] pub struct NotParam<'tcx> { pub arg: GenericArg<'tcx>, #[primary_span] diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 81d5304b81265..9faad10dd14df 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -38,6 +38,7 @@ fn resolve_instance<'tcx>( debug!(" => nontrivial drop glue"); match *ty.kind() { ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Tuple(..) | ty::Adt(..) @@ -215,6 +216,7 @@ fn resolve_associated_item<'tcx>( ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Tuple(..) => {} _ => return Ok(None), }; @@ -245,63 +247,6 @@ fn resolve_associated_item<'tcx>( span: tcx.def_span(trait_item_id), }) } - } else if Some(trait_ref.def_id) == lang_items.future_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - if Some(trait_item_id) == tcx.lang_items().future_poll_fn() { - // `Future::poll` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args: args }) - } else { - // All other methods are default methods of the `Future` trait. - // (this assumes that `ImplSource::Builtin` is only used for methods on `Future`) - debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_args)) - } - } else if Some(trait_ref.def_id) == lang_items.iterator_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - if Some(trait_item_id) == tcx.lang_items().next_fn() { - // `Iterator::next` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) - } else { - // All other methods are default methods of the `Iterator` trait. - // (this assumes that `ImplSource::Builtin` is only used for methods on `Iterator`) - debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_args)) - } - } else if Some(trait_ref.def_id) == lang_items.async_iterator_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - - if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::poll_next { - span_bug!( - tcx.def_span(coroutine_def_id), - "no definition for `{trait_ref}::{}` for built-in coroutine type", - tcx.item_name(trait_item_id) - ) - } - - // `AsyncIterator::poll_next` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) - } else if Some(trait_ref.def_id) == lang_items.coroutine_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume { - // For compiler developers who'd like to add new items to `Coroutine`, - // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if - // it is given a default implementation by the trait. - span_bug!( - tcx.def_span(coroutine_def_id), - "no definition for `{trait_ref}::{}` for built-in coroutine type", - tcx.item_name(trait_item_id) - ) - } - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { // FIXME: This doesn't check for malformed libcore that defines, e.g., // `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension @@ -322,7 +267,12 @@ fn resolve_associated_item<'tcx>( match *rcvr_args.type_at(0).kind() { ty::Closure(closure_def_id, args) => { let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); - Instance::resolve_closure(tcx, closure_def_id, args, trait_closure_kind) + Some(Instance::resolve_closure( + tcx, + closure_def_id, + args, + trait_closure_kind, + )) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), @@ -333,8 +283,36 @@ fn resolve_associated_item<'tcx>( tcx.item_name(trait_item_id) ), } + } else if let Some(target_kind) = tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id) + { + match *rcvr_args.type_at(0).kind() { + ty::CoroutineClosure(coroutine_closure_def_id, args) => { + // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure, + // or `AsyncFnOnce` for a by-mut closure, then construct a new body that + // has the right return types. + // + // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs + // to have its input and output types fixed (`&mut self` and returning + // `i16` coroutine kind). + if target_kind > args.as_coroutine_closure().kind() { + Some(Instance { + def: ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind, + }, + args, + }) + } else { + Some(Instance::new(coroutine_closure_def_id, args)) + } + } + _ => bug!( + "no built-in definition for `{trait_ref}::{}` for non-lending-closure type", + tcx.item_name(trait_item_id) + ), + } } else { - None + Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) } } traits::ImplSource::Param(..) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 2fc4bfd4aa31c..f20ded355b1cd 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -328,6 +328,17 @@ fn layout_of_uncached<'tcx>( )? } + ty::CoroutineClosure(_, args) => { + let tys = args.as_coroutine_closure().upvar_tys(); + univariant( + &tys.iter() + .map(|ty| Ok(cx.layout_of(ty)?.layout)) + .try_collect::>()?, + &ReprOptions::default(), + StructKind::AlwaysSized, + )? + } + ty::Tuple(tys) => { let kind = if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index fa1f94e8b41e8..51acb99d29b58 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -15,7 +15,6 @@ #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(never_type)] -#![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 08e5476ae43b7..7b3d2ab22cfa4 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -172,6 +172,12 @@ where } } + ty::CoroutineClosure(_, args) => { + for upvar in args.as_coroutine_closure().upvar_tys() { + queue_type(self, upvar); + } + } + // Check for a `Drop` impl and whether this is a union or // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 0bb833c66fa76..ef67317a601ac 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -118,6 +118,69 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } TaitInBodyFinder { collector: self }.visit_expr(body); } + + fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) { + if !self.seen.insert(alias_ty.def_id.expect_local()) { + return; + } + + // TAITs outside their defining scopes are ignored. + let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); + trace!(?origin); + match origin { + rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {} + rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + if !in_assoc_ty { + if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { + return; + } + } + } + } + + self.opaques.push(alias_ty.def_id.expect_local()); + + let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count; + // Only check that the parent generics of the TAIT/RPIT are unique. + // the args owned by the opaque are going to always be duplicate + // lifetime params for RPITs, and empty for TAITs. + match self + .tcx + .uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::FromFunction) + { + Ok(()) => { + // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not + // supported at all, so this is sound to do, but once we want to support them, you'll + // start seeing the error below. + + // Collect opaque types nested within the associated type bounds of this opaque type. + // We use identity args here, because we already know that the opaque type uses + // only generic parameters, and thus substituting would not give us more information. + for (pred, span) in self + .tcx + .explicit_item_bounds(alias_ty.def_id) + .instantiate_identity_iter_copied() + { + trace!(?pred); + self.visit_spanned(span, pred); + } + } + Err(NotUniqueParam::NotParam(arg)) => { + self.tcx.dcx().emit_err(NotParam { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + } + Err(NotUniqueParam::DuplicateParam(arg)) => { + self.tcx.dcx().emit_err(DuplicateArg { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + } + } + } } impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> { @@ -134,67 +197,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { t.super_visit_with(self)?; match t.kind() { ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => { - if !self.seen.insert(alias_ty.def_id.expect_local()) { - return ControlFlow::Continue(()); - } - - // TAITs outside their defining scopes are ignored. - let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); - trace!(?origin); - match origin { - rustc_hir::OpaqueTyOrigin::FnReturn(_) - | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {} - rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { - if !in_assoc_ty { - if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { - return ControlFlow::Continue(()); - } - } - } - } - - self.opaques.push(alias_ty.def_id.expect_local()); - - let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count; - // Only check that the parent generics of the TAIT/RPIT are unique. - // the args owned by the opaque are going to always be duplicate - // lifetime params for RPITs, and empty for TAITs. - match self.tcx.uses_unique_generic_params( - &alias_ty.args[..parent_count], - CheckRegions::FromFunction, - ) { - Ok(()) => { - // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not - // supported at all, so this is sound to do, but once we want to support them, you'll - // start seeing the error below. - - // Collect opaque types nested within the associated type bounds of this opaque type. - // We use identity args here, because we already know that the opaque type uses - // only generic parameters, and thus substituting would not give us more information. - for (pred, span) in self - .tcx - .explicit_item_bounds(alias_ty.def_id) - .instantiate_identity_iter_copied() - { - trace!(?pred); - self.visit_spanned(span, pred); - } - } - Err(NotUniqueParam::NotParam(arg)) => { - self.tcx.dcx().emit_err(NotParam { - arg, - span: self.span(), - opaque_span: self.tcx.def_span(alias_ty.def_id), - }); - } - Err(NotUniqueParam::DuplicateParam(arg)) => { - self.tcx.dcx().emit_err(DuplicateArg { - arg, - span: self.span(), - opaque_span: self.tcx.def_span(alias_ty.def_id), - }); - } - } + self.visit_opaque_ty(alias_ty); } ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => { self.tcx @@ -272,6 +275,91 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } } +struct ImplTraitInAssocTypeCollector<'tcx>(OpaqueTypeCollector<'tcx>); + +impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> { + #[instrument(skip(self), ret, level = "trace")] + fn visit(&mut self, span: Span, value: impl TypeVisitable>) -> ControlFlow { + let old = self.0.span; + self.0.span = Some(span); + value.visit_with(self); + self.0.span = old; + + ControlFlow::Continue(()) + } +} + +impl<'tcx> TypeVisitor> for ImplTraitInAssocTypeCollector<'tcx> { + #[instrument(skip(self), ret, level = "trace")] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + t.super_visit_with(self)?; + match t.kind() { + ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => { + self.0.visit_opaque_ty(alias_ty); + } + ty::Alias(ty::Projection, alias_ty) => { + // This avoids having to do normalization of `Self::AssocTy` by only + // supporting the case of a method defining opaque types from assoc types + // in the same impl block. + let parent_trait_ref = self + .0 + .parent_trait_ref() + .expect("impl trait in assoc type collector used on non-assoc item"); + // If the trait ref of the associated item and the impl differs, + // then we can't use the impl's identity substitutions below, so + // just skip. + if alias_ty.trait_ref(self.0.tcx) == parent_trait_ref { + let parent = self.0.parent().expect("we should have a parent here"); + + for &assoc in self.0.tcx.associated_items(parent).in_definition_order() { + trace!(?assoc); + if assoc.trait_item_def_id != Some(alias_ty.def_id) { + continue; + } + + // If the type is further specializable, then the type_of + // is not actually correct below. + if !assoc.defaultness(self.0.tcx).is_final() { + continue; + } + + let impl_args = alias_ty.args.rebase_onto( + self.0.tcx, + parent_trait_ref.def_id, + ty::GenericArgs::identity_for_item(self.0.tcx, parent), + ); + + if check_args_compatible(self.0.tcx, assoc, impl_args) { + return self + .0 + .tcx + .type_of(assoc.def_id) + .instantiate(self.0.tcx, impl_args) + .visit_with(self); + } else { + self.0.tcx.dcx().span_delayed_bug( + self.0.tcx.def_span(assoc.def_id), + "item had incorrect args", + ); + } + } + } + } + _ => trace!(kind=?t.kind()), + } + ControlFlow::Continue(()) + } +} + +fn impl_trait_in_assoc_types_defined_by<'tcx>( + tcx: TyCtxt<'tcx>, + item: LocalDefId, +) -> &'tcx ty::List { + let mut collector = ImplTraitInAssocTypeCollector(OpaqueTypeCollector::new(tcx, item)); + super::sig_types::walk_types(tcx, item, &mut collector); + tcx.mk_local_def_ids(&collector.0.opaques) +} + fn opaque_types_defined_by<'tcx>( tcx: TyCtxt<'tcx>, item: LocalDefId, @@ -321,5 +409,6 @@ fn opaque_types_defined_by<'tcx>( } pub(super) fn provide(providers: &mut Providers) { - *providers = Providers { opaque_types_defined_by, ..*providers }; + *providers = + Providers { opaque_types_defined_by, impl_trait_in_assoc_types_defined_by, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 6e7a9887774f8..241aff9c30a00 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -6,13 +6,12 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// This method returns true if and only if `adt_ty` itself has been marked as -/// eligible for structural-match: namely, if it implements both -/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by -/// `#[derive(PartialEq)]` and `#[derive(Eq)]`). +/// eligible for structural-match: namely, if it implements +/// `StructuralPartialEq` (which is injected by `#[derive(PartialEq)]`). /// /// Note that this does *not* recursively check if the substructure of `adt_ty` -/// implements the traits. -fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { +/// implements the trait. +fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { let infcx = &tcx.infer_ctxt().build(); let cause = ObligationCause::dummy(); @@ -21,11 +20,6 @@ fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { let structural_peq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id); - // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around - // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) - let structural_teq_def_id = - infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span)); - ocx.register_bound(cause, ty::ParamEnv::empty(), adt_ty, structural_teq_def_id); // We deliberately skip *reporting* fulfillment errors (via // `report_fulfillment_errors`), for two reasons: @@ -40,5 +34,5 @@ fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { } pub(crate) fn provide(providers: &mut Providers) { - providers.has_structural_eq_impls = has_structural_eq_impls; + providers.has_structural_eq_impl = has_structural_eq_impl; } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2158aacab03d8..60b1bbe8c2a5f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -18,7 +18,9 @@ fn sized_constraint_for_ty<'tcx>( let result = match ty.kind() { Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) - | FnPtr(_) | Array(..) | Closure(..) | Coroutine(..) | Never => vec![], + | FnPtr(_) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..) | Never => { + vec![] + } Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | CoroutineWitness(..) => { // these are never sized - return the target type diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index bff938596458a..83efbfb855f91 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -327,21 +327,21 @@ impl UniverseIndex { /// name the region `'a`, but that region was not nameable from /// `U` because it was not in scope there. pub fn next_universe(self) -> UniverseIndex { - UniverseIndex::from_u32(self.private.checked_add(1).unwrap()) + UniverseIndex::from_u32(self.as_u32().checked_add(1).unwrap()) } /// Returns `true` if `self` can name a name from `other` -- in other words, /// if the set of names in `self` is a superset of those in /// `other` (`self >= other`). pub fn can_name(self, other: UniverseIndex) -> bool { - self.private >= other.private + self >= other } /// Returns `true` if `self` cannot name some names from `other` -- in other /// words, if the set of names in `self` is a strict subset of /// those in `other` (`self < other`). pub fn cannot_name(self, other: UniverseIndex) -> bool { - self.private < other.private + self < other } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 859000fb6cb18..a4fe572067b03 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -202,6 +202,13 @@ pub enum TyKind { /// `ClosureArgs` for more details. Closure(I::DefId, I::GenericArgs), + /// The anonymous type of a closure. Used to represent the type of `async |a| a`. + /// + /// Coroutine-closure args contain both the - potentially substituted - generic + /// parameters of its parent and some synthetic parameters. See the documentation + /// for `CoroutineClosureArgs` for more details. + CoroutineClosure(I::DefId, I::GenericArgs), + /// The anonymous type of a coroutine. Used to represent the type of /// `|a| yield a`. /// @@ -317,16 +324,17 @@ const fn tykind_discriminant(value: &TyKind) -> usize { FnPtr(_) => 13, Dynamic(..) => 14, Closure(_, _) => 15, - Coroutine(_, _) => 16, - CoroutineWitness(_, _) => 17, - Never => 18, - Tuple(_) => 19, - Alias(_, _) => 20, - Param(_) => 21, - Bound(_, _) => 22, - Placeholder(_) => 23, - Infer(_) => 24, - Error(_) => 25, + CoroutineClosure(_, _) => 16, + Coroutine(_, _) => 17, + CoroutineWitness(_, _) => 18, + Never => 19, + Tuple(_) => 20, + Alias(_, _) => 21, + Param(_) => 22, + Bound(_, _) => 23, + Placeholder(_) => 24, + Infer(_) => 25, + Error(_) => 26, } } @@ -356,6 +364,7 @@ impl PartialEq for TyKind { a_p == b_p && a_r == b_r && a_repr == b_repr } (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s, + (CoroutineClosure(a_d, a_s), CoroutineClosure(b_d, b_s)) => a_d == b_d && a_s == b_s, (Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s, (CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s, (Tuple(a_t), Tuple(b_t)) => a_t == b_t, @@ -430,6 +439,9 @@ impl DebugWithInfcx for TyKind { } }, Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(), + CoroutineClosure(d, s) => { + f.debug_tuple("CoroutineClosure").field(d).field(&this.wrap(s)).finish() + } Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).finish(), CoroutineWitness(d, s) => { f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish() diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 53dac6abefb30..a15fd3e0999bd 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -275,7 +275,6 @@ pub enum CallConvention { X86_64SysV, X86_64Win64, - AmdGpuKernel, AvrInterrupt, AvrNonBlockingInterrupt, diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index de5dfcdf207f7..4f57f532a40c9 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -16,7 +16,6 @@ //! //! The goal is to eventually be published on //! [crates.io](https://crates.io). -#![feature(type_alias_impl_trait)] #[macro_use] extern crate scoped_tls; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index eba2ac57012b9..bdda929534705 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -12,7 +12,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct Ty(pub usize); +pub struct Ty(usize); impl Debug for Ty { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -138,7 +138,7 @@ impl Const { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct ConstId(pub usize); +pub struct ConstId(usize); type Ident = Opaque; @@ -864,7 +864,6 @@ pub enum Abi { PtxKernel, Msp430Interrupt, X86Interrupt, - AmdGpuKernel, EfiApi, AvrInterrupt, AvrNonBlockingInterrupt, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 1663aa84921c9..0b1429397559d 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -3,7 +3,7 @@ #![stable(feature = "alloc_module", since = "1.28.0")] #[cfg(not(test))] -use core::intrinsics; +use core::hint; #[cfg(not(test))] use core::ptr::{self, NonNull}; @@ -208,7 +208,7 @@ impl Global { let new_size = new_layout.size(); // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. - intrinsics::assume(new_size >= old_layout.size()); + hint::assert_unchecked(new_size >= old_layout.size()); let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; @@ -299,7 +299,7 @@ unsafe impl Allocator for Global { // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller new_size if old_layout.align() == new_layout.align() => unsafe { // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. - intrinsics::assume(new_size <= old_layout.size()); + hint::assert_unchecked(new_size <= old_layout.size()); let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 6977681e5a397..953041b8c202b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -191,8 +191,7 @@ mod thin; #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] // The declaration of the `Box` struct must be kept in sync with the -// `alloc::alloc::box_free` function or ICEs will happen. See the comment -// on `box_free` for more details. +// compiler or ICEs will happen. pub struct Box< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -2285,7 +2284,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { +impl<'a> From for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// /// # Examples @@ -2300,7 +2299,7 @@ impl From for Box { /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` #[inline] - fn from(err: String) -> Box { + fn from(err: String) -> Box { struct StringError(String); impl Error for StringError { @@ -2329,7 +2328,7 @@ impl From for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_box_error", since = "1.6.0")] -impl From for Box { +impl<'a> From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. /// /// # Examples @@ -2342,7 +2341,7 @@ impl From for Box { /// let a_boxed_error = Box::::from(a_string_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(str_err: String) -> Box { + fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); let err2: Box = err1; err2 @@ -2375,7 +2374,7 @@ impl<'a> From<&str> for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_box_error", since = "1.6.0")] -impl From<&str> for Box { +impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// /// [`str`]: prim@str @@ -2390,7 +2389,7 @@ impl From<&str> for Box { /// let a_boxed_error = Box::::from(a_str_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(err: &str) -> Box { + fn from(err: &str) -> Box { From::from(String::from(err)) } } @@ -2419,7 +2418,7 @@ impl<'a, 'b> From> for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a> From> for Box { +impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. /// /// # Examples @@ -2433,7 +2432,7 @@ impl<'a> From> for Box { /// let a_boxed_error = Box::::from(a_cow_str_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(err: Cow<'a, str>) -> Box { + fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) } } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 4bdd9639557d4..b585e2082f137 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1,6 +1,7 @@ use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering; +use core::error::Error; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; @@ -2521,14 +2522,10 @@ impl BTreeMap { self.len() == 0 } - /// Returns a [`Cursor`] pointing at the first element that is above the - /// given bound. + /// Returns a [`Cursor`] pointing to the first gap above the given bound. /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. - /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start + /// of the map. /// /// # Examples /// @@ -2542,14 +2539,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); + /// a.insert(4, "d"); /// let cursor = a.lower_bound(Bound::Included(&2)); - /// assert_eq!(cursor.key(), Some(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&1, &"a"))); + /// assert_eq!(cursor.peek_next(), Some((&2, &"b"))); /// let cursor = a.lower_bound(Bound::Excluded(&2)); - /// assert_eq!(cursor.key(), Some(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &"c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where K: Borrow + Ord, Q: Ord, @@ -2559,17 +2558,14 @@ impl BTreeMap { Some(root) => root.reborrow(), }; let edge = root_node.lower_bound(SearchBound::from_range(bound)); - Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() } + Cursor { current: Some(edge), root: self.root.as_ref() } } - /// Returns a [`CursorMut`] pointing at the first element that is above the - /// given bound. + /// Returns a [`CursorMut`] pointing to the first gap above the given bound. /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start + /// of the map. /// /// # Examples /// @@ -2583,14 +2579,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); - /// let cursor = a.lower_bound_mut(Bound::Included(&2)); - /// assert_eq!(cursor.key(), Some(&2)); - /// let cursor = a.lower_bound_mut(Bound::Excluded(&2)); - /// assert_eq!(cursor.key(), Some(&3)); + /// a.insert(4, "d"); + /// let mut cursor = a.lower_bound_mut(Bound::Included(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&1, &mut "a"))); + /// assert_eq!(cursor.peek_next(), Some((&2, &mut "b"))); + /// let mut cursor = a.lower_bound_mut(Bound::Excluded(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> where K: Borrow + Ord, Q: Ord, @@ -2599,31 +2597,31 @@ impl BTreeMap { let root_node = match root.as_mut() { None => { return CursorMut { - current: None, - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: None, + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, }; } Some(root) => root.borrow_mut(), }; let edge = root_node.lower_bound(SearchBound::from_range(bound)); CursorMut { - current: edge.next_kv().ok(), - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: Some(edge), + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, } } - /// Returns a [`Cursor`] pointing at the last element that is below the - /// given bound. - /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. + /// Returns a [`Cursor`] pointing at the last gap below the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end + /// of the map. /// /// # Examples /// @@ -2637,14 +2635,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); + /// a.insert(4, "d"); /// let cursor = a.upper_bound(Bound::Included(&3)); - /// assert_eq!(cursor.key(), Some(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&3, &"c"))); + /// assert_eq!(cursor.peek_next(), Some((&4, &"d"))); /// let cursor = a.upper_bound(Bound::Excluded(&3)); - /// assert_eq!(cursor.key(), Some(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &"c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where K: Borrow + Ord, Q: Ord, @@ -2654,17 +2654,13 @@ impl BTreeMap { Some(root) => root.reborrow(), }; let edge = root_node.upper_bound(SearchBound::from_range(bound)); - Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() } + Cursor { current: Some(edge), root: self.root.as_ref() } } - /// Returns a [`CursorMut`] pointing at the last element that is below the - /// given bound. - /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. + /// Returns a [`CursorMut`] pointing at the last gap below the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end + /// of the map. /// /// # Examples /// @@ -2678,14 +2674,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); - /// let cursor = a.upper_bound_mut(Bound::Included(&3)); - /// assert_eq!(cursor.key(), Some(&3)); - /// let cursor = a.upper_bound_mut(Bound::Excluded(&3)); - /// assert_eq!(cursor.key(), Some(&2)); + /// a.insert(4, "d"); + /// let mut cursor = a.upper_bound_mut(Bound::Included(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&3, &mut "c"))); + /// assert_eq!(cursor.peek_next(), Some((&4, &mut "d"))); + /// let mut cursor = a.upper_bound_mut(Bound::Excluded(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> where K: Borrow + Ord, Q: Ord, @@ -2694,20 +2692,24 @@ impl BTreeMap { let root_node = match root.as_mut() { None => { return CursorMut { - current: None, - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: None, + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, }; } Some(root) => root.borrow_mut(), }; let edge = root_node.upper_bound(SearchBound::from_range(bound)); CursorMut { - current: edge.next_back_kv().ok(), - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: Some(edge), + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, } } } @@ -2716,14 +2718,14 @@ impl BTreeMap { /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. /// -/// Cursors always point to an element in the tree, and index in a logically circular way. -/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and -/// first elements of the tree. +/// Cursors always point to a gap between two elements in the map, and can +/// operate on the two immediately adjacent elements. /// /// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods. #[unstable(feature = "btree_cursors", issue = "107540")] pub struct Cursor<'a, K: 'a, V: 'a> { - current: Option, K, V, marker::LeafOrInternal>, marker::KV>>, + // If current is None then it means the tree has not been allocated yet. + current: Option, K, V, marker::Leaf>, marker::Edge>>, root: Option<&'a node::Root>, } @@ -2738,22 +2740,21 @@ impl Clone for Cursor<'_, K, V> { #[unstable(feature = "btree_cursors", issue = "107540")] impl Debug for Cursor<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Cursor").field(&self.key_value()).finish() + f.write_str("Cursor") } } /// A cursor over a `BTreeMap` with editing operations. /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can -/// safely mutate the tree during iteration. This is because the lifetime of its yielded -/// references is tied to its own lifetime, instead of just the underlying tree. This means +/// safely mutate the map during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying map. This means /// cursors cannot yield multiple elements at once. /// -/// Cursors always point to an element in the tree, and index in a logically circular way. -/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and -/// first elements of the tree. +/// Cursors always point to a gap between two elements in the map, and can +/// operate on the two immediately adjacent elements. /// -/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`] +/// A `CursorMut` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`] /// methods. #[unstable(feature = "btree_cursors", issue = "107540")] pub struct CursorMut< @@ -2762,287 +2763,271 @@ pub struct CursorMut< V: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global, > { - current: Option, K, V, marker::LeafOrInternal>, marker::KV>>, + inner: CursorMutKey<'a, K, V, A>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Debug for CursorMut<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("CursorMut") + } +} + +/// A cursor over a `BTreeMap` with editing operations, and which allows +/// mutating the key of elements. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the map during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying map. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always point to a gap between two elements in the map, and can +/// operate on the two immediately adjacent elements. +/// +/// A `CursorMutKey` is created from a [`CursorMut`] with the +/// [`CursorMut::with_mutable_key`] method. +/// +/// # Safety +/// +/// Since this cursor allows mutating keys, you must ensure that the `BTreeMap` +/// invariants are maintained. Specifically: +/// +/// * The key of the newly inserted element must be unique in the tree. +/// * All keys in the tree must remain in sorted order. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct CursorMutKey< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A = Global, +> { + // If current is None then it means the tree has not been allocated yet. + current: Option, K, V, marker::Leaf>, marker::Edge>>, root: DormantMutRef<'a, Option>>, length: &'a mut usize, alloc: &'a mut A, } #[unstable(feature = "btree_cursors", issue = "107540")] -impl Debug for CursorMut<'_, K, V, A> { +impl Debug for CursorMutKey<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("CursorMut").field(&self.key_value()).finish() + f.write_str("CursorMutKey") } } impl<'a, K, V> Cursor<'a, K, V> { - /// Moves the cursor to the next element of the `BTreeMap`. + /// Advances the cursor to the next gap, returning the key and value of the + /// element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the end of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_next(&mut self) { - match self.current.take() { - None => { - self.current = self.root.and_then(|root| { - root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok() - }); + pub fn next(&mut self) -> Option<(&'a K, &'a V)> { + let current = self.current.take()?; + match current.next_kv() { + Ok(kv) => { + let result = kv.into_kv(); + self.current = Some(kv.next_leaf_edge()); + Some(result) } - Some(current) => { - self.current = current.next_leaf_edge().next_kv().ok(); + Err(root) => { + self.current = Some(root.last_leaf_edge()); + None } } } - /// Moves the cursor to the previous element of the `BTreeMap`. + /// Advances the cursor to the previous gap, returning the key and value of + /// the element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the start of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_prev(&mut self) { - match self.current.take() { - None => { - self.current = self.root.and_then(|root| { - root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok() - }); + pub fn prev(&mut self) -> Option<(&'a K, &'a V)> { + let current = self.current.take()?; + match current.next_back_kv() { + Ok(kv) => { + let result = kv.into_kv(); + self.current = Some(kv.next_back_leaf_edge()); + Some(result) } - Some(current) => { - self.current = current.next_back_leaf_edge().next_back_kv().ok(); + Err(root) => { + self.current = Some(root.first_leaf_edge()); + None } } } - /// Returns a reference to the key of the element that the cursor is - /// currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key(&self) -> Option<&'a K> { - self.current.as_ref().map(|current| current.into_kv().0) - } - - /// Returns a reference to the value of the element that the cursor is - /// currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn value(&self) -> Option<&'a V> { - self.current.as_ref().map(|current| current.into_kv().1) - } - - /// Returns a reference to the key and value of the element that the cursor - /// is currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key_value(&self) -> Option<(&'a K, &'a V)> { - self.current.as_ref().map(|current| current.into_kv()) - } - - /// Returns a reference to the next element. + /// Returns a reference to the the key and value of the next element without + /// moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the end of the map then `None` is returned #[unstable(feature = "btree_cursors", issue = "107540")] pub fn peek_next(&self) -> Option<(&'a K, &'a V)> { - let mut next = self.clone(); - next.move_next(); - next.current.as_ref().map(|current| current.into_kv()) + self.clone().next() } - /// Returns a reference to the previous element. + /// Returns a reference to the the key and value of the previous element + /// without moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the start of the map then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> { - let mut prev = self.clone(); - prev.move_prev(); - prev.current.as_ref().map(|current| current.into_kv()) + self.clone().prev() } } impl<'a, K, V, A> CursorMut<'a, K, V, A> { - /// Moves the cursor to the next element of the `BTreeMap`. + /// Advances the cursor to the next gap, returning the key and value of the + /// element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the end of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_next(&mut self) { - match self.current.take() { - None => { - // SAFETY: The previous borrow of root has ended. - self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| { - root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok() - }); - } - Some(current) => { - self.current = current.next_leaf_edge().next_kv().ok(); - } - } + pub fn next(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.next()?; + Some((&*k, v)) } - /// Moves the cursor to the previous element of the `BTreeMap`. + /// Advances the cursor to the previous gap, returning the key and value of + /// the element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the start of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_prev(&mut self) { - match self.current.take() { - None => { - // SAFETY: The previous borrow of root has ended. - self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| { - root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok() - }); - } - Some(current) => { - self.current = current.next_back_leaf_edge().next_back_kv().ok(); - } - } + pub fn prev(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.prev()?; + Some((&*k, v)) } - /// Returns a reference to the key of the element that the cursor is - /// currently pointing to. + /// Returns a reference to the the key and value of the next element without + /// moving the cursor. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// If the cursor is at the end of the map then `None` is returned #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key(&self) -> Option<&K> { - self.current.as_ref().map(|current| current.reborrow().into_kv().0) + pub fn peek_next(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.peek_next()?; + Some((&*k, v)) } - /// Returns a reference to the value of the element that the cursor is - /// currently pointing to. + /// Returns a reference to the the key and value of the previous element + /// without moving the cursor. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// If the cursor is at the start of the map then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn value(&self) -> Option<&V> { - self.current.as_ref().map(|current| current.reborrow().into_kv().1) + pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.peek_prev()?; + Some((&*k, v)) } - /// Returns a reference to the key and value of the element that the cursor - /// is currently pointing to. + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMut`. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key_value(&self) -> Option<(&K, &V)> { - self.current.as_ref().map(|current| current.reborrow().into_kv()) + pub fn as_cursor(&self) -> Cursor<'_, K, V> { + self.inner.as_cursor() } - /// Returns a mutable reference to the value of the element that the cursor - /// is currently pointing to. + /// Converts the cursor into a [`CursorMutKey`], which allows mutating + /// the key of elements in the tree. + /// + /// # Safety + /// + /// Since this cursor allows mutating keys, you must ensure that the `BTreeMap` + /// invariants are maintained. Specifically: /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn value_mut(&mut self) -> Option<&mut V> { - self.current.as_mut().map(|current| current.kv_mut().1) + pub unsafe fn with_mutable_key(self) -> CursorMutKey<'a, K, V, A> { + self.inner } +} - /// Returns a reference to the key and mutable reference to the value of the - /// element that the cursor is currently pointing to. +impl<'a, K, V, A> CursorMutKey<'a, K, V, A> { + /// Advances the cursor to the next gap, returning the key and value of the + /// element that it moved over. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// If the cursor is already at the end of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> { - self.current.as_mut().map(|current| { - let (k, v) = current.kv_mut(); - (&*k, v) - }) + pub fn next(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.take()?; + match current.next_kv() { + Ok(mut kv) => { + // SAFETY: The key/value pointers remain valid even after the + // cursor is moved forward. The lifetimes then prevent any + // further access to the cursor. + let (k, v) = unsafe { kv.reborrow_mut().into_kv_mut() }; + let (k, v) = (k as *mut _, v as *mut _); + self.current = Some(kv.next_leaf_edge()); + Some(unsafe { (&mut *k, &mut *v) }) + } + Err(root) => { + self.current = Some(root.last_leaf_edge()); + None + } + } } - /// Returns a mutable reference to the key of the element that the cursor is - /// currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// Advances the cursor to the previous gap, returning the key and value of + /// the element that it moved over. /// - /// # Safety - /// - /// This can be used to modify the key, but you must ensure that the - /// `BTreeMap` invariants are maintained. Specifically: - /// - /// * The key must remain unique within the tree. - /// * The key must remain in sorted order with regards to other elements in - /// the tree. + /// If the cursor is already at the start of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> { - self.current.as_mut().map(|current| current.kv_mut().0) + pub fn prev(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.take()?; + match current.next_back_kv() { + Ok(mut kv) => { + // SAFETY: The key/value pointers remain valid even after the + // cursor is moved forward. The lifetimes then prevent any + // further access to the cursor. + let (k, v) = unsafe { kv.reborrow_mut().into_kv_mut() }; + let (k, v) = (k as *mut _, v as *mut _); + self.current = Some(kv.next_back_leaf_edge()); + Some(unsafe { (&mut *k, &mut *v) }) + } + Err(root) => { + self.current = Some(root.first_leaf_edge()); + None + } + } } - /// Returns a reference to the key and value of the next element. + /// Returns a reference to the the key and value of the next element without + /// moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the end of the map then `None` is returned #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_next(&mut self) -> Option<(&K, &mut V)> { - let (k, v) = match self.current { - None => { - // SAFETY: The previous borrow of root has ended. - unsafe { self.root.reborrow() } - .as_mut()? - .borrow_mut() - .first_leaf_edge() - .next_kv() - .ok()? - .into_kv_valmut() - } - // SAFETY: We're not using this to mutate the tree. - Some(ref mut current) => { - unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut() - } - }; - Some((k, v)) + pub fn peek_next(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.as_mut()?; + // SAFETY: We're not using this to mutate the tree. + let kv = unsafe { current.reborrow_mut() }.next_kv().ok()?.into_kv_mut(); + Some(kv) } - /// Returns a reference to the key and value of the previous element. + /// Returns a reference to the the key and value of the previous element + /// without moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the start of the map then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> { - let (k, v) = match self.current.as_mut() { - None => { - // SAFETY: The previous borrow of root has ended. - unsafe { self.root.reborrow() } - .as_mut()? - .borrow_mut() - .last_leaf_edge() - .next_back_kv() - .ok()? - .into_kv_valmut() - } - Some(current) => { - // SAFETY: We're not using this to mutate the tree. - unsafe { current.reborrow_mut() } - .next_back_leaf_edge() - .next_back_kv() - .ok()? - .into_kv_valmut() - } - }; - Some((k, v)) + pub fn peek_prev(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.as_mut()?; + // SAFETY: We're not using this to mutate the tree. + let kv = unsafe { current.reborrow_mut() }.next_back_kv().ok()?.into_kv_mut(); + Some(kv) } - /// Returns a read-only cursor pointing to the current element. + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMutKey`. /// /// The lifetime of the returned `Cursor` is bound to that of the - /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the - /// `CursorMut` is frozen for the lifetime of the `Cursor`. + /// `CursorMutKey`, which means it cannot outlive the `CursorMutKey` and that the + /// `CursorMutKey` is frozen for the lifetime of the `Cursor`. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn as_cursor(&self) -> Cursor<'_, K, V> { Cursor { @@ -3054,11 +3039,12 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> { } // Now the tree editing operations -impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { - /// Inserts a new element into the `BTreeMap` after the current one. +impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the front of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. /// /// # Safety /// @@ -3071,20 +3057,19 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) { let edge = match self.current.take() { None => { + // Tree is empty, allocate a new root. // SAFETY: We have no other reference to the tree. - match unsafe { self.root.reborrow() } { - root @ None => { - // Tree is empty, allocate a new root. - let mut node = NodeRef::new_leaf(self.alloc.clone()); - node.borrow_mut().push(key, value); - *root = Some(node.forget_type()); - *self.length += 1; - return; - } - Some(root) => root.borrow_mut().first_leaf_edge(), - } + let root = unsafe { self.root.reborrow() }; + debug_assert!(root.is_none()); + let mut node = NodeRef::new_leaf(self.alloc.clone()); + // SAFETY: We don't touch the root while the handle is alive. + let handle = unsafe { node.borrow_mut().push_with_handle(key, value) }; + *root = Some(node.forget_type()); + *self.length += 1; + self.current = Some(handle.left_edge()); + return; } - Some(current) => current.next_leaf_edge(), + Some(current) => current, }; let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| { @@ -3094,14 +3079,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { let root = unsafe { self.root.reborrow().as_mut().unwrap() }; root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) }); - self.current = handle.left_edge().next_back_kv().ok(); + self.current = Some(handle.left_edge()); *self.length += 1; } - /// Inserts a new element into the `BTreeMap` before the current one. + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the end of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. /// /// # Safety /// @@ -3119,15 +3105,17 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { root @ None => { // Tree is empty, allocate a new root. let mut node = NodeRef::new_leaf(self.alloc.clone()); - node.borrow_mut().push(key, value); + // SAFETY: We don't touch the root while the handle is alive. + let handle = unsafe { node.borrow_mut().push_with_handle(key, value) }; *root = Some(node.forget_type()); *self.length += 1; + self.current = Some(handle.right_edge()); return; } Some(root) => root.borrow_mut().last_leaf_edge(), } } - Some(current) => current.next_back_leaf_edge(), + Some(current) => current, }; let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| { @@ -3137,14 +3125,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { let root = unsafe { self.root.reborrow().as_mut().unwrap() }; root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) }); - self.current = handle.right_edge().next_kv().ok(); + self.current = Some(handle.right_edge()); *self.length += 1; } - /// Inserts a new element into the `BTreeMap` after the current one. + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the front of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. /// /// # Panics /// @@ -3154,26 +3143,28 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { /// - the given key compares greater than or equal to the next element (if /// any). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_after(&mut self, key: K, value: V) { - if let Some(current) = self.key() { - if &key <= current { - panic!("key must be ordered above the current element"); + pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { + if let Some((prev, _)) = self.peek_prev() { + if &key <= prev { + return Err(UnorderedKeyError {}); } } if let Some((next, _)) = self.peek_next() { if &key >= next { - panic!("key must be ordered below the next element"); + return Err(UnorderedKeyError {}); } } unsafe { self.insert_after_unchecked(key, value); } + Ok(()) } - /// Inserts a new element into the `BTreeMap` before the current one. + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the end of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. /// /// # Panics /// @@ -3183,36 +3174,36 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { /// - the given key compares less than or equal to the previous element (if /// any). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_before(&mut self, key: K, value: V) { - if let Some(current) = self.key() { - if &key >= current { - panic!("key must be ordered below the current element"); - } - } + pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { if let Some((prev, _)) = self.peek_prev() { if &key <= prev { - panic!("key must be ordered above the previous element"); + return Err(UnorderedKeyError {}); + } + } + if let Some((next, _)) = self.peek_next() { + if &key >= next { + return Err(UnorderedKeyError {}); } } unsafe { self.insert_before_unchecked(key, value); } + Ok(()) } - /// Removes the current element from the `BTreeMap`. - /// - /// The element that was removed is returned, and the cursor is - /// moved to point to the next element in the `BTreeMap`. + /// Removes the next element from the `BTreeMap`. /// - /// If the cursor is currently pointing to the "ghost" non-element then no element - /// is removed and `None` is returned. The cursor is not moved in this case. + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn remove_current(&mut self) -> Option<(K, V)> { + pub fn remove_next(&mut self) -> Option<(K, V)> { let current = self.current.take()?; let mut emptied_internal_root = false; - let (kv, pos) = - current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); - self.current = pos.next_kv().ok(); + let (kv, pos) = current + .next_kv() + .ok()? + .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); + self.current = Some(pos); *self.length -= 1; if emptied_internal_root { // SAFETY: This is safe since current does not point within the now @@ -3223,20 +3214,19 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { Some(kv) } - /// Removes the current element from the `BTreeMap`. + /// Removes the precending element from the `BTreeMap`. /// - /// The element that was removed is returned, and the cursor is - /// moved to point to the previous element in the `BTreeMap`. - /// - /// If the cursor is currently pointing to the "ghost" non-element then no element - /// is removed and `None` is returned. The cursor is not moved in this case. + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> { + pub fn remove_prev(&mut self) -> Option<(K, V)> { let current = self.current.take()?; let mut emptied_internal_root = false; - let (kv, pos) = - current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); - self.current = pos.next_back_kv().ok(); + let (kv, pos) = current + .next_back_kv() + .ok()? + .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); + self.current = Some(pos); *self.length -= 1; if emptied_internal_root { // SAFETY: This is safe since current does not point within the now @@ -3248,5 +3238,114 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { } } +impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) { + unsafe { self.inner.insert_after_unchecked(key, value) } + } + + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) { + unsafe { self.inner.insert_before_unchecked(key, value) } + } + + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Panics + /// + /// This function panics if: + /// - the given key compares less than or equal to the current element (if + /// any). + /// - the given key compares greater than or equal to the next element (if + /// any). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { + self.inner.insert_after(key, value) + } + + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Panics + /// + /// This function panics if: + /// - the given key compares greater than or equal to the current element + /// (if any). + /// - the given key compares less than or equal to the previous element (if + /// any). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { + self.inner.insert_before(key, value) + } + + /// Removes the next element from the `BTreeMap`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_next(&mut self) -> Option<(K, V)> { + self.inner.remove_next() + } + + /// Removes the precending element from the `BTreeMap`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_prev(&mut self) -> Option<(K, V)> { + self.inner.remove_prev() + } +} + +/// Error type returned by [`CursorMut::insert_before`] and +/// [`CursorMut::insert_after`] if the key being inserted is not properly +/// ordered with regards to adjacent keys. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct UnorderedKeyError {} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl fmt::Display for UnorderedKeyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "key is not properly ordered relative to neighbors") + } +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Error for UnorderedKeyError {} + #[cfg(test)] mod tests; diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index a1b7cfe6b17c8..56620cf890db7 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2349,112 +2349,151 @@ fn test_cursor() { let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.lower_bound(Bound::Unbounded); - assert_eq!(cur.key(), Some(&1)); - cur.move_next(); - assert_eq!(cur.key(), Some(&2)); - assert_eq!(cur.peek_next(), Some((&3, &'c'))); - cur.move_prev(); - assert_eq!(cur.key(), Some(&1)); + assert_eq!(cur.peek_next(), Some((&1, &'a'))); assert_eq!(cur.peek_prev(), None); + assert_eq!(cur.prev(), None); + assert_eq!(cur.next(), Some((&1, &'a'))); + + assert_eq!(cur.next(), Some((&2, &'b'))); + + assert_eq!(cur.peek_next(), Some((&3, &'c'))); + assert_eq!(cur.prev(), Some((&2, &'b'))); + assert_eq!(cur.peek_prev(), Some((&1, &'a'))); let mut cur = map.upper_bound(Bound::Excluded(&1)); - assert_eq!(cur.key(), None); - cur.move_next(); - assert_eq!(cur.key(), Some(&1)); - cur.move_prev(); - assert_eq!(cur.key(), None); - assert_eq!(cur.peek_prev(), Some((&3, &'c'))); + assert_eq!(cur.peek_prev(), None); + assert_eq!(cur.next(), Some((&1, &'a'))); + assert_eq!(cur.prev(), Some((&1, &'a'))); } #[test] fn test_cursor_mut() { let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]); let mut cur = map.lower_bound_mut(Bound::Excluded(&3)); - assert_eq!(cur.key(), Some(&5)); - cur.insert_before(4, 'd'); - assert_eq!(cur.key(), Some(&5)); + assert_eq!(cur.peek_next(), Some((&5, &mut 'e'))); + assert_eq!(cur.peek_prev(), Some((&3, &mut 'c'))); + + cur.insert_before(4, 'd').unwrap(); + assert_eq!(cur.peek_next(), Some((&5, &mut 'e'))); assert_eq!(cur.peek_prev(), Some((&4, &mut 'd'))); - cur.move_next(); - assert_eq!(cur.key(), None); - cur.insert_before(6, 'f'); - assert_eq!(cur.key(), None); - assert_eq!(cur.remove_current(), None); - assert_eq!(cur.key(), None); - cur.insert_after(0, '?'); - assert_eq!(cur.key(), None); - assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')])); + + assert_eq!(cur.next(), Some((&5, &mut 'e'))); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&5, &mut 'e'))); + cur.insert_before(6, 'f').unwrap(); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&6, &mut 'f'))); + assert_eq!(cur.remove_prev(), Some((6, 'f'))); + assert_eq!(cur.remove_prev(), Some((5, 'e'))); + assert_eq!(cur.remove_next(), None); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')])); let mut cur = map.upper_bound_mut(Bound::Included(&5)); - assert_eq!(cur.key(), Some(&5)); - assert_eq!(cur.remove_current(), Some((5, 'e'))); - assert_eq!(cur.key(), Some(&6)); - assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f'))); - assert_eq!(cur.key(), Some(&4)); - assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')])); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.prev(), Some((&4, &mut 'd'))); + assert_eq!(cur.peek_next(), Some((&4, &mut 'd'))); + assert_eq!(cur.peek_prev(), Some((&3, &mut 'c'))); + assert_eq!(cur.remove_next(), Some((4, 'd'))); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')])); +} + +#[test] +fn test_cursor_mut_key() { + let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]); + let mut cur = unsafe { map.lower_bound_mut(Bound::Excluded(&3)).with_mutable_key() }; + assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e'))); + assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c'))); + + cur.insert_before(4, 'd').unwrap(); + assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e'))); + assert_eq!(cur.peek_prev(), Some((&mut 4, &mut 'd'))); + + assert_eq!(cur.next(), Some((&mut 5, &mut 'e'))); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&mut 5, &mut 'e'))); + cur.insert_before(6, 'f').unwrap(); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&mut 6, &mut 'f'))); + assert_eq!(cur.remove_prev(), Some((6, 'f'))); + assert_eq!(cur.remove_prev(), Some((5, 'e'))); + assert_eq!(cur.remove_next(), None); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')])); + + let mut cur = unsafe { map.upper_bound_mut(Bound::Included(&5)).with_mutable_key() }; + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.prev(), Some((&mut 4, &mut 'd'))); + assert_eq!(cur.peek_next(), Some((&mut 4, &mut 'd'))); + assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c'))); + assert_eq!(cur.remove_next(), Some((4, 'd'))); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')])); +} + +#[test] +fn test_cursor_empty() { + let mut map = BTreeMap::new(); + let mut cur = map.lower_bound_mut(Bound::Excluded(&3)); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), None); + cur.insert_after(0, 0).unwrap(); + assert_eq!(cur.peek_next(), Some((&0, &mut 0))); + assert_eq!(cur.peek_prev(), None); + assert_eq!(map, BTreeMap::from([(0, 0)])); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_before_1() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(0, 'd'); + cur.insert_before(0, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_before_2() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(1, 'd'); + cur.insert_before(1, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the current element")] #[test] fn test_cursor_mut_insert_before_3() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(2, 'd'); + cur.insert_before(2, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the current element")] #[test] fn test_cursor_mut_insert_before_4() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(3, 'd'); + cur.insert_before(3, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the current element")] #[test] fn test_cursor_mut_insert_after_1() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(1, 'd'); + cur.insert_after(1, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the current element")] #[test] fn test_cursor_mut_insert_after_2() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(2, 'd'); + cur.insert_after(2, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the next element")] #[test] fn test_cursor_mut_insert_after_3() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(3, 'd'); + cur.insert_after(3, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the next element")] #[test] fn test_cursor_mut_insert_after_4() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(4, 'd'); + cur.insert_after(4, 'd').unwrap_err(); } #[test] @@ -2462,14 +2501,14 @@ fn cursor_peek_prev_agrees_with_cursor_mut() { let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]); let cursor = map.lower_bound(Bound::Excluded(&3)); - assert!(cursor.key().is_none()); + assert!(cursor.peek_next().is_none()); let prev = cursor.peek_prev(); assert_matches!(prev, Some((&3, _))); // Shadow names so the two parts of this test match. let mut cursor = map.lower_bound_mut(Bound::Excluded(&3)); - assert!(cursor.key().is_none()); + assert!(cursor.peek_next().is_none()); let prev = cursor.peek_prev(); assert_matches!(prev, Some((&3, _))); diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 3233a575ecf25..78ccb3af66dbb 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -648,17 +648,36 @@ impl NodeRef { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key-value pair to the end of the node, and returns - /// the mutable reference of the inserted value. - pub fn push(&mut self, key: K, val: V) -> &mut V { + /// a handle to the inserted value. + /// + /// # Safety + /// + /// The returned handle has an unbound lifetime. + pub unsafe fn push_with_handle<'b>( + &mut self, + key: K, + val: V, + ) -> Handle, K, V, marker::Leaf>, marker::KV> { let len = self.len_mut(); let idx = usize::from(*len); assert!(idx < CAPACITY); *len += 1; unsafe { self.key_area_mut(idx).write(key); - self.val_area_mut(idx).write(val) + self.val_area_mut(idx).write(val); + Handle::new_kv( + NodeRef { height: self.height, node: self.node, _marker: PhantomData }, + idx, + ) } } + + /// Adds a key-value pair to the end of the node, and returns + /// the mutable reference of the inserted value. + pub fn push(&mut self, key: K, val: V) -> *mut V { + // SAFETY: The unbound handle is no longer accessible. + unsafe { self.push_with_handle(key, val).into_val_mut() } + } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { @@ -1100,10 +1119,10 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } - pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); - let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() }; + let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }; (k, v) } diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 4a4a3abd47f39..9419b0cfb24fa 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1024,6 +1024,8 @@ impl ToOwned for CStr { #[stable(feature = "cstring_asref", since = "1.7.0")] impl From<&CStr> for CString { + /// Converts a &[CStr] into a [`CString`] + /// by copying the contents into a new allocation. fn from(s: &CStr) -> CString { s.to_owned() } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 78629b39d34b1..96d43e11dc6b1 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,7 +103,6 @@ #![feature(allocator_api)] #![feature(array_chunks)] #![feature(array_into_iter_constructors)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] @@ -129,12 +128,14 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(hasher_prefixfree_extras)] +#![feature(hint_assert_unchecked)] #![feature(inline_const)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(iter_repeat_n)] #![feature(layout_for_ptr)] +#![feature(local_waker)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] @@ -148,7 +149,6 @@ #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] -#![feature(slice_group_by)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] @@ -253,7 +253,7 @@ pub mod str; pub mod string; #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] pub mod sync; -#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))] pub mod task; #[cfg(test)] mod tests; diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 45e8224016466..94e6924f41a75 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -2,7 +2,7 @@ use core::alloc::LayoutError; use core::cmp; -use core::intrinsics; +use core::hint; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ptr::{self, NonNull, Unique}; use core::slice; @@ -325,7 +325,7 @@ impl RawVec { } unsafe { // Inform the optimizer that the reservation has succeeded or wasn't needed - core::intrinsics::assume(!self.needs_to_grow(len, additional)); + hint::assert_unchecked(!self.needs_to_grow(len, additional)); } Ok(()) } @@ -363,7 +363,7 @@ impl RawVec { } unsafe { // Inform the optimizer that the reservation has succeeded or wasn't needed - core::intrinsics::assume(!self.needs_to_grow(len, additional)); + hint::assert_unchecked(!self.needs_to_grow(len, additional)); } Ok(()) } @@ -514,7 +514,7 @@ where debug_assert_eq!(old_layout.align(), new_layout.align()); unsafe { // The allocator checks for alignment equality - intrinsics::assume(old_layout.align() == new_layout.align()); + hint::assert_unchecked(old_layout.align() == new_layout.align()); alloc.grow(ptr, old_layout, new_layout) } } else { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 263b1449de156..0338565980c9c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -252,6 +252,7 @@ use core::cell::Cell; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; +use core::hint; use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; @@ -938,8 +939,11 @@ impl Rc { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for - /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.) + /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. + /// And while they are meant for different use-cases, `Rc::into_inner(this)` + /// is in fact equivalent to [Rc::try_unwrap]\(this).[ok][Result::ok](). + /// (Note that the same kind of equivalence does **not** hold true for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) #[inline] #[stable(feature = "rc_into_inner", since = "1.70.0")] pub fn into_inner(this: Self) -> Option { @@ -1885,10 +1889,10 @@ impl Rc { // Initialize the RcBox let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); unsafe { - debug_assert_eq!(Layout::for_value(&*inner), layout); + debug_assert_eq!(Layout::for_value_raw(inner), layout); - ptr::write(&mut (*inner).strong, Cell::new(1)); - ptr::write(&mut (*inner).weak, Cell::new(1)); + ptr::addr_of_mut!((*inner).strong).write(Cell::new(1)); + ptr::addr_of_mut!((*inner).weak).write(Cell::new(1)); } Ok(inner) @@ -1902,7 +1906,7 @@ impl Rc { // Allocate for the `RcBox` using the given value. unsafe { Rc::::allocate_for_layout( - Layout::for_value(&*ptr), + Layout::for_value_raw(ptr), |layout| alloc.allocate(layout), |mem| mem.with_metadata_of(ptr as *const RcBox), ) @@ -1918,13 +1922,13 @@ impl Rc { // Copy value as bytes ptr::copy_nonoverlapping( &*src as *const T as *const u8, - &mut (*ptr).value as *mut _ as *mut u8, + ptr::addr_of_mut!((*ptr).value) as *mut u8, value_size, ); // Free the allocation without dropping its contents let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw(bptr as *mut mem::ManuallyDrop); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); drop(src); Self::from_ptr_in(ptr, alloc) @@ -1952,7 +1956,11 @@ impl Rc<[T]> { unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len()); + ptr::copy_nonoverlapping( + v.as_ptr(), + ptr::addr_of_mut!((*ptr).value) as *mut T, + v.len(), + ); Self::from_ptr(ptr) } } @@ -1987,10 +1995,10 @@ impl Rc<[T]> { let ptr = Self::allocate_for_slice(len); let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = &mut (*ptr).value as *mut [T] as *mut T; + let elems = ptr::addr_of_mut!((*ptr).value) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2096,7 +2104,8 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { self.inner().dec_weak(); if self.inner().weak() == 0 { - self.alloc.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + self.alloc + .deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } @@ -2524,7 +2533,7 @@ impl From> for Rc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, &mut (*rc_ptr).value as *mut [T] as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).value) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator @@ -3268,7 +3277,7 @@ trait RcInnerPtr { // SAFETY: The reference count will never be zero when this is // called. unsafe { - core::intrinsics::assume(strong != 0); + hint::assert_unchecked(strong != 0); } let strong = strong.wrapping_add(1); @@ -3301,7 +3310,7 @@ trait RcInnerPtr { // SAFETY: The reference count will never be zero when this is // called. unsafe { - core::intrinsics::assume(weak != 0); + hint::assert_unchecked(weak != 0); } let weak = weak.wrapping_add(1); @@ -3514,7 +3523,7 @@ unsafe impl<#[may_dangle] T> Drop for UniqueRc { self.ptr.as_ref().dec_weak(); if self.ptr.as_ref().weak() == 0 { - Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index aa3b7b7e1914b..4033f4eb068c6 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -51,14 +51,14 @@ pub use core::slice::{from_mut, from_ref}; pub use core::slice::{from_mut_ptr_range, from_ptr_range}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Chunks, Windows}; #[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{ChunksMut, Split, SplitMut}; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use core::slice::{GroupBy, GroupByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Iter, IterMut}; #[stable(feature = "rchunks", since = "1.31.0")] diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 38f9f39fbf89a..ade114678b7f9 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -30,6 +30,8 @@ pub use core::str::SplitAsciiWhitespace; pub use core::str::SplitInclusive; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::SplitWhitespace; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use core::str::{from_raw_parts, from_raw_parts_mut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8, from_utf8_mut, Bytes, CharIndices, Chars}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5273b3cb2dafa..e16574f3d8066 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -279,6 +279,12 @@ impl Arc { } impl Arc { + #[inline] + fn internal_into_inner_with_allocator(self) -> (NonNull>, A) { + let this = mem::ManuallyDrop::new(self); + (this.ptr, unsafe { ptr::read(&this.alloc) }) + } + #[inline] unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { Self { ptr, phantom: PhantomData, alloc } @@ -983,9 +989,13 @@ impl Arc { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// The similar expression `Arc::try_unwrap(this).ok()` does not - /// offer such a guarantee. See the last example below - /// and the documentation of [`Arc::try_unwrap`]. + /// [`Arc::try_unwrap`] is conceptually similar to `Arc::into_inner`, but it + /// is meant for different use-cases. If used as a direct replacement + /// for `Arc::into_inner` anyway, such as with the expression + /// [Arc::try_unwrap]\(this).[ok][Result::ok](), then it does + /// **not** give the same guarantee as described in the previous paragraph. + /// For more information, see the examples below and read the documentation + /// of [`Arc::try_unwrap`]. /// /// # Examples /// @@ -1271,12 +1281,9 @@ impl Arc, A> { #[unstable(feature = "new_uninit", issue = "63291")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] - pub unsafe fn assume_init(self) -> Arc - where - A: Clone, - { - let md_self = mem::ManuallyDrop::new(self); - unsafe { Arc::from_inner_in(md_self.ptr.cast(), md_self.alloc.clone()) } + pub unsafe fn assume_init(self) -> Arc { + let (ptr, alloc) = self.internal_into_inner_with_allocator(); + unsafe { Arc::from_inner_in(ptr.cast(), alloc) } } } @@ -1316,12 +1323,9 @@ impl Arc<[mem::MaybeUninit], A> { #[unstable(feature = "new_uninit", issue = "63291")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] - pub unsafe fn assume_init(self) -> Arc<[T], A> - where - A: Clone, - { - let md_self = mem::ManuallyDrop::new(self); - unsafe { Arc::from_ptr_in(md_self.ptr.as_ptr() as _, md_self.alloc.clone()) } + pub unsafe fn assume_init(self) -> Arc<[T], A> { + let (ptr, alloc) = self.internal_into_inner_with_allocator(); + unsafe { Arc::from_ptr_in(ptr.as_ptr() as _, alloc) } } } @@ -1828,11 +1832,11 @@ impl Arc { mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, ) -> *mut ArcInner { let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); - debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); + debug_assert_eq!(unsafe { Layout::for_value_raw(inner) }, layout); unsafe { - ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); - ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + ptr::addr_of_mut!((*inner).strong).write(atomic::AtomicUsize::new(1)); + ptr::addr_of_mut!((*inner).weak).write(atomic::AtomicUsize::new(1)); } inner @@ -1847,7 +1851,7 @@ impl Arc { // Allocate for the `ArcInner` using the given value. unsafe { Arc::allocate_for_layout( - Layout::for_value(&*ptr), + Layout::for_value_raw(ptr), |layout| alloc.allocate(layout), |mem| mem.with_metadata_of(ptr as *const ArcInner), ) @@ -1863,13 +1867,13 @@ impl Arc { // Copy value as bytes ptr::copy_nonoverlapping( &*src as *const T as *const u8, - &mut (*ptr).data as *mut _ as *mut u8, + ptr::addr_of_mut!((*ptr).data) as *mut u8, value_size, ); // Free the allocation without dropping its contents let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw(bptr as *mut mem::ManuallyDrop); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); drop(src); Self::from_ptr_in(ptr, alloc) @@ -1898,7 +1902,7 @@ impl Arc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), ptr::addr_of_mut!((*ptr).data) as *mut T, v.len()); Self::from_ptr(ptr) } @@ -1934,10 +1938,10 @@ impl Arc<[T]> { let ptr = Self::allocate_for_slice(len); let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = &mut (*ptr).data as *mut [T] as *mut T; + let elems = ptr::addr_of_mut!((*ptr).data) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2409,7 +2413,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Arc { } } -impl Arc { +impl Arc { /// Attempt to downcast the `Arc` to a concrete type. /// /// # Examples @@ -2436,10 +2440,8 @@ impl Arc { { if (*self).is::() { unsafe { - let ptr = self.ptr.cast::>(); - let alloc = self.alloc.clone(); - mem::forget(self); - Ok(Arc::from_inner_in(ptr, alloc)) + let (ptr, alloc) = self.internal_into_inner_with_allocator(); + Ok(Arc::from_inner_in(ptr.cast(), alloc)) } } else { Err(self) @@ -2479,10 +2481,8 @@ impl Arc { T: Any + Send + Sync, { unsafe { - let ptr = self.ptr.cast::>(); - let alloc = self.alloc.clone(); - mem::forget(self); - Arc::from_inner_in(ptr, alloc) + let (ptr, alloc) = self.internal_into_inner_with_allocator(); + Arc::from_inner_in(ptr.cast(), alloc) } } } @@ -3380,7 +3380,7 @@ impl From> for Arc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, &mut (*rc_ptr).data as *mut [T] as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).data) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator @@ -3438,13 +3438,13 @@ impl From> for Arc<[u8]> { } #[stable(feature = "boxed_slice_try_from", since = "1.43.0")] -impl TryFrom> for Arc<[T; N], A> { +impl TryFrom> for Arc<[T; N], A> { type Error = Arc<[T], A>; fn try_from(boxed_slice: Arc<[T], A>) -> Result { if boxed_slice.len() == N { - let alloc = boxed_slice.alloc.clone(); - Ok(unsafe { Arc::from_raw_in(Arc::into_raw(boxed_slice) as *mut [T; N], alloc) }) + let (ptr, alloc) = boxed_slice.internal_into_inner_with_allocator(); + Ok(unsafe { Arc::from_inner_in(ptr.cast(), alloc) }) } else { Err(boxed_slice) } diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index d37e45569cf0f..49eae718c1690 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -1,13 +1,15 @@ use super::*; use std::clone::Clone; +use std::mem::MaybeUninit; use std::option::Option::None; +use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::sync::mpsc::channel; use std::sync::Mutex; use std::thread; -struct Canary(*mut atomic::AtomicUsize); +struct Canary(*mut AtomicUsize); impl Drop for Canary { fn drop(&mut self) { @@ -21,6 +23,37 @@ impl Drop for Canary { } } +struct AllocCanary<'a>(&'a AtomicUsize); + +impl<'a> AllocCanary<'a> { + fn new(counter: &'a AtomicUsize) -> Self { + counter.fetch_add(1, SeqCst); + Self(counter) + } +} + +unsafe impl Allocator for AllocCanary<'_> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + std::alloc::Global.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { std::alloc::Global.deallocate(ptr, layout) } + } +} + +impl Clone for AllocCanary<'_> { + fn clone(&self) -> Self { + Self::new(self.0) + } +} + +impl Drop for AllocCanary<'_> { + fn drop(&mut self) { + self.0.fetch_sub(1, SeqCst); + } +} + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn manually_share_arc() { @@ -295,16 +328,16 @@ fn weak_self_cyclic() { #[test] fn drop_arc() { - let mut canary = atomic::AtomicUsize::new(0); - let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); + let mut canary = AtomicUsize::new(0); + let x = Arc::new(Canary(&mut canary as *mut AtomicUsize)); drop(x); assert!(canary.load(Acquire) == 1); } #[test] fn drop_arc_weak() { - let mut canary = atomic::AtomicUsize::new(0); - let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); + let mut canary = AtomicUsize::new(0); + let arc = Arc::new(Canary(&mut canary as *mut AtomicUsize)); let arc_weak = Arc::downgrade(&arc); assert!(canary.load(Acquire) == 0); drop(arc); @@ -660,3 +693,25 @@ fn arc_drop_dereferenceable_race() { thread.join().unwrap(); } } + +#[test] +fn arc_doesnt_leak_allocator() { + let counter = AtomicUsize::new(0); + + { + let arc: Arc = Arc::new_in(5usize, AllocCanary::new(&counter)); + drop(arc.downcast::().unwrap()); + + let arc: Arc = Arc::new_in(5usize, AllocCanary::new(&counter)); + drop(unsafe { arc.downcast_unchecked::() }); + + let arc = Arc::new_in(MaybeUninit::::new(5usize), AllocCanary::new(&counter)); + drop(unsafe { arc.assume_init() }); + + let arc: Arc<[MaybeUninit], _> = + Arc::new_zeroed_slice_in(5, AllocCanary::new(&counter)); + drop(unsafe { arc.assume_init() }); + } + + assert_eq!(counter.load(SeqCst), 0); +} diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 5d9772b878b03..87db8629ad09a 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -2,14 +2,19 @@ //! Types and Traits for working with asynchronous tasks. //! -//! **Note**: This module is only available on platforms that support atomic -//! loads and stores of pointers. This may be detected at compile time using +//! **Note**: Some of the types in this module are only available +//! on platforms that support atomic loads and stores of pointers. +//! This may be detected at compile time using //! `#[cfg(target_has_atomic = "ptr")]`. +use crate::rc::Rc; use core::mem::ManuallyDrop; -use core::task::{RawWaker, RawWakerVTable, Waker}; +use core::task::{LocalWaker, RawWaker, RawWakerVTable}; +#[cfg(target_has_atomic = "ptr")] use crate::sync::Arc; +#[cfg(target_has_atomic = "ptr")] +use core::task::Waker; /// The implementation of waking a task on an executor. /// @@ -73,6 +78,7 @@ use crate::sync::Arc; /// println!("Hi from inside a future!"); /// }); /// ``` +#[cfg(target_has_atomic = "ptr")] #[stable(feature = "wake_trait", since = "1.51.0")] pub trait Wake { /// Wake this task. @@ -91,7 +97,7 @@ pub trait Wake { self.clone().wake(); } } - +#[cfg(target_has_atomic = "ptr")] #[stable(feature = "wake_trait", since = "1.51.0")] impl From> for Waker { /// Use a `Wake`-able type as a `Waker`. @@ -103,7 +109,7 @@ impl From> for Waker { unsafe { Waker::from_raw(raw_waker(waker)) } } } - +#[cfg(target_has_atomic = "ptr")] #[stable(feature = "wake_trait", since = "1.51.0")] impl From> for RawWaker { /// Use a `Wake`-able type as a `RawWaker`. @@ -119,6 +125,7 @@ impl From> for RawWaker { // the safety of `From> for Waker` does not depend on the correct // trait dispatch - instead both impls call this function directly and // explicitly. +#[cfg(target_has_atomic = "ptr")] #[inline(always)] fn raw_waker(waker: Arc) -> RawWaker { // Increment the reference count of the arc to clone it. @@ -152,3 +159,171 @@ fn raw_waker(waker: Arc) -> RawWaker { &RawWakerVTable::new(clone_waker::, wake::, wake_by_ref::, drop_waker::), ) } + +/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API +/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead +/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`. +/// +/// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker +/// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls +/// to `Arc::clone`, which requires atomic synchronization. +/// +/// +/// # Examples +/// +/// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function +/// is used to push new tasks onto the run queue, while the block on function will remove them +/// and poll them. When a task is woken, it will put itself back on the run queue to be polled +/// by the executor. +/// +/// **Note:** This example trades correctness for simplicity. A real world example would interleave +/// poll calls with calls to an io reactor to wait for events instead of spinning on a loop. +/// +/// ```rust +/// #![feature(local_waker)] +/// #![feature(noop_waker)] +/// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker}; +/// use std::future::Future; +/// use std::pin::Pin; +/// use std::rc::Rc; +/// use std::cell::RefCell; +/// use std::collections::VecDeque; +/// +/// +/// thread_local! { +/// // A queue containing all tasks ready to do progress +/// static RUN_QUEUE: RefCell>> = RefCell::default(); +/// } +/// +/// type BoxedFuture = Pin>>; +/// +/// struct Task(RefCell); +/// +/// impl LocalWake for Task { +/// fn wake(self: Rc) { +/// RUN_QUEUE.with_borrow_mut(|queue| { +/// queue.push_back(self) +/// }) +/// } +/// } +/// +/// fn spawn(future: F) +/// where +/// F: Future + 'static + Send + Sync +/// { +/// let task = RefCell::new(Box::pin(future)); +/// RUN_QUEUE.with_borrow_mut(|queue| { +/// queue.push_back(Rc::new(Task(task))); +/// }); +/// } +/// +/// fn block_on(future: F) +/// where +/// F: Future + 'static + Sync + Send +/// { +/// spawn(future); +/// loop { +/// let Some(task) = RUN_QUEUE.with_borrow_mut(|queue| queue.pop_front()) else { +/// // we exit, since there are no more tasks remaining on the queue +/// return; +/// }; +/// +/// // cast the Rc into a `LocalWaker` +/// let local_waker: LocalWaker = task.clone().into(); +/// // Build the context using `ContextBuilder` +/// let mut cx = ContextBuilder::from_waker(Waker::noop()) +/// .local_waker(&local_waker) +/// .build(); +/// +/// // Poll the task +/// let _ = task.0 +/// .borrow_mut() +/// .as_mut() +/// .poll(&mut cx); +/// } +/// } +/// +/// block_on(async { +/// println!("hello world"); +/// }); +/// ``` +/// +#[unstable(feature = "local_waker", issue = "118959")] +pub trait LocalWake { + /// Wake this task. + #[unstable(feature = "local_waker", issue = "118959")] + fn wake(self: Rc); + + /// Wake this task without consuming the local waker. + /// + /// If an executor supports a cheaper way to wake without consuming the + /// waker, it should override this method. By default, it clones the + /// [`Rc`] and calls [`wake`] on the clone. + /// + /// [`wake`]: LocalWaker::wake + #[unstable(feature = "local_waker", issue = "118959")] + fn wake_by_ref(self: &Rc) { + self.clone().wake(); + } +} + +#[unstable(feature = "local_waker", issue = "118959")] +impl From> for LocalWaker { + /// Use a `Wake`-able type as a `LocalWaker`. + /// + /// No heap allocations or atomic operations are used for this conversion. + fn from(waker: Rc) -> LocalWaker { + // SAFETY: This is safe because raw_waker safely constructs + // a RawWaker from Rc. + unsafe { LocalWaker::from_raw(local_raw_waker(waker)) } + } +} +#[allow(ineffective_unstable_trait_impl)] +#[unstable(feature = "local_waker", issue = "118959")] +impl From> for RawWaker { + /// Use a `Wake`-able type as a `RawWaker`. + /// + /// No heap allocations or atomic operations are used for this conversion. + fn from(waker: Rc) -> RawWaker { + local_raw_waker(waker) + } +} + +// NB: This private function for constructing a RawWaker is used, rather than +// inlining this into the `From> for RawWaker` impl, to ensure that +// the safety of `From> for Waker` does not depend on the correct +// trait dispatch - instead both impls call this function directly and +// explicitly. +#[inline(always)] +fn local_raw_waker(waker: Rc) -> RawWaker { + // Increment the reference count of the Rc to clone it. + unsafe fn clone_waker(waker: *const ()) -> RawWaker { + unsafe { Rc::increment_strong_count(waker as *const W) }; + RawWaker::new( + waker as *const (), + &RawWakerVTable::new(clone_waker::, wake::, wake_by_ref::, drop_waker::), + ) + } + + // Wake by value, moving the Rc into the LocalWake::wake function + unsafe fn wake(waker: *const ()) { + let waker = unsafe { Rc::from_raw(waker as *const W) }; + ::wake(waker); + } + + // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it + unsafe fn wake_by_ref(waker: *const ()) { + let waker = unsafe { ManuallyDrop::new(Rc::from_raw(waker as *const W)) }; + ::wake_by_ref(&waker); + } + + // Decrement the reference count of the Rc on drop + unsafe fn drop_waker(waker: *const ()) { + unsafe { Rc::decrement_strong_count(waker as *const W) }; + } + + RawWaker::new( + Rc::into_raw(waker) as *const (), + &RawWakerVTable::new(clone_waker::, wake::, wake_by_ref::, drop_waker::), + ) +} diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 2c799605b7b67..b12910f3690b5 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -15,6 +15,19 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { } } +#[stable(feature = "cow_from_array_ref", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: Clone, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> { + /// Creates a [`Borrowed`] variant of [`Cow`] + /// from a reference to an array. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed + fn from(s: &'a [T; N]) -> Cow<'a, [T]> { + Cow::Borrowed(s as &[_]) + } +} + #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From> for Cow<'a, [T]> { /// Creates an [`Owned`] variant of [`Cow`] diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index ec5f32539f2c2..5dc3c69e49320 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -72,7 +72,7 @@ //! This is handled by the [`InPlaceDrop`] guard for sink items (`U`) and by //! [`vec::IntoIter::forget_allocation_drop_remaining()`] for remaining source items (`T`). //! -//! If dropping any remaining source item (`T`) panics then [`InPlaceDstBufDrop`] will handle dropping +//! If dropping any remaining source item (`T`) panics then [`InPlaceDstDataSrcBufDrop`] will handle dropping //! the already collected sink items (`U`) and freeing the allocation. //! //! [`vec::IntoIter::forget_allocation_drop_remaining()`]: super::IntoIter::forget_allocation_drop_remaining() @@ -158,17 +158,20 @@ use crate::alloc::{handle_alloc_error, Global}; use core::alloc::Allocator; use core::alloc::Layout; use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; +use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, SizedTypeProperties}; use core::num::NonZeroUsize; use core::ptr::{self, NonNull}; -use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec}; +use super::{InPlaceDrop, InPlaceDstDataSrcBufDrop, SpecFromIter, SpecFromIterNested, Vec}; const fn in_place_collectible( step_merge: Option, step_expand: Option, ) -> bool { - if const { SRC::IS_ZST || DEST::IS_ZST || mem::align_of::() < mem::align_of::() } { + // 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::() } { return false; } @@ -188,7 +191,8 @@ const fn in_place_collectible( const fn needs_realloc(src_cap: usize, dst_cap: usize) -> bool { if const { mem::align_of::() != mem::align_of::() } { - return src_cap > 0; + // FIXME: use unreachable! once that works in const + panic!("in_place_collectible() prevents this"); } // If src type size is an integer multiple of the destination type size then @@ -262,7 +266,7 @@ where ); } - // The ownership of the allocation and the new `T` values is temporarily moved into `dst_guard`. + // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`. // This is safe because // * `forget_allocation_drop_remaining` immediately forgets the allocation // before any panic can occur in order to avoid any double free, and then proceeds to drop @@ -273,11 +277,12 @@ where // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the // module documentation why this is ok anyway. - let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap: dst_cap }; + let dst_guard = + InPlaceDstDataSrcBufDrop { ptr: dst_buf, len, src_cap, src: PhantomData:: }; src.forget_allocation_drop_remaining(); - // Adjust the allocation if the alignment didn't match or the source had a capacity in bytes - // that wasn't a multiple of the destination type size. + // Adjust the allocation if the source had a capacity in bytes that wasn't a multiple + // of the destination type size. // Since the discrepancy should generally be small this should only result in some // bookkeeping updates and no memmove. if needs_realloc::(src_cap, dst_cap) { @@ -290,7 +295,7 @@ where let src_size = mem::size_of::().unchecked_mul(src_cap); let old_layout = Layout::from_size_align_unchecked(src_size, src_align); - // The must be equal or smaller for in-place iteration to be possible + // 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); diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 25ca33c6a7bf0..40a540b57fc22 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -1,6 +1,10 @@ -use core::ptr::{self}; +use core::marker::PhantomData; +use core::ptr::{self, drop_in_place}; use core::slice::{self}; +use crate::alloc::Global; +use crate::raw_vec::RawVec; + // A helper struct for in-place iteration that drops the destination slice of iteration, // i.e. the head. The source slice (the tail) is dropped by IntoIter. pub(super) struct InPlaceDrop { @@ -23,17 +27,23 @@ impl Drop for InPlaceDrop { } } -// A helper struct for in-place collection that drops the destination allocation and elements, -// to avoid leaking them if some other destructor panics. -pub(super) struct InPlaceDstBufDrop { - pub(super) ptr: *mut T, +// A helper struct for in-place collection that drops the destination items together with +// the source allocation - i.e. before the reallocation happened - to avoid leaking them +// if some other destructor panics. +pub(super) struct InPlaceDstDataSrcBufDrop { + pub(super) ptr: *mut Dest, pub(super) len: usize, - pub(super) cap: usize, + pub(super) src_cap: usize, + pub(super) src: PhantomData, } -impl Drop for InPlaceDstBufDrop { +impl Drop for InPlaceDstDataSrcBufDrop { #[inline] fn drop(&mut self) { - unsafe { super::Vec::from_raw_parts(self.ptr, self.len, self.cap) }; + unsafe { + let _drop_allocation = + RawVec::::from_raw_parts_in(self.ptr.cast::(), self.src_cap, Global); + drop_in_place(core::ptr::slice_from_raw_parts_mut::(self.ptr, self.len)); + }; } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 35ea97bfe609c..b3e5ecc924071 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -123,7 +123,7 @@ use self::set_len_on_drop::SetLenOnDrop; mod set_len_on_drop; #[cfg(not(no_global_oom_handling))] -use self::in_place_drop::{InPlaceDrop, InPlaceDstBufDrop}; +use self::in_place_drop::{InPlaceDrop, InPlaceDstDataSrcBufDrop}; #[cfg(not(no_global_oom_handling))] mod in_place_drop; @@ -1996,7 +1996,7 @@ impl Vec { } else { unsafe { self.len -= 1; - core::intrinsics::assume(self.len < self.capacity()); + core::hint::assert_unchecked(self.len < self.capacity()); Some(ptr::read(self.as_ptr().add(self.len()))) } } @@ -2167,6 +2167,12 @@ impl Vec { /// `[at, len)`. After the call, the original vector will be left containing /// the elements `[0, at)` with its previous capacity unchanged. /// + /// - If you want to take ownership of the entire contents and capacity of + /// the vector, see [`mem::take`] or [`mem::replace`]. + /// - If you don't need the returned vector at all, see [`Vec::truncate`]. + /// - If you want to take ownership of an arbitrary subslice, or you don't + /// necessarily want to store the removed items in a vector, see [`Vec::drain`]. + /// /// # Panics /// /// Panics if `at > len`. @@ -2198,14 +2204,6 @@ impl Vec { assert_failed(at, self.len()); } - if at == 0 { - // the new vector can take over the original buffer and avoid the copy - return mem::replace( - self, - Vec::with_capacity_in(self.capacity(), self.allocator().clone()), - ); - } - let other_len = self.len - at; let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); @@ -2786,6 +2784,50 @@ impl, A: Allocator> IndexMut for Vec { } } +/// Collects an iterator into a Vec, commonly called via [`Iterator::collect()`] +/// +/// # Allocation behavior +/// +/// In general `Vec` does not guarantee any particular growth or allocation strategy. +/// That also applies to this trait impl. +/// +/// **Note:** This section covers implementation details and is therefore exempt from +/// stability guarantees. +/// +/// Vec may use any or none of the following strategies, +/// depending on the supplied iterator: +/// +/// * preallocate based on [`Iterator::size_hint()`] +/// * and panic if the number of items is outside the provided lower/upper bounds +/// * use an amortized growth strategy similar to `pushing` one item at a time +/// * perform the iteration in-place on the original allocation backing the iterator +/// +/// The last case warrants some attention. It is an optimization that in many cases reduces peak memory +/// consumption and improves cache locality. But when big, short-lived allocations are created, +/// only a small fraction of their items get collected, no further use is made of the spare capacity +/// and the resulting `Vec` is moved into a longer-lived structure, then this can lead to the large +/// allocations having their lifetimes unnecessarily extended which can result in increased memory +/// footprint. +/// +/// In cases where this is an issue, the excess capacity can be discarded with [`Vec::shrink_to()`], +/// [`Vec::shrink_to_fit()`] or by collecting into [`Box<[T]>`][owned slice] instead, which additionally reduces +/// the size of the long-lived struct. +/// +/// [owned slice]: Box +/// +/// ```rust +/// # use std::sync::Mutex; +/// static LONG_LIVED: Mutex>> = Mutex::new(Vec::new()); +/// +/// for i in 0..10 { +/// let big_temporary: Vec = (0..1024).collect(); +/// // discard most items +/// let mut result: Vec<_> = big_temporary.into_iter().filter(|i| i % 100 == 0).collect(); +/// // without this a lot of unused capacity might be moved into the global +/// result.shrink_to_fit(); +/// LONG_LIVED.lock().unwrap().push(result); +/// } +/// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for Vec { diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index e976552cf2b92..33dd4139bc08b 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -13,13 +13,13 @@ use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; /// +-+-----------+ /// | /// v -/// +-+-------------------------------+ +---------------------+ -/// |SpecFromIter +---->+SpecFromIterNested | -/// |where I: | | |where I: | -/// | Iterator (default)----------+ | | Iterator (default) | -/// | vec::IntoIter | | | TrustedLen | -/// | SourceIterMarker---fallback-+ | +---------------------+ -/// +---------------------------------+ +/// +-+---------------------------------+ +---------------------+ +/// |SpecFromIter +---->+SpecFromIterNested | +/// |where I: | | |where I: | +/// | Iterator (default)------------+ | | Iterator (default) | +/// | vec::IntoIter | | | TrustedLen | +/// | InPlaceCollect--(fallback to)-+ | +---------------------+ +/// +-----------------------------------+ /// ``` pub(super) trait SpecFromIter { fn from_iter(iter: I) -> Self; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 2dcfc6b4abfe9..ca17dab55b027 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -29,7 +29,6 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(round_char_boundary)] -#![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(string_remove_matches)] #![feature(const_btree_len)] diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 784839a3ffa42..c0f7a11a93e12 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1614,10 +1614,10 @@ fn subslice_patterns() { } #[test] -fn test_group_by() { +fn test_chunk_by() { let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); @@ -1625,7 +1625,7 @@ fn test_group_by() { assert_eq!(iter.next(), Some(&[0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); @@ -1633,7 +1633,7 @@ fn test_group_by() { assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1643,10 +1643,10 @@ fn test_group_by() { } #[test] -fn test_group_by_mut() { +fn test_chunk_by_mut() { let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); @@ -1654,7 +1654,7 @@ fn test_group_by_mut() { assert_eq!(iter.next(), Some(&mut [0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next_back(), Some(&mut [1][..])); assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); @@ -1662,7 +1662,7 @@ fn test_group_by_mut() { assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 0f5e0d99eca12..38a68df79cc73 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -958,23 +958,35 @@ fn test_append() { #[test] fn test_split_off() { let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); - let vec2 = vec.split_off(4); + + let split_off = vec.split_off(4); assert_eq!(vec, [1, 2, 3, 4]); - assert_eq!(vec2, [5, 6]); + assert_eq!(split_off, [5, 6]); assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec.as_ptr(), orig_ptr); } #[test] fn test_split_off_take_all() { - let mut vec = vec![1, 2, 3, 4, 5, 6]; + // Allocate enough capacity that we can tell whether the split-off vector's + // capacity is based on its size, or (incorrectly) on the original capacity. + let mut vec = Vec::with_capacity(1000); + vec.extend([1, 2, 3, 4, 5, 6]); let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); - let vec2 = vec.split_off(0); + + let split_off = vec.split_off(0); assert_eq!(vec, []); - assert_eq!(vec2, [1, 2, 3, 4, 5, 6]); + assert_eq!(split_off, [1, 2, 3, 4, 5, 6]); assert_eq!(vec.capacity(), orig_capacity); - assert_eq!(vec2.as_ptr(), orig_ptr); + assert_eq!(vec.as_ptr(), orig_ptr); + + // The split-off vector should be newly-allocated, and should not have + // stolen the original vector's allocation. + assert!(split_off.capacity() < orig_capacity); + assert_ne!(split_off.as_ptr(), orig_ptr); } #[test] @@ -1166,10 +1178,14 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { fn assert_in_place_trait(_: &T) {} - let src: Vec = vec![0usize; 256]; + let owned: Vec = vec![0usize; 256]; + let refd: Vec<&usize> = owned.iter().collect(); + let src: Vec<&&usize> = refd.iter().collect(); let srcptr = src.as_ptr(); let iter = src .into_iter() + .copied() + .cloned() .enumerate() .map(|i| i.0 + i.1) .zip(std::iter::repeat(1usize)) @@ -1180,7 +1196,7 @@ fn test_from_iter_specialization_with_iterator_adapters() { assert_in_place_trait(&iter); let sink = iter.collect::, _>>().unwrap(); let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr as *const usize); + assert_eq!(srcptr as *const usize, sinkptr as *const usize); } #[test] diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index 64938745a4a16..71ec9fed2fe75 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -63,6 +63,7 @@ macro_rules! benches { } } +use std::fmt::Write; use test::black_box; use test::Bencher; @@ -351,3 +352,30 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, ]; + +const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; + +#[bench] +fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = ASCII_PATH.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} + +#[bench] +fn bench_ascii_escape_display_mixed(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = RUST_INCANTATION.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 05fec0c4b9d26..c1cec5e6d3c8c 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -391,6 +391,19 @@ fn bench_skip_then_zip(b: &mut Bencher) { }); } +#[bench] +fn bench_skip_trusted_random_access(b: &mut Bencher) { + let v: Vec = black_box(vec![42; 10000]); + let mut sink = [0; 10000]; + + b.iter(|| { + for (val, idx) in v.iter().skip(8).zip(0..10000) { + sink[idx] += val; + } + sink + }); +} + #[bench] fn bench_filter_count(b: &mut Bencher) { b.iter(|| (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count()) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index c582111701a99..a1fff6707bd0f 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -110,7 +110,7 @@ use crate::ptr; /// ```rust,ignore (unsound and has placeholders) /// drop(Box::new(42)); /// let number_of_heap_allocs = /* call private allocator API */; -/// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } +/// unsafe { std::hint::assert_unchecked(number_of_heap_allocs > 0); } /// ``` /// /// Note that the optimizations mentioned above are not the only diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index d749865f76f51..bdb6599abf549 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -2,36 +2,36 @@ use crate::cmp::BytewiseEq; use crate::convert::TryInto; #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B; N]> for [A; N] +impl PartialEq<[U; N]> for [T; N] where - A: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &[B; N]) -> bool { + fn eq(&self, other: &[U; N]) -> bool { SpecArrayEq::spec_eq(self, other) } #[inline] - fn ne(&self, other: &[B; N]) -> bool { + fn ne(&self, other: &[U; N]) -> bool { SpecArrayEq::spec_ne(self, other) } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B]> for [A; N] +impl PartialEq<[U]> for [T; N] where - A: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &[B]) -> bool { - let b: Result<&[B; N], _> = other.try_into(); + fn eq(&self, other: &[U]) -> bool { + let b: Result<&[U; N], _> = other.try_into(); match b { Ok(b) => *self == *b, Err(_) => false, } } #[inline] - fn ne(&self, other: &[B]) -> bool { - let b: Result<&[B; N], _> = other.try_into(); + fn ne(&self, other: &[U]) -> bool { + let b: Result<&[U; N], _> = other.try_into(); match b { Ok(b) => *self != *b, Err(_) => true, @@ -40,21 +40,21 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[A; N]> for [B] +impl PartialEq<[U; N]> for [T] where - B: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &[A; N]) -> bool { - let b: Result<&[B; N], _> = self.try_into(); + fn eq(&self, other: &[U; N]) -> bool { + let b: Result<&[T; N], _> = self.try_into(); match b { Ok(b) => *b == *other, Err(_) => false, } } #[inline] - fn ne(&self, other: &[A; N]) -> bool { - let b: Result<&[B; N], _> = self.try_into(); + fn ne(&self, other: &[U; N]) -> bool { + let b: Result<&[T; N], _> = self.try_into(); match b { Ok(b) => *b != *other, Err(_) => true, @@ -63,61 +63,61 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<&[B]> for [A; N] +impl PartialEq<&[U]> for [T; N] where - A: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &&[B]) -> bool { + fn eq(&self, other: &&[U]) -> bool { *self == **other } #[inline] - fn ne(&self, other: &&[B]) -> bool { + fn ne(&self, other: &&[U]) -> bool { *self != **other } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[A; N]> for &[B] +impl PartialEq<[U; N]> for &[T] where - B: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &[A; N]) -> bool { + fn eq(&self, other: &[U; N]) -> bool { **self == *other } #[inline] - fn ne(&self, other: &[A; N]) -> bool { + fn ne(&self, other: &[U; N]) -> bool { **self != *other } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<&mut [B]> for [A; N] +impl PartialEq<&mut [U]> for [T; N] where - A: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &&mut [B]) -> bool { + fn eq(&self, other: &&mut [U]) -> bool { *self == **other } #[inline] - fn ne(&self, other: &&mut [B]) -> bool { + fn ne(&self, other: &&mut [U]) -> bool { *self != **other } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[A; N]> for &mut [B] +impl PartialEq<[U; N]> for &mut [T] where - B: PartialEq, + T: PartialEq, { #[inline] - fn eq(&self, other: &[A; N]) -> bool { + fn eq(&self, other: &[U; N]) -> bool { **self == *other } #[inline] - fn ne(&self, other: &[A; N]) -> bool { + fn ne(&self, other: &[U; N]) -> bool { **self != *other } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 34213637a32fc..85cce81f2c122 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -559,8 +559,6 @@ impl [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] - /// /// let floats = [3.1, 2.7, -1.0]; /// let float_refs: [&f64; 3] = floats.each_ref(); /// assert_eq!(float_refs, [&3.1, &2.7, &-1.0]); @@ -571,8 +569,6 @@ impl [T; N] { /// array if its elements are not [`Copy`]. /// /// ``` - /// #![feature(array_methods)] - /// /// let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()]; /// let is_ascii = strings.each_ref().map(|s| s.is_ascii()); /// assert_eq!(is_ascii, [true, false, true]); @@ -580,7 +576,7 @@ impl [T; N] { /// // We can still access the original array: it has not been moved. /// assert_eq!(strings.len(), 3); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_ref(&self) -> [&T; N] { from_trusted_iterator(self.iter()) } @@ -592,7 +588,6 @@ impl [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] /// /// let mut floats = [3.1, 2.7, -1.0]; /// let float_refs: [&mut f64; 3] = floats.each_mut(); @@ -600,7 +595,7 @@ impl [T; N] { /// assert_eq!(float_refs, [&mut 0.0, &mut 2.7, &mut -1.0]); /// assert_eq!(floats, [0.0, 2.7, -1.0]); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_mut(&mut self) -> [&mut T; N] { from_trusted_iterator(self.iter_mut()) } @@ -647,7 +642,7 @@ impl [T; N] { )] #[inline] pub fn split_array_ref(&self) -> (&[T; M], &[T]) { - (&self[..]).split_array_ref::() + (&self[..]).split_first_chunk::().unwrap() } /// Divides one mutable array reference into two at an index. @@ -680,7 +675,7 @@ impl [T; N] { )] #[inline] pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { - (&mut self[..]).split_array_mut::() + (&mut self[..]).split_first_chunk_mut::().unwrap() } /// Divides one array reference into two at an index from the end. @@ -725,7 +720,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { - (&self[..]).rsplit_array_ref::() + (&self[..]).split_last_chunk::().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -758,7 +753,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { - (&mut self[..]).rsplit_array_mut::() + (&mut self[..]).split_last_chunk_mut::().unwrap() } } diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index ef8e4d098ed95..02867789b79dd 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -96,6 +96,17 @@ pub fn escape_default(c: u8) -> EscapeDefault { EscapeDefault(escape::EscapeIterInner::new(data, range)) } +impl EscapeDefault { + pub(crate) fn empty() -> Self { + let data = [Char::Null; 4]; + EscapeDefault(escape::EscapeIterInner::new(data, 0..0)) + } + + pub(crate) fn as_str(&self) -> &str { + self.0.as_str() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for EscapeDefault { type Item = u8; diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index cc872a5343d6a..5f758af162477 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -537,6 +537,22 @@ impl AsciiChar { } } +macro_rules! into_int_impl { + ($($ty:ty)*) => { + $( + #[unstable(feature = "ascii_char", issue = "110998")] + impl From for $ty { + #[inline] + fn from(chr: AsciiChar) -> $ty { + chr as u8 as $ty + } + } + )* + } +} + +into_int_impl!(u8 u16 u32 u64 u128 char); + impl [AsciiChar] { /// Views this slice of ASCII characters as a UTF-8 `str`. #[unstable(feature = "ascii_char", issue = "110998")] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index bffd3b2af971a..a2f07814726ac 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -61,11 +61,13 @@ use self::Ordering::*; /// The equality relation `==` must satisfy the following conditions /// (for all `a`, `b`, `c` of type `A`, `B`, `C`): /// -/// - **Symmetric**: if `A: PartialEq` and `B: PartialEq`, then **`a == b` +/// - **Symmetry**: if `A: PartialEq` and `B: PartialEq`, then **`a == b` /// implies `b == a`**; and /// -/// - **Transitive**: if `A: PartialEq` and `B: PartialEq` and `A: +/// - **Transitivity**: if `A: PartialEq` and `B: PartialEq` and `A: /// PartialEq`, then **`a == b` and `b == c` implies `a == c`**. +/// This must also work for longer chains, such as when `A: PartialEq`, `B: PartialEq`, +/// `C: PartialEq`, and `A: PartialEq` all exist. /// /// Note that the `B: PartialEq` (symmetric) and `A: PartialEq` /// (transitive) impls are not forced to exist, but these requirements apply @@ -76,6 +78,25 @@ use self::Ordering::*; /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// +/// ## Cross-crate considerations +/// +/// Upholding the requirements stated above can become tricky when one crate implements `PartialEq` +/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the +/// standard library). The recommendation is to never implement this trait for a foreign type. In +/// other words, such a crate should do `impl PartialEq for LocalType`, but it should +/// *not* do `impl PartialEq for ForeignType`. +/// +/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local +/// types `T`, you may assume that no other crate will add `impl`s that allow comparing `T == U`. In +/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 == ... +/// == T == V1 == ...`, then all the types that appear to the right of `T` must be types that the +/// crate defining `T` already knows about. This rules out transitive chains where downstream crates +/// can add new `impl`s that "stitch together" comparisons of foreign types in ways that violate +/// transitivity. +/// +/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding +/// more `PartialEq` implementations can cause build failures in downstream crates. +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two @@ -710,7 +731,8 @@ impl Clone for Reverse { /// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering /// based on the top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered by their discriminants. +/// When `derive`d on enums, variants are ordered primarily by their discriminants. +/// Secondarily, they are ordered by their fields. /// By default, the discriminant is smallest for variants at the top, and /// largest for variants at the bottom. Here's an example: /// @@ -919,20 +941,43 @@ pub macro Ord($item:item) { /// easy to accidentally make them disagree by deriving some of the traits and manually /// implementing others. /// -/// The comparison must satisfy, for all `a`, `b` and `c`: +/// The comparison relations must satisfy the following conditions +/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): /// -/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. -/// - duality: `a < b` if and only if `b > a`. +/// - **Transitivity**: if `A: PartialOrd` and `B: PartialOrd` and `A: +/// PartialOrd`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// This must also work for longer chains, such as when `A: PartialOrd`, `B: PartialOrd`, +/// `C: PartialOrd`, and `A: PartialOrd` all exist. +/// - **Duality**: if `A: PartialOrd` and `B: PartialOrd`, then `a < b` if and only if `b > a`. /// -/// Note that these requirements mean that the trait itself must be implemented symmetrically and -/// transitively: if `T: PartialOrd` and `U: PartialOrd` then `U: PartialOrd` and `T: -/// PartialOrd`. +/// Note that the `B: PartialOrd` (dual) and `A: PartialOrd` +/// (transitive) impls are not forced to exist, but these requirements apply +/// whenever they do exist. /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// +/// ## Cross-crate considerations +/// +/// Upholding the requirements stated above can become tricky when one crate implements `PartialOrd` +/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the +/// standard library). The recommendation is to never implement this trait for a foreign type. In +/// other words, such a crate should do `impl PartialOrd for LocalType`, but it should +/// *not* do `impl PartialOrd for ForeignType`. +/// +/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local +/// types `T`, you may assume that no other crate will add `impl`s that allow comparing `T < U`. In +/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 < ... +/// < T < V1 < ...`, then all the types that appear to the right of `T` must be types that the crate +/// defining `T` already knows about. This rules out transitive chains where downstream crates can +/// add new `impl`s that "stitch together" comparisons of foreign types in ways that violate +/// transitivity. +/// +/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding +/// more `PartialOrd` implementations can cause build failures in downstream crates. +/// /// ## Corollaries /// /// The following corollaries follow from the above requirements: @@ -963,7 +1008,8 @@ pub macro Ord($item:item) { /// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering /// based on the top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered by their discriminants. +/// When `derive`d on enums, variants are primarily ordered by their discriminants. +/// Secondarily, they are ordered by their fields. /// By default, the discriminant is smallest for variants at the top, and /// largest for variants at the bottom. Here's an example: /// diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 8c01b0973d65a..45f6e375e8942 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -753,6 +753,7 @@ where /// That is, this conversion is whatever the implementation of /// [From]<T> for U chooses to do. #[inline] + #[track_caller] fn into(self) -> U { U::from(self) } diff --git a/library/core/src/error.rs b/library/core/src/error.rs index f1a7ad935480c..ded17e69bd9c6 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -415,7 +415,7 @@ where // Request and its methods /////////////////////////////////////////////////////////////////////////////// -/// `Request` supports generic, type-driven access to data. It's use is currently restricted to the +/// `Request` supports generic, type-driven access to data. Its use is currently restricted to the /// standard library in cases where trait authors wish to allow trait implementors to share generic /// information across trait boundaries. The motivating and prototypical use case is /// `core::error::Error` which would otherwise require a method per concrete type (eg. diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 7340ad90da509..44200926a32eb 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -11,7 +11,6 @@ use crate::fmt; use crate::marker::PhantomData; -use crate::num::*; use crate::ops::{Deref, DerefMut}; #[stable(feature = "core_c_str", since = "1.64.0")] @@ -19,7 +18,7 @@ pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError}; mod c_str; -macro_rules! type_alias_no_nz { +macro_rules! type_alias { { $Docfile:tt, $Alias:ident = $Real:ty; $( $Cfg:tt )* @@ -31,49 +30,24 @@ macro_rules! type_alias_no_nz { } } -// To verify that the NonZero types in this file's macro invocations correspond -// -// perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2' -// -// NB this does not check that the main c_* types are right. - -macro_rules! type_alias { - { - $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty; - $( $Cfg:tt )* - } => { - type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* } - - #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")] - #[unstable(feature = "raw_os_nonzero", issue = "82363")] - $( $Cfg )* - pub type $NZAlias = $NZReal; - } -} - -type_alias! { "c_char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char; -#[doc(cfg(all()))] } +type_alias! { "c_char.md", c_char = c_char_definition::c_char; #[doc(cfg(all()))] } -type_alias! { "c_schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; } -type_alias! { "c_uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; } -type_alias! { "c_short.md", c_short = i16, NonZero_c_short = NonZeroI16; } -type_alias! { "c_ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } +type_alias! { "c_schar.md", c_schar = i8; } +type_alias! { "c_uchar.md", c_uchar = u8; } +type_alias! { "c_short.md", c_short = i16; } +type_alias! { "c_ushort.md", c_ushort = u16; } -type_alias! { "c_int.md", c_int = c_int_definition::c_int, NonZero_c_int = c_int_definition::NonZero_c_int; -#[doc(cfg(all()))] } -type_alias! { "c_uint.md", c_uint = c_int_definition::c_uint, NonZero_c_uint = c_int_definition::NonZero_c_uint; -#[doc(cfg(all()))] } +type_alias! { "c_int.md", c_int = c_int_definition::c_int; #[doc(cfg(all()))] } +type_alias! { "c_uint.md", c_uint = c_int_definition::c_uint; #[doc(cfg(all()))] } -type_alias! { "c_long.md", c_long = c_long_definition::c_long, NonZero_c_long = c_long_definition::NonZero_c_long; -#[doc(cfg(all()))] } -type_alias! { "c_ulong.md", c_ulong = c_long_definition::c_ulong, NonZero_c_ulong = c_long_definition::NonZero_c_ulong; -#[doc(cfg(all()))] } +type_alias! { "c_long.md", c_long = c_long_definition::c_long; #[doc(cfg(all()))] } +type_alias! { "c_ulong.md", c_ulong = c_long_definition::c_ulong; #[doc(cfg(all()))] } -type_alias! { "c_longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } -type_alias! { "c_ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } +type_alias! { "c_longlong.md", c_longlong = i64; } +type_alias! { "c_ulonglong.md", c_ulonglong = u64; } -type_alias_no_nz! { "c_float.md", c_float = f32; } -type_alias_no_nz! { "c_double.md", c_double = f64; } +type_alias! { "c_float.md", c_float = f32; } +type_alias! { "c_double.md", c_double = f64; } /// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++). /// @@ -152,11 +126,9 @@ mod c_char_definition { target_os = "horizon" ))] { pub type c_char = u8; - pub type NonZero_c_char = crate::num::NonZeroU8; } else { // On every other target, c_char is signed. pub type c_char = i8; - pub type NonZero_c_char = crate::num::NonZeroI8; } } } @@ -165,14 +137,10 @@ mod c_int_definition { cfg_if! { if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { pub type c_int = i16; - pub type NonZero_c_int = crate::num::NonZeroI16; pub type c_uint = u16; - pub type NonZero_c_uint = crate::num::NonZeroU16; } else { pub type c_int = i32; - pub type NonZero_c_int = crate::num::NonZeroI32; pub type c_uint = u32; - pub type NonZero_c_uint = crate::num::NonZeroU32; } } } @@ -181,15 +149,11 @@ mod c_long_definition { cfg_if! { if #[cfg(all(target_pointer_width = "64", not(windows)))] { pub type c_long = i64; - pub type NonZero_c_long = crate::num::NonZeroI64; pub type c_ulong = u64; - pub type NonZero_c_ulong = crate::num::NonZeroU64; } else { // The minimal size of `long` in the C standard is 32 bits pub type c_long = i32; - pub type NonZero_c_long = crate::num::NonZeroI32; pub type c_ulong = u32; - pub type NonZero_c_ulong = crate::num::NonZeroU32; } } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 6b8490bc69b65..f4d37731bce0b 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2523,6 +2523,66 @@ extern "rust-intrinsic" { where G: FnOnce, F: FnOnce; + + /// Returns whether the argument's value is statically known at + /// compile-time. + /// + /// This is useful when there is a way of writing the code that will + /// be *faster* when some variables have known values, but *slower* + /// in the general case: an `if is_val_statically_known(var)` can be used + /// to select between these two variants. The `if` will be optimized away + /// and only the desired branch remains. + /// + /// Formally speaking, this function non-deterministically returns `true` + /// or `false`, and the caller has to ensure sound behavior for both cases. + /// In other words, the following code has *Undefined Behavior*: + /// + /// ```no_run + /// #![feature(is_val_statically_known)] + /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] + /// use std::hint::unreachable_unchecked; + /// use std::intrinsics::is_val_statically_known; + /// + /// unsafe { + /// if !is_val_statically_known(0) { unreachable_unchecked(); } + /// } + /// ``` + /// + /// This also means that the following code's behavior is unspecified; it + /// may panic, or it may not: + /// + /// ```no_run + /// #![feature(is_val_statically_known)] + /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] + /// use std::intrinsics::is_val_statically_known; + /// + /// unsafe { + /// assert_eq!(is_val_statically_known(0), is_val_statically_known(0)); + /// } + /// ``` + /// + /// Unsafe code may not rely on `is_val_statically_known` returning any + /// particular value, ever. However, the compiler will generally make it + /// return `true` only if the value of the argument is actually known. + /// + /// When calling this in a `const fn`, both paths must be semantically + /// equivalent, that is, the result of the `true` branch and the `false` + /// branch must return the same value and have the same side-effects *no + /// matter what*. + #[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")] + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn is_val_statically_known(arg: T) -> bool; +} + +// FIXME: Seems using `unstable` here completely ignores `rustc_allow_const_fn_unstable` +// and thus compiling stage0 core doesn't work. +#[rustc_const_stable(feature = "is_val_statically_known", since = "0.0.0")] +#[cfg(bootstrap)] +pub const unsafe fn is_val_statically_known(_arg: T) -> bool { + false } // Some functions are defined here because they accidentally got made @@ -2695,13 +2755,13 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[rustc_nounwind] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } @@ -2791,13 +2851,13 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[rustc_nounwind] fn copy(src: *const T, dst: *mut T, count: usize); } diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 334e32b26b184..d348e31609d48 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -357,6 +357,8 @@ define!("mir_unwind_resume", define!("mir_storage_live", fn StorageLive(local: T)); define!("mir_storage_dead", fn StorageDead(local: T)); +#[cfg(not(bootstrap))] +define!("mir_assume", fn Assume(operand: bool)); define!("mir_deinit", fn Deinit(place: T)); define!("mir_checked", fn Checked(binop: T) -> (T, bool)); define!("mir_len", fn Len(place: T) -> usize); diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index d3cceb8d4ad54..3de91267cf5d9 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,8 +1,9 @@ use crate::iter::adapters::{ - zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, + zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; -use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; use crate::ops::Try; +use core::num::NonZeroUsize; /// An iterator that clones the elements of an underlying iterator. /// @@ -167,3 +168,23 @@ impl Default for Cloned { Self::new(Default::default()) } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Cloned +where + I: SourceIter, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.it) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Cloned { + const EXPAND_BY: Option = I::EXPAND_BY; + const MERGE_BY: Option = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 7a2c9d839b7e4..52a5add1132a4 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,7 +1,7 @@ use crate::iter::adapters::{ - zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, + zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; -use crate::iter::{FusedIterator, TrustedLen}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::mem::MaybeUninit; use crate::mem::SizedTypeProperties; use crate::num::NonZeroUsize; @@ -255,3 +255,23 @@ impl Default for Copied { Self::new(Default::default()) } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Copied +where + I: SourceIter, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.it) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Copied { + const EXPAND_BY: Option = I::EXPAND_BY; + const MERGE_BY: Option = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 6122332da0d24..7d6f746845e31 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -24,6 +24,14 @@ impl U> FlatMap { pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } + + pub(crate) fn into_parts(self) -> (Option, Option, Option) { + ( + self.inner.frontiter, + self.inner.iter.into_inner().map(Map::into_inner), + self.inner.backiter, + ) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 462a7e8773320..7781ed088b76c 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -24,6 +24,10 @@ impl Fuse { pub(in crate::iter) fn new(iter: I) -> Fuse { Fuse { iter: Some(iter) } } + + pub(crate) fn into_inner(self) -> Option { + self.iter + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index d8bbd424cf258..c97a59b614f9d 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -1,4 +1,5 @@ -use super::Peekable; +use crate::fmt; +use crate::iter::{Fuse, FusedIterator}; /// An iterator adapter that places a separator between all elements. /// @@ -10,9 +11,18 @@ pub struct Intersperse where I::Item: Clone, { + started: bool, separator: I::Item, - iter: Peekable, - needs_sep: bool, + next_item: Option, + iter: Fuse, +} + +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl FusedIterator for Intersperse +where + I: FusedIterator, + I::Item: Clone, +{ } impl Intersperse @@ -20,7 +30,7 @@ where I::Item: Clone, { pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { - Self { iter: iter.peekable(), separator, needs_sep: false } + Self { started: false, separator, next_item: None, iter: iter.fuse() } } } @@ -33,27 +43,43 @@ where type Item = I::Item; #[inline] - fn next(&mut self) -> Option { - if self.needs_sep && self.iter.peek().is_some() { - self.needs_sep = false; - Some(self.separator.clone()) + fn next(&mut self) -> Option { + if self.started { + if let Some(v) = self.next_item.take() { + Some(v) + } else { + let next_item = self.iter.next(); + if next_item.is_some() { + self.next_item = next_item; + Some(self.separator.clone()) + } else { + None + } + } } else { - self.needs_sep = true; + self.started = true; self.iter.next() } } + fn size_hint(&self) -> (usize, Option) { + intersperse_size_hint(&self.iter, self.started, self.next_item.is_some()) + } + fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { let separator = self.separator; - intersperse_fold(self.iter, init, f, move || separator.clone(), self.needs_sep) - } - - fn size_hint(&self) -> (usize, Option) { - intersperse_size_hint(&self.iter, self.needs_sep) + intersperse_fold( + self.iter, + init, + f, + move || separator.clone(), + self.started, + self.next_item, + ) } } @@ -66,39 +92,50 @@ pub struct IntersperseWith where I: Iterator, { + started: bool, separator: G, - iter: Peekable, - needs_sep: bool, + next_item: Option, + iter: Fuse, +} + +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl FusedIterator for IntersperseWith +where + I: FusedIterator, + G: FnMut() -> I::Item, +{ } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -impl crate::fmt::Debug for IntersperseWith +impl fmt::Debug for IntersperseWith where - I: Iterator + crate::fmt::Debug, - I::Item: crate::fmt::Debug, - G: crate::fmt::Debug, + I: Iterator + fmt::Debug, + I::Item: fmt::Debug, + G: fmt::Debug, { - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("IntersperseWith") + .field("started", &self.started) .field("separator", &self.separator) .field("iter", &self.iter) - .field("needs_sep", &self.needs_sep) + .field("next_item", &self.next_item) .finish() } } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -impl crate::clone::Clone for IntersperseWith +impl Clone for IntersperseWith where - I: Iterator + crate::clone::Clone, - I::Item: crate::clone::Clone, + I: Iterator + Clone, + I::Item: Clone, G: Clone, { fn clone(&self) -> Self { - IntersperseWith { + Self { + started: self.started, separator: self.separator.clone(), iter: self.iter.clone(), - needs_sep: self.needs_sep.clone(), + next_item: self.next_item.clone(), } } } @@ -109,7 +146,7 @@ where G: FnMut() -> I::Item, { pub(in crate::iter) fn new(iter: I, separator: G) -> Self { - Self { iter: iter.peekable(), separator, needs_sep: false } + Self { started: false, separator, next_item: None, iter: iter.fuse() } } } @@ -122,38 +159,52 @@ where type Item = I::Item; #[inline] - fn next(&mut self) -> Option { - if self.needs_sep && self.iter.peek().is_some() { - self.needs_sep = false; - Some((self.separator)()) + fn next(&mut self) -> Option { + if self.started { + if let Some(v) = self.next_item.take() { + Some(v) + } else { + let next_item = self.iter.next(); + if next_item.is_some() { + self.next_item = next_item; + Some((self.separator)()) + } else { + None + } + } } else { - self.needs_sep = true; + self.started = true; self.iter.next() } } + fn size_hint(&self) -> (usize, Option) { + intersperse_size_hint(&self.iter, self.started, self.next_item.is_some()) + } + fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - intersperse_fold(self.iter, init, f, self.separator, self.needs_sep) - } - - fn size_hint(&self) -> (usize, Option) { - intersperse_size_hint(&self.iter, self.needs_sep) + intersperse_fold(self.iter, init, f, self.separator, self.started, self.next_item) } } -fn intersperse_size_hint(iter: &I, needs_sep: bool) -> (usize, Option) +fn intersperse_size_hint(iter: &I, started: bool, next_is_some: bool) -> (usize, Option) where I: Iterator, { let (lo, hi) = iter.size_hint(); - let next_is_elem = !needs_sep; ( - lo.saturating_sub(next_is_elem as usize).saturating_add(lo), - hi.and_then(|hi| hi.saturating_sub(next_is_elem as usize).checked_add(hi)), + lo.saturating_sub(!started as usize) + .saturating_add(next_is_some as usize) + .saturating_add(lo), + hi.and_then(|hi| { + hi.saturating_sub(!started as usize) + .saturating_add(next_is_some as usize) + .checked_add(hi) + }), ) } @@ -162,7 +213,8 @@ fn intersperse_fold( init: B, mut f: F, mut separator: G, - needs_sep: bool, + started: bool, + mut next_item: Option, ) -> B where I: Iterator, @@ -171,12 +223,9 @@ where { let mut accum = init; - if !needs_sep { - if let Some(x) = iter.next() { - accum = f(accum, x); - } else { - return accum; - } + let first = if started { next_item.take() } else { iter.next() }; + if let Some(x) = first { + accum = f(accum, x); } iter.fold(accum, |mut accum, x| { diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index e27fc7257f6cc..c882c9e7f3f51 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -69,6 +69,10 @@ impl Map { pub(in crate::iter) fn new(iter: I, f: F) -> Map { Map { iter, f } } + + pub(crate) fn into_inner(self) -> I { + self.iter + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index e6c946e7f880d..f5188dd458df9 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -1,6 +1,10 @@ use crate::intrinsics::unlikely; +use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::TrustedFused; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{ + adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess, + TrustedRandomAccessNoCoerce, +}; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -152,6 +156,32 @@ where NonZeroUsize::new(n).map_or(Ok(()), Err) } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccessNoCoerce, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + // + // Dropping the skipped prefix when index 0 is passed is safe + // since + // * the caller passing index 0 means that the inner iterator has more items than `self.n` + // * TRA contract requires that get_unchecked will only be called once + // (unless elements are copyable) + // * it does not conflict with in-place iteration since index 0 must be accessed + // before something is written into the storage used by the prefix + unsafe { + if Self::MAY_HAVE_SIDE_EFFECT && idx == 0 { + for skipped_idx in 0..self.n { + drop(try_get_unchecked(&mut self.iter, skipped_idx)); + } + } + + try_get_unchecked(&mut self.iter, idx + self.n) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -237,3 +267,23 @@ unsafe impl InPlaceIterable for Skip { const EXPAND_BY: Option = I::EXPAND_BY; const MERGE_BY: Option = I::MERGE_BY; } + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Skip where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNoCoerce for Skip +where + I: TrustedRandomAccessNoCoerce, +{ + const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; +} + +// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly. +// These requirements can only be satisfied when the upper bound of the inner iterator's upper +// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while +// I: TrustedLen would not. +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Skip where I: Iterator + TrustedRandomAccess {} diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 9e83584e3f3db..54ed4c952fb8b 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,7 +1,7 @@ use crate::convert::TryFrom; use crate::{ intrinsics, - iter::{from_fn, TrustedLen}, + iter::{from_fn, TrustedLen, TrustedRandomAccess}, ops::{Range, Try}, }; @@ -124,6 +124,14 @@ where #[stable(feature = "iterator_step_by", since = "1.28.0")] impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} +// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly. +// These requirements can only be satisfied when the upper bound of the inner iterator's upper +// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while +// I: TrustedLen would not. +// This also covers the Range specializations since the ranges also implement TRA +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for StepBy where I: Iterator + TrustedRandomAccess {} + trait SpecRangeSetup { fn setup(inner: T, step: usize) -> T; } @@ -480,12 +488,6 @@ macro_rules! spec_int_ranges { acc } } - - /// Safety: This macro is only applied to ranges over types <= usize - /// which means the inner length is guaranteed to fit into a usize and so - /// the outer length calculation won't encounter clamped values - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for StepBy> {} )*) } diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index 0b0445850bf52..db2f8b7ac283f 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -59,7 +59,6 @@ use crate::num::NonZeroUsize; /// ``` #[inline] #[unstable(feature = "iter_repeat_n", issue = "104434")] -#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly pub fn repeat_n(element: T, count: usize) -> RepeatN { let mut element = ManuallyDrop::new(element); @@ -79,7 +78,6 @@ pub fn repeat_n(element: T, count: usize) -> RepeatN { /// See its documentation for more. #[derive(Clone, Debug)] #[unstable(feature = "iter_repeat_n", issue = "104434")] -#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly pub struct RepeatN { count: usize, // Invariant: has been dropped iff count == 0. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d94a508b5b28a..83f8fd25b50bd 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -4033,42 +4033,42 @@ pub trait Iterator { Self: Sized, Self::Item: PartialOrd, { - self.is_sorted_by(PartialOrd::partial_cmp) + self.is_sorted_by(|a, b| a <= b) } /// Checks if the elements of this iterator are sorted using the given comparator function. /// /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` - /// function to determine the ordering of two elements. Apart from that, it's equivalent to - /// [`is_sorted`]; see its documentation for more information. + /// function to determine whether two elements are to be considered in sorted order. /// /// # Examples /// /// ``` /// #![feature(is_sorted)] /// - /// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a.partial_cmp(b))); - /// assert!(![1, 3, 2, 4].iter().is_sorted_by(|a, b| a.partial_cmp(b))); - /// assert!([0].iter().is_sorted_by(|a, b| a.partial_cmp(b))); - /// assert!(std::iter::empty::().is_sorted_by(|a, b| a.partial_cmp(b))); - /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); - /// ``` + /// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a <= b)); + /// assert!(![1, 2, 2, 9].iter().is_sorted_by(|a, b| a < b)); /// - /// [`is_sorted`]: Iterator::is_sorted + /// assert!([0].iter().is_sorted_by(|a, b| true)); + /// assert!([0].iter().is_sorted_by(|a, b| false)); + /// + /// assert!(std::iter::empty::().is_sorted_by(|a, b| false)); + /// assert!(std::iter::empty::().is_sorted_by(|a, b| true)); + /// ``` #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] #[rustc_do_not_const_check] fn is_sorted_by(mut self, compare: F) -> bool where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, + F: FnMut(&Self::Item, &Self::Item) -> bool, { #[inline] fn check<'a, T>( last: &'a mut T, - mut compare: impl FnMut(&T, &T) -> Option + 'a, + mut compare: impl FnMut(&T, &T) -> bool + 'a, ) -> impl FnMut(T) -> bool + 'a { move |curr| { - if let Some(Ordering::Greater) | None = compare(&last, &curr) { + if !compare(&last, &curr) { return false; } *last = curr; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1a8f245c8be30..09d589f7cd807 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -111,6 +111,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(not(bootstrap), feature(offset_of_nested))] #![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] @@ -131,8 +132,10 @@ #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] +#![feature(const_hint_assert_unchecked)] #![feature(const_index_range_slice_index)] #![feature(const_int_unchecked_arith)] +#![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] #![feature(const_ipv6)] @@ -160,6 +163,7 @@ #![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] +#![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] #![feature(const_type_id)] @@ -176,7 +180,6 @@ #![feature(isqrt)] #![feature(maybe_uninit_uninit_array)] #![feature(non_null_convenience)] -#![feature(offset_of)] #![feature(offset_of_enum)] #![feature(panic_internals)] #![feature(ptr_alignment_type)] @@ -184,6 +187,7 @@ #![feature(set_ptr_value)] #![feature(slice_ptr_get)] #![feature(slice_split_at_unchecked)] +#![feature(split_at_checked)] #![feature(str_internals)] #![feature(str_split_inclusive_remainder)] #![feature(str_split_remainder)] @@ -425,10 +429,6 @@ pub mod primitive; deprecated_in_future )] #[allow(rustdoc::bare_urls)] -// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is -// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. -#[allow(clashing_extern_declarations)] -#[unstable(feature = "stdsimd", issue = "48556")] mod core_arch; #[stable(feature = "simd_arch", since = "1.27.0")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a2437feeeb9cf..9bbaf62a5caaf 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1596,7 +1596,7 @@ pub(crate) mod builtin { /// /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(test, rustc_attrs)] + #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] #[rustc_builtin_macro] pub macro test($item:item) { /* compiler built-in */ @@ -1609,7 +1609,7 @@ pub(crate) mod builtin { soft, reason = "`bench` is a part of custom test frameworks which are unstable" )] - #[allow_internal_unstable(test, rustc_attrs)] + #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] #[rustc_builtin_macro] pub macro bench($item:item) { /* compiler built-in */ diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 561f8ef36ffde..d6e0e1895cdff 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -187,7 +187,7 @@ pub trait Unsize { /// Required trait for constants used in pattern matches. /// /// Any type that derives `PartialEq` automatically implements this trait, -/// *regardless* of whether its type-parameters implement `Eq`. +/// *regardless* of whether its type-parameters implement `PartialEq`. /// /// If a `const` item contains some type that does not implement this trait, /// then that type either (1.) does not implement `PartialEq` (which means the @@ -200,7 +200,7 @@ pub trait Unsize { /// a pattern match. /// /// See also the [structural match RFC][RFC1445], and [issue 63438] which -/// motivated migrating from attribute-based design to this trait. +/// motivated migrating from an attribute-based design to this trait. /// /// [RFC1445]: https://github.com/rust-lang/rfcs/blob/master/text/1445-restrict-constants-in-patterns.md /// [issue 63438]: https://github.com/rust-lang/rust/issues/63438 @@ -218,7 +218,7 @@ marker_impls! { isize, i8, i16, i32, i64, i128, bool, char, - str /* Technically requires `[u8]: StructuralEq` */, + str /* Technically requires `[u8]: StructuralPartialEq` */, (), {T, const N: usize} [T; N], {T} [T], @@ -275,6 +275,7 @@ marker_impls! { #[unstable(feature = "structural_match", issue = "31434")] #[diagnostic::on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] #[lang = "structural_teq"] +#[cfg(bootstrap)] pub trait StructuralEq { // Empty. } @@ -282,6 +283,7 @@ pub trait StructuralEq { // FIXME: Remove special cases of these types from the compiler pattern checking code and always check `T: StructuralEq` instead marker_impls! { #[unstable(feature = "structural_match", issue = "31434")] + #[cfg(bootstrap)] StructuralEq for usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, @@ -859,6 +861,7 @@ impl Default for PhantomData { impl StructuralPartialEq for PhantomData {} #[unstable(feature = "structural_match", issue = "31434")] +#[cfg(bootstrap)] impl StructuralEq for PhantomData {} /// Compiler-internal trait used to indicate the type of enum discriminants. @@ -1038,6 +1041,20 @@ pub trait PointerLike {} #[unstable(feature = "adt_const_params", issue = "95174")] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] #[allow(multiple_supertrait_upcastable)] +#[cfg(not(bootstrap))] +pub trait ConstParamTy: StructuralPartialEq + Eq {} + +/// A marker for types which can be used as types of `const` generic parameters. +/// +/// These types must have a proper equivalence relation (`Eq`) and it must be automatically +/// derived (`StructuralPartialEq`). There's a hard-coded check in the compiler ensuring +/// that all fields are also `ConstParamTy`, which implies that recursively, all fields +/// are `StructuralPartialEq`. +#[lang = "const_param_ty"] +#[unstable(feature = "adt_const_params", issue = "95174")] +#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] +#[allow(multiple_supertrait_upcastable)] +#[cfg(bootstrap)] pub trait ConstParamTy: StructuralEq + StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 407954001e4ce..318a99e23ec64 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -736,7 +736,7 @@ pub const fn swap(x: &mut T, y: &mut T) { // tends to copy the whole thing to stack rather than doing it one part // at a time, so instead treat them as one-element slices and piggy-back // the slice optimizations that will split up the swaps. - if size_of::() / align_of::() > 4 { + if const { size_of::() / align_of::() > 2 } { // SAFETY: exclusive references always point to one non-overlapping // element and are non-null and properly aligned. return unsafe { ptr::swap_nonoverlapping(x, y, 1) }; @@ -1303,11 +1303,12 @@ impl SizedTypeProperties for T {} /// Enum variants may be traversed as if they were fields. Variants themselves do /// not have an offset. /// +/// However, on stable only a single field name is supported, which blocks the use of +/// enum support. +/// /// Visibility is respected - all types and fields must be visible to the call site: /// /// ``` -/// #![feature(offset_of)] -/// /// mod nested { /// #[repr(C)] /// pub struct Struct { @@ -1330,8 +1331,6 @@ impl SizedTypeProperties for T {} /// not *identical*, e.g.: /// /// ``` -/// #![feature(offset_of)] -/// /// struct Wrapper(T, U); /// /// type A = Wrapper; @@ -1359,8 +1358,7 @@ impl SizedTypeProperties for T {} /// # Examples /// /// ``` -/// #![feature(offset_of)] -/// # #![feature(offset_of_enum)] +/// #![feature(offset_of_enum, offset_of_nested)] /// /// use std::mem; /// #[repr(C)] @@ -1396,7 +1394,7 @@ impl SizedTypeProperties for T {} /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` #[cfg(not(bootstrap))] -#[unstable(feature = "offset_of", issue = "106655")] +#[stable(feature = "offset_of", since = "CURRENT_RUSTC_VERSION")] #[allow_internal_unstable(builtin_syntax, hint_must_use)] pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { // The `{}` is for better error messages @@ -1404,7 +1402,7 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { } #[cfg(bootstrap)] -#[unstable(feature = "offset_of", issue = "106655")] +#[stable(feature = "offset_of", since = "CURRENT_RUSTC_VERSION")] #[allow_internal_unstable(builtin_syntax, hint_must_use)] #[allow(missing_docs)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 4b5862d98a3ab..959c3289affbf 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1785,6 +1785,31 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } + /// Returns [`true`] if the address is an IPv4-mapped address (`::ffff:0:0/96`). + /// + /// IPv4-mapped addresses can be converted to their canonical IPv4 address with + /// [`to_ipv4_mapped`](Ipv6Addr::to_ipv4_mapped). + /// + /// # Examples + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// let ipv4_mapped = Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(); + /// assert_eq!(ipv4_mapped.is_ipv4_mapped(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff).is_ipv4_mapped(), true); + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_ipv4_mapped(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_ipv4_mapped(&self) -> bool { + matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + } + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. /// @@ -1868,7 +1893,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index fd01f1b261012..d052dcc3e6ee6 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -451,7 +451,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict integer addition. Computes `self + rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_add(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) { overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -498,7 +531,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict addition with an unsigned integer. Computes `self + rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) { overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if @@ -519,7 +585,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict integer subtraction. Computes `self - rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_sub(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) { overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -566,7 +665,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict subtraction with an unsigned integer. Computes `self - rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) { overflow_panic::sub() } else { a } } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if @@ -587,7 +719,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict integer multiplication. Computes `self * rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] + /// ``` + /// + /// ``` should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_mul(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) { overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -642,6 +807,50 @@ macro_rules! int_impl { } } + /// Strict integer division. Computes `self / rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where + /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_div(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_div(rhs); + if unlikely!(b) { overflow_panic::div() } else { a } + } + /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, /// returning `None` if `rhs == 0` or the division results in overflow. /// @@ -668,6 +877,50 @@ macro_rules! int_impl { } } + /// Strict Euclidean division. Computes `self.div_euclid(rhs)`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where + /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_div_euclid(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_div_euclid(rhs); + if unlikely!(b) { overflow_panic::div() } else { a } + } + /// Checked integer remainder. Computes `self % rhs`, returning `None` if /// `rhs == 0` or the division results in overflow. /// @@ -694,6 +947,49 @@ macro_rules! int_impl { } } + /// Strict integer remainder. Computes `self % rhs`, panicking if + /// the division results in overflow. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a + /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_rem(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_rem(rhs); + if unlikely!(b) { overflow_panic::rem() } else { a } + } + /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` /// if `rhs == 0` or the division results in overflow. /// @@ -720,6 +1016,49 @@ macro_rules! int_impl { } } + /// Strict Euclidean remainder. Computes `self.rem_euclid(rhs)`, panicking if + /// the division results in overflow. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a + /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_rem_euclid(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_rem_euclid(rhs); + if unlikely!(b) { overflow_panic::rem() } else { a } + } + /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. /// /// # Examples @@ -737,7 +1076,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Unchecked negation. Computes `-self`, assuming overflow cannot occur. @@ -765,6 +1104,38 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(0, self) } } + /// Strict negation. Computes `-self`, panicking if `self == MIN`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] + /// + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_neg(self) -> Self { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) { overflow_panic::neg() } else { a } + } + /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger /// than or equal to the number of bits in `self`. /// @@ -783,7 +1154,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger + /// than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_shl(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -831,7 +1235,40 @@ macro_rules! int_impl { #[inline] pub const fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// larger than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_shr(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that @@ -885,6 +1322,42 @@ macro_rules! int_impl { } } + /// Strict absolute value. Computes `self.abs()`, panicking if + /// `self == MIN`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_abs(self) -> Self { + if self.is_negative() { + self.strict_neg() + } else { + self + } + } + /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if /// overflow occurred. /// @@ -923,6 +1396,55 @@ macro_rules! int_impl { acc.checked_mul(base) } + /// Strict exponentiation. Computes `self.pow(exp)`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.strict_mul(base); + } + exp /= 2; + base = base.strict_mul(base); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.strict_mul(base) + } + /// Returns the square root of the number, rounded down. /// /// Returns `None` if `self` is negative. @@ -1121,6 +1643,10 @@ macro_rules! int_impl { /// Saturating integer division. Computes `self / rhs`, saturating at the /// numeric bounds instead of overflowing. /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// /// # Examples /// /// Basic usage: @@ -1131,11 +1657,6 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_div(-1), ", stringify!($SelfT), "::MAX);")] /// /// ``` - /// - /// ```should_panic - #[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")] - /// - /// ``` #[stable(feature = "saturating_div", since = "1.58.0")] #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")] #[must_use = "this returns the result of the operation, \ @@ -1913,6 +2434,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { if unlikely!(rhs == -1) { (0, self == Self::MIN) @@ -2152,7 +2674,8 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or the division results in overflow. + /// This function will panic if `rhs` is 0 or if `self` is -1 and `rhs` is + /// `Self::MIN`. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples /// @@ -2172,7 +2695,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn div_euclid(self, rhs: Self) -> Self { let q = self / rhs; if self % rhs < 0 { @@ -2190,7 +2713,8 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or the division results in overflow. + /// This function will panic if `rhs` is 0 or if `self` is -1 and `rhs` is + /// `Self::MIN`. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples /// @@ -2211,7 +2735,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn rem_euclid(self, rhs: Self) -> Self { let r = self % rhs; if r < 0 { @@ -2233,12 +2757,8 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is zero. - /// - /// ## Overflow behavior - /// - /// On overflow, this function will panic if overflow checks are enabled (default in debug - /// mode) and wrap if overflow checks are disabled (default in release mode). + /// This function will panic if `rhs` is 0 or if `self` is -1 and `rhs` is + /// `Self::MIN`. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples /// @@ -2258,7 +2778,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn div_floor(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; @@ -2273,12 +2793,8 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is zero. - /// - /// ## Overflow behavior - /// - /// On overflow, this function will panic if overflow checks are enabled (default in debug - /// mode) and wrap if overflow checks are disabled (default in release mode). + /// This function will panic if `rhs` is 0 or if `self` is -1 and `rhs` is + /// `Self::MIN`. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples /// @@ -2298,7 +2814,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f5d765e690db4..03c977abbbb42 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,6 +3,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; +use crate::hint; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -44,6 +45,7 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod nonzero; +mod overflow_panic; mod saturating; mod wrapping; @@ -59,7 +61,15 @@ pub use dec2flt::ParseFloatError; #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; -pub(crate) use nonzero::NonZero; +#[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +pub use nonzero::ZeroablePrimitive; + +#[unstable(feature = "generic_nonzero", issue = "120257")] +pub use nonzero::NonZero; #[stable(feature = "nonzero", since = "1.28.0")] pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7d60686597a0d..1124719fc8df1 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,11 @@ //! Definitions of integer that is known not to equal zero. +use crate::cmp::Ordering; use crate::fmt; +use crate::hash::{Hash, Hasher}; +#[cfg(bootstrap)] +use crate::marker::StructuralEq; +use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; use crate::str::FromStr; @@ -27,16 +32,7 @@ mod private { issue = "none" )] #[const_trait] -pub trait ZeroablePrimitive: Sized + Copy + private::Sealed { - type NonZero; -} - -#[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" -)] -pub(crate) type NonZero = ::NonZero; +pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {} macro_rules! impl_zeroable_primitive { ($NonZero:ident ( $primitive:ty )) => { @@ -52,9 +48,7 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - impl const ZeroablePrimitive for $primitive { - type NonZero = $NonZero; - } + impl const ZeroablePrimitive for $primitive {} }; } @@ -71,6 +65,24 @@ impl_zeroable_primitive!(NonZeroI64(i64)); impl_zeroable_primitive!(NonZeroI128(i128)); impl_zeroable_primitive!(NonZeroIsize(isize)); +/// A value that is known not to equal zero. +/// +/// This enables some memory layout optimization. +/// For example, `Option>` is the same size as `u32`: +/// +/// ``` +/// #![feature(generic_nonzero)] +/// use core::mem::size_of; +/// +/// assert_eq!(size_of::>>(), size_of::()); +/// ``` +#[unstable(feature = "generic_nonzero", issue = "120257")] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(1)] +#[rustc_nonnull_optimization_guaranteed] +#[rustc_diagnostic_item = "NonZero"] +pub struct NonZero(T); + macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( @@ -128,12 +140,7 @@ macro_rules! nonzero_integer { /// /// [null pointer optimization]: crate::option#representation #[$stability] - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - #[rustc_diagnostic_item = stringify!($Ty)] - pub struct $Ty($Int); + pub type $Ty = NonZero<$Int>; impl $Ty { /// Creates a non-zero without checking whether the value is non-zero. @@ -171,6 +178,39 @@ macro_rules! nonzero_integer { } } + /// Converts a primitive mutable reference to a non-zero mutable reference + /// without checking whether the referenced value is non-zero. + /// This results in undefined behavior if `*n` is zero. + /// + /// # Safety + /// The referenced value must not be currently zero. + #[unstable(feature = "nonzero_from_mut", issue = "106290")] + #[must_use] + #[inline] + pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self { + // SAFETY: Self is repr(transparent), and the value is assumed to be non-zero. + unsafe { + let n_alias = &mut *n; + core::intrinsics::assert_unsafe_precondition!( + concat!(stringify!($Ty), "::from_mut_unchecked requires the argument to dereference as non-zero"), + (n_alias: &mut $Int) => *n_alias != 0 + ); + &mut *(n as *mut $Int as *mut Self) + } + } + + /// Converts a primitive mutable reference to a non-zero mutable reference + /// if the referenced integer is not zero. + #[unstable(feature = "nonzero_from_mut", issue = "106290")] + #[must_use] + #[inline] + pub fn from_mut(n: &mut $Int) -> Option<&mut Self> { + // SAFETY: Self is repr(transparent), and the value is non-zero. + // As long as the returned reference is alive, + // the user cannot `*n = 0` directly. + (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) }) + } + /// Returns the value as a primitive type. #[$stability] #[inline] @@ -252,6 +292,43 @@ macro_rules! nonzero_integer { unsafe { intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) as u32 } } + /// Returns the number of ones in the binary representation of `self`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(non_zero_count_ones)] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("# use std::num::{self, ", stringify!($Ty), "};")] + /// + /// let one = num::NonZeroU32::new(1)?; + /// let three = num::NonZeroU32::new(3)?; + #[doc = concat!("let a = ", stringify!($Ty), "::new(0b100_0000)?;")] + #[doc = concat!("let b = ", stringify!($Ty), "::new(0b100_0011)?;")] + /// + /// assert_eq!(a.count_ones(), one); + /// assert_eq!(b.count_ones(), three); + /// # Some(()) + /// # } + /// ``` + /// + #[unstable(feature = "non_zero_count_ones", issue = "120287")] + #[rustc_const_unstable(feature = "non_zero_count_ones", issue = "120287")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn count_ones(self) -> NonZeroU32 { + // SAFETY: + // `self` is non-zero, which means it has at least one bit set, which means + // that the result of `count_ones` is non-zero. + unsafe { NonZeroU32::new_unchecked(self.get().count_ones()) } + } + nonzero_integer_signedness_dependent_methods! { Self = $Ty, Primitive = $signedness $Int, @@ -284,7 +361,7 @@ macro_rules! nonzero_integer { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { + pub const fn checked_mul(self, other: Self) -> Option { if let Some(result) = self.get().checked_mul(other.get()) { // SAFETY: // - `checked_mul` returns `None` on overflow @@ -293,7 +370,7 @@ macro_rules! nonzero_integer { // of the sides to be zero // // So the result cannot be zero. - Some(unsafe { $Ty::new_unchecked(result) }) + Some(unsafe { Self::new_unchecked(result) }) } else { None } @@ -323,7 +400,7 @@ macro_rules! nonzero_integer { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn saturating_mul(self, other: $Ty) -> $Ty { + pub const fn saturating_mul(self, other: Self) -> Self { // SAFETY: // - `saturating_mul` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, // all of which are non-zero @@ -332,7 +409,7 @@ macro_rules! nonzero_integer { // of the sides to be zero // // So the result cannot be zero. - unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } + unsafe { Self::new_unchecked(self.get().saturating_mul(other.get())) } } /// Multiplies two non-zero integers together, @@ -370,9 +447,9 @@ macro_rules! nonzero_integer { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { + pub const unsafe fn unchecked_mul(self, other: Self) -> Self { // SAFETY: The caller ensures there is no overflow. - unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } + unsafe { Self::new_unchecked(self.get().unchecked_mul(other.get())) } } /// Raises non-zero value to an integer power. @@ -400,7 +477,7 @@ macro_rules! nonzero_integer { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_pow(self, other: u32) -> Option<$Ty> { + pub const fn checked_pow(self, other: u32) -> Option { if let Some(result) = self.get().checked_pow(other) { // SAFETY: // - `checked_pow` returns `None` on overflow/underflow @@ -409,7 +486,7 @@ macro_rules! nonzero_integer { // for base to be zero // // So the result cannot be zero. - Some(unsafe { $Ty::new_unchecked(result) }) + Some(unsafe { Self::new_unchecked(result) }) } else { None } @@ -448,7 +525,7 @@ macro_rules! nonzero_integer { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn saturating_pow(self, other: u32) -> $Ty { + pub const fn saturating_pow(self, other: u32) -> Self { // SAFETY: // - `saturating_pow` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, // all of which are non-zero @@ -457,7 +534,107 @@ macro_rules! nonzero_integer { // for base to be zero // // So the result cannot be zero. - unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) } + unsafe { Self::new_unchecked(self.get().saturating_pow(other)) } + } + } + + #[$stability] + impl Clone for $Ty { + #[inline] + fn clone(&self) -> Self { + // SAFETY: The contained value is non-zero. + unsafe { Self(self.0) } + } + } + + #[$stability] + impl Copy for $Ty {} + + #[$stability] + impl PartialEq for $Ty { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + + #[inline] + fn ne(&self, other: &Self) -> bool { + self.0 != other.0 + } + } + + #[unstable(feature = "structural_match", issue = "31434")] + impl StructuralPartialEq for $Ty {} + + #[$stability] + impl Eq for $Ty {} + + #[unstable(feature = "structural_match", issue = "31434")] + #[cfg(bootstrap)] + impl StructuralEq for $Ty {} + + #[$stability] + impl PartialOrd for $Ty { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } + + #[inline] + fn lt(&self, other: &Self) -> bool { + self.0 < other.0 + } + + #[inline] + fn le(&self, other: &Self) -> bool { + self.0 <= other.0 + } + + #[inline] + fn gt(&self, other: &Self) -> bool { + self.0 > other.0 + } + + #[inline] + fn ge(&self, other: &Self) -> bool { + self.0 >= other.0 + } + } + + #[$stability] + impl Ord for $Ty { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } + + #[inline] + fn max(self, other: Self) -> Self { + // SAFETY: The maximum of two non-zero values is still non-zero. + unsafe { Self(self.0.max(other.0)) } + } + + #[inline] + fn min(self, other: Self) -> Self { + // SAFETY: The minimum of two non-zero values is still non-zero. + unsafe { Self(self.0.min(other.0)) } + } + + #[inline] + fn clamp(self, min: Self, max: Self) -> Self { + // SAFETY: A non-zero value clamped between two non-zero values is still non-zero. + unsafe { Self(self.0.clamp(min.0, max.0)) } + } + } + + #[$stability] + impl Hash for $Ty { + #[inline] + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.0.hash(state) } } @@ -475,29 +652,32 @@ macro_rules! nonzero_integer { #[stable(feature = "nonzero_bitor", since = "1.45.0")] impl BitOr for $Ty { type Output = Self; + #[inline] fn bitor(self, rhs: Self) -> Self::Output { // SAFETY: since `self` and `rhs` are both nonzero, the // result of the bitwise-or will be nonzero. - unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } + unsafe { Self::new_unchecked(self.get() | rhs.get()) } } } #[stable(feature = "nonzero_bitor", since = "1.45.0")] impl BitOr<$Int> for $Ty { type Output = Self; + #[inline] fn bitor(self, rhs: $Int) -> Self::Output { // SAFETY: since `self` is nonzero, the result of the // bitwise-or will be nonzero regardless of the value of // `rhs`. - unsafe { $Ty::new_unchecked(self.get() | rhs) } + unsafe { Self::new_unchecked(self.get() | rhs) } } } #[stable(feature = "nonzero_bitor", since = "1.45.0")] impl BitOr<$Ty> for $Int { type Output = $Ty; + #[inline] fn bitor(self, rhs: $Ty) -> Self::Output { // SAFETY: since `rhs` is nonzero, the result of the @@ -570,6 +750,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { #[stable(feature = "nonzero_div", since = "1.51.0")] impl Div<$Ty> for $Int { type Output = $Int; + /// This operation rounds towards zero, /// truncating any fractional part of the exact result, and cannot panic. #[inline] @@ -583,6 +764,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { #[stable(feature = "nonzero_div", since = "1.51.0")] impl Rem<$Ty> for $Int { type Output = $Int; + /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. #[inline] fn rem(self, other: $Ty) -> $Int { @@ -597,12 +779,12 @@ macro_rules! nonzero_integer_signedness_dependent_impls { ($Ty:ident signed $Int:ty) => { #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] impl Neg for $Ty { - type Output = $Ty; + type Output = Self; #[inline] - fn neg(self) -> $Ty { + fn neg(self) -> Self { // SAFETY: negation of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(self.get().neg()) } + unsafe { Self::new_unchecked(self.get().neg()) } } } @@ -670,7 +852,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_add(self, other: $Int) -> Option<$Ty> { + pub const fn checked_add(self, other: $Int) -> Option { if let Some(result) = self.get().checked_add(other) { // SAFETY: // - `checked_add` returns `None` on overflow @@ -679,7 +861,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // sides to be zero // // So the result cannot be zero. - Some(unsafe { $Ty::new_unchecked(result) }) + Some(unsafe { Self::new_unchecked(result) }) } else { None } @@ -709,7 +891,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn saturating_add(self, other: $Int) -> $Ty { + pub const fn saturating_add(self, other: $Int) -> Self { // SAFETY: // - `saturating_add` returns `u*::MAX` on overflow, which is non-zero // - `self` is non-zero @@ -717,7 +899,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // sides to be zero // // So the result cannot be zero. - unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } + unsafe { Self::new_unchecked(self.get().saturating_add(other)) } } /// Adds an unsigned integer to a non-zero value, @@ -746,9 +928,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_add(self, other: $Int) -> $Ty { + pub const unsafe fn unchecked_add(self, other: $Int) -> Self { // SAFETY: The caller ensures there is no overflow. - unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } + unsafe { Self::new_unchecked(self.get().unchecked_add(other)) } } /// Returns the smallest power of two greater than or equal to n. @@ -779,11 +961,11 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_next_power_of_two(self) -> Option<$Ty> { + pub const fn checked_next_power_of_two(self) -> Option { if let Some(nz) = self.get().checked_next_power_of_two() { // SAFETY: The next power of two is positive // and overflow is checked. - Some(unsafe { $Ty::new_unchecked(nz) }) + Some(unsafe { Self::new_unchecked(nz) }) } else { None } @@ -869,9 +1051,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { pub const fn midpoint(self, rhs: Self) -> Self { // SAFETY: The only way to get `0` with midpoint is to have two opposite or // near opposite numbers: (-5, 5), (0, 1), (0, 0) which is impossible because - // of the unsignedness of this number and also because $Ty is guaranteed to + // of the unsignedness of this number and also because `Self` is guaranteed to // never being 0. - unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) } + unsafe { Self::new_unchecked(self.get().midpoint(rhs.get())) } } /// Returns `true` if and only if `self == (1 << k)` for some `k`. @@ -967,9 +1149,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn abs(self) -> $Ty { + pub const fn abs(self) -> Self { // SAFETY: This cannot overflow to zero. - unsafe { $Ty::new_unchecked(self.get().abs()) } + unsafe { Self::new_unchecked(self.get().abs()) } } /// Checked absolute value. @@ -998,10 +1180,10 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_abs(self) -> Option<$Ty> { + pub const fn checked_abs(self) -> Option { if let Some(nz) = self.get().checked_abs() { // SAFETY: absolute value of nonzero cannot yield zero values. - Some(unsafe { $Ty::new_unchecked(nz) }) + Some(unsafe { Self::new_unchecked(nz) }) } else { None } @@ -1033,11 +1215,11 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn overflowing_abs(self) -> ($Ty, bool) { + pub const fn overflowing_abs(self) -> (Self, bool) { let (nz, flag) = self.get().overflowing_abs(); ( // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(nz) }, + unsafe { Self::new_unchecked(nz) }, flag, ) } @@ -1072,9 +1254,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn saturating_abs(self) -> $Ty { + pub const fn saturating_abs(self) -> Self { // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(self.get().saturating_abs()) } + unsafe { Self::new_unchecked(self.get().saturating_abs()) } } /// Wrapping absolute value, see @@ -1105,9 +1287,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn wrapping_abs(self) -> $Ty { + pub const fn wrapping_abs(self) -> Self { // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) } + unsafe { Self::new_unchecked(self.get().wrapping_abs()) } } /// Computes the absolute value of self @@ -1217,10 +1399,10 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[inline] #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn checked_neg(self) -> Option<$Ty> { + pub const fn checked_neg(self) -> Option { if let Some(result) = self.get().checked_neg() { // SAFETY: negation of nonzero cannot yield zero values. - return Some(unsafe { $Ty::new_unchecked(result) }); + return Some(unsafe { Self::new_unchecked(result) }); } None } @@ -1249,10 +1431,10 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[inline] #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn overflowing_neg(self) -> ($Ty, bool) { + pub const fn overflowing_neg(self) -> (Self, bool) { let (result, overflow) = self.get().overflowing_neg(); // SAFETY: negation of nonzero cannot yield zero values. - ((unsafe { $Ty::new_unchecked(result) }), overflow) + ((unsafe { Self::new_unchecked(result) }), overflow) } /// Saturating negation. Computes `-self`, @@ -1284,11 +1466,11 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[inline] #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn saturating_neg(self) -> $Ty { + pub const fn saturating_neg(self) -> Self { if let Some(result) = self.checked_neg() { return result; } - $Ty::MAX + Self::MAX } /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary @@ -1316,10 +1498,10 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[inline] #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn wrapping_neg(self) -> $Ty { + pub const fn wrapping_neg(self) -> Self { let result = self.get().wrapping_neg(); // SAFETY: negation of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(result) } + unsafe { Self::new_unchecked(result) } } }; } diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/overflow_panic.rs new file mode 100644 index 0000000000000..203037ffb43ea --- /dev/null +++ b/library/core/src/num/overflow_panic.rs @@ -0,0 +1,51 @@ +//! Functions for panicking on overflow. +//! +//! In particular, these are used by the `strict_` methods on integers. + +#[cold] +#[track_caller] +pub const fn add() -> ! { + panic!("attempt to add with overflow") +} + +#[cold] +#[track_caller] +pub const fn sub() -> ! { + panic!("attempt to subtract with overflow") +} + +#[cold] +#[track_caller] +pub const fn mul() -> ! { + panic!("attempt to multiply with overflow") +} + +#[cold] +#[track_caller] +pub const fn div() -> ! { + panic!("attempt to divide with overflow") +} + +#[cold] +#[track_caller] +pub const fn rem() -> ! { + panic!("attempt to calculate the remainder with overflow") +} + +#[cold] +#[track_caller] +pub const fn neg() -> ! { + panic!("attempt to negate with overflow") +} + +#[cold] +#[track_caller] +pub const fn shr() -> ! { + panic!("attempt to shift right with overflow") +} + +#[cold] +#[track_caller] +pub const fn shl() -> ! { + panic!("attempt to shift left with overflow") +} diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index bbbbd61c4b1c9..a217c2e259d2b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -459,9 +459,42 @@ macro_rules! uint_impl { #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } + /// Strict integer addition. Computes `self + rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_add(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) { overflow_panic ::add()} else {a} + } + /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. /// @@ -507,9 +540,47 @@ macro_rules! uint_impl { #[inline] pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } + /// Strict addition with a signed integer. Computes `self + rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_signed(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { + let (a, b) = self.overflowing_add_signed(rhs); + if unlikely!(b) { overflow_panic ::add()} else {a} + } + /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. /// @@ -528,9 +599,42 @@ macro_rules! uint_impl { #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } + /// Strict integer subtraction. Computes `self - rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_sub(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) { overflow_panic ::sub()} else {a} + } + /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. /// @@ -575,9 +679,42 @@ macro_rules! uint_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } + /// Strict integer multiplication. Computes `self * rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")] + /// ``` + /// + /// ``` should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_mul(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) { overflow_panic ::mul()} else {a} + } + /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. /// @@ -630,6 +767,34 @@ macro_rules! uint_impl { } } + /// Strict integer division. Computes `self / rhs`. + /// Strict division on unsigned types is just normal division. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + #[track_caller] + pub const fn strict_div(self, rhs: Self) -> Self { + self / rhs + } + /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` /// if `rhs == 0`. /// @@ -654,6 +819,36 @@ macro_rules! uint_impl { } } + /// Strict Euclidean division. Computes `self.div_euclid(rhs)`. + /// Strict division on unsigned types is just normal division. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// Since, for the positive integers, all common + /// definitions of division are equal, this + /// is exactly equal to `self.strict_div(rhs)`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + #[track_caller] + pub const fn strict_div_euclid(self, rhs: Self) -> Self { + self / rhs + } /// Checked integer remainder. Computes `self % rhs`, returning `None` /// if `rhs == 0`. @@ -681,6 +876,35 @@ macro_rules! uint_impl { } } + /// Strict integer remainder. Computes `self % rhs`. + /// Strict remainder calculation on unsigned types is + /// just the regular remainder calculation. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + #[track_caller] + pub const fn strict_rem(self, rhs: Self) -> Self { + self % rhs + } + /// Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` /// if `rhs == 0`. /// @@ -705,6 +929,38 @@ macro_rules! uint_impl { } } + /// Strict Euclidean modulo. Computes `self.rem_euclid(rhs)`. + /// Strict modulo calculation on unsigned types is + /// just the regular remainder calculation. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// Since, for the positive integers, all common + /// definitions of division are equal, this + /// is exactly equal to `self.strict_rem(rhs)`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + #[track_caller] + pub const fn strict_rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + /// Returns the logarithm of the number with respect to an arbitrary base, /// rounded down. /// @@ -893,7 +1149,42 @@ macro_rules! uint_impl { #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict negation. Computes `-self`, panicking unless `self == + /// 0`. + /// + /// Note that negating any positive integer will overflow. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] + /// + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_neg(self) -> Self { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` @@ -914,7 +1205,40 @@ macro_rules! uint_impl { #[inline] pub const fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger + /// than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_shl(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -962,7 +1286,40 @@ macro_rules! uint_impl { #[inline] pub const fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } + } + + /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// larger than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_shr(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that @@ -1031,6 +1388,55 @@ macro_rules! uint_impl { acc.checked_mul(base) } + /// Strict exponentiation. Computes `self.pow(exp)`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.strict_mul(base); + } + exp /= 2; + base = base.strict_mul(base); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.strict_mul(base) + } + /// Saturating integer addition. Computes `self + rhs`, saturating at /// the numeric bounds instead of overflowing. /// @@ -1125,6 +1531,10 @@ macro_rules! uint_impl { /// Saturating integer division. Computes `self / rhs`, saturating at the /// numeric bounds instead of overflowing. /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// /// # Examples /// /// Basic usage: @@ -1133,16 +1543,12 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")] /// /// ``` - /// - /// ```should_panic - #[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")] - /// - /// ``` #[stable(feature = "saturating_div", since = "1.58.0")] #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn saturating_div(self, rhs: Self) -> Self { // on unsigned types, there is no overflow in integer division self.wrapping_div(rhs) @@ -1277,6 +1683,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn wrapping_div(self, rhs: Self) -> Self { self / rhs } @@ -1306,6 +1713,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { self / rhs } @@ -1333,6 +1741,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn wrapping_rem(self, rhs: Self) -> Self { self % rhs } @@ -1363,6 +1772,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { self % rhs } @@ -1745,6 +2155,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_overflowing_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[track_caller] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } @@ -1775,6 +2186,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[track_caller] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } @@ -1802,6 +2214,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_overflowing_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[track_caller] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } @@ -1832,6 +2245,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[track_caller] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } @@ -2038,8 +2452,8 @@ macro_rules! uint_impl { // SAFETY: the result is positive and fits in an integer with half as many bits. // Inform the optimizer about it. unsafe { - intrinsics::assume(0 < res); - intrinsics::assume(res < 1 << (Self::BITS / 2)); + hint::assert_unchecked(0 < res); + hint::assert_unchecked(res < 1 << (Self::BITS / 2)); } res @@ -2067,7 +2481,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn div_euclid(self, rhs: Self) -> Self { self / rhs } @@ -2096,7 +2510,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn rem_euclid(self, rhs: Self) -> Self { self % rhs } @@ -2121,6 +2535,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn div_floor(self, rhs: Self) -> Self { self / rhs } @@ -2131,11 +2546,6 @@ macro_rules! uint_impl { /// /// This function will panic if `rhs` is zero. /// - /// ## Overflow behavior - /// - /// On overflow, this function will panic if overflow checks are enabled (default in debug - /// mode) and wrap if overflow checks are disabled (default in release mode). - /// /// # Examples /// /// Basic usage: @@ -2148,7 +2558,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] + #[track_caller] pub const fn div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs new file mode 100644 index 0000000000000..efbe9d164c3a7 --- /dev/null +++ b/library/core/src/ops/async_function.rs @@ -0,0 +1,133 @@ +use crate::future::Future; +use crate::marker::Tuple; + +/// An async-aware version of the [`Fn`](crate::ops::Fn) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn")] +pub trait AsyncFn: AsyncFnMut { + /// Future returned by [`AsyncFn::async_call`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFn`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>; +} + +/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_mut")] +pub trait AsyncFnMut: AsyncFnOnce { + /// Future returned by [`AsyncFnMut::async_call_mut`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallMutFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>; +} + +/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_once")] +pub trait AsyncFnOnce { + /// Future returned by [`AsyncFnOnce::async_call_once`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallOnceFuture: Future; + + /// Output type of the called closure's future. + #[unstable(feature = "async_fn_traits", issue = "none")] + type Output; + + /// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; +} + +mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::future::Future; + use crate::marker::Tuple; + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFn for F + where + >::Output: Future, + { + type CallFuture<'a> = >::Output where Self: 'a; + + extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { + self.call(args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnMut for F + where + >::Output: Future, + { + type CallMutFuture<'a> = >::Output where Self: 'a; + + extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { + self.call_mut(args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnOnce for F + where + >::Output: Future, + { + type CallOnceFuture = >::Output; + + type Output = <>::Output as Future>::Output; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + self.call_once(args) + } + } +} + +mod internal_implementation_detail { + /// A helper trait that is used to enforce that the `ClosureKind` of a goal + /// is within the capabilities of a `CoroutineClosure`, and which allows us + /// to delay the projection of the tupled upvar types until after upvar + /// analysis is complete. + /// + /// The `Self` type is expected to be the `kind_ty` of the coroutine-closure, + /// and thus either `?0` or `i8`/`i16`/`i32` (see docs for `ClosureKind` + /// for an explanation of that). The `GoalKind` is also the same type, but + /// representing the kind of the trait that the closure is being called with. + #[cfg_attr(not(bootstrap), lang = "async_fn_kind_helper")] + trait AsyncFnKindHelper { + // Projects a set of closure inputs (arguments), a region, and a set of upvars + // (by move and by ref) to the upvars that we expect the coroutine to have + // according to the `GoalKind` parameter above. + // + // The `Upvars` parameter should be the upvars of the parent coroutine-closure, + // and the `BorrowedUpvarsAsFnPtr` will be a function pointer that has the shape + // `for<'env> fn() -> (&'env T, ...)`. This allows us to represent the binder + // of the closure's self-capture, and these upvar types will be instantiated with + // the `'closure_env` region provided to the associated type. + type Upvars<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>; + } +} diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index e58c9068af85c..6faded76a4a49 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -111,6 +111,7 @@ pub trait Coroutine { /// been returned previously. While coroutine literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Coroutine` trait. + #[cfg_attr(not(bootstrap), lang = "coroutine_resume")] fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState; } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 35654d0b853b7..4289a86f89b06 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -139,6 +139,7 @@ #![stable(feature = "rust1", since = "1.0.0")] mod arith; +mod async_function; mod bit; mod control_flow; mod coroutine; @@ -173,6 +174,9 @@ pub use self::drop::Drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; +#[unstable(feature = "async_fn_traits", issue = "none")] +pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::index::{Index, IndexMut}; diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ce29352ba1952..c94e7d73a2ae6 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -642,7 +642,7 @@ impl Option { /// assert_eq!(x.is_none(), true); /// ``` #[must_use = "if you intended to assert that this doesn't have a value, consider \ - `.and_then(|_| panic!(\"`Option` had a value when expected `None`\"))` instead"] + wrapping this in an `assert!()` instead"] #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_option_basics", since = "1.48.0")] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index bb6c81a486a59..a0227d9130bb7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1092,14 +1092,20 @@ pub struct Pin { // - deter downstream users from accessing it (which would be unsound!), // - let the `pin!` macro access it (such a macro requires using struct // literal syntax in order to benefit from lifetime extension). - // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives. + // + // However, if the `Deref` impl exposes a field with the same name as this + // field, then the two will collide, resulting in a confusing error when the + // user attempts to access the field through a `Pin`. Therefore, the + // name `__pointer` is designed to be unlikely to collide with any other + // field. Long-term, macro hygiene is expected to offer a more robust + // alternative, alongside `unsafe` fields. #[unstable(feature = "unsafe_pin_internals", issue = "none")] #[doc(hidden)] - pub pointer: Ptr, + pub __pointer: Ptr, } // The following implementations aren't derived in order to avoid soundness -// issues. `&self.pointer` should not be accessible to untrusted trait +// issues. `&self.__pointer` should not be accessible to untrusted trait // implementations. // // See for more details. @@ -1212,7 +1218,7 @@ impl> Pin { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin) -> Ptr { - pin.pointer + pin.__pointer } } @@ -1349,7 +1355,7 @@ impl Pin { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin { - Pin { pointer } + Pin { __pointer: pointer } } /// Gets a shared reference to the pinned value this [`Pin`] points to. @@ -1363,7 +1369,7 @@ impl Pin { #[inline(always)] pub fn as_ref(&self) -> Pin<&Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&*self.pointer) } + unsafe { Pin::new_unchecked(&*self.__pointer) } } /// Unwraps this `Pin`, returning the underlying `Ptr`. @@ -1388,7 +1394,7 @@ impl Pin { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { - pin.pointer + pin.__pointer } } @@ -1426,7 +1432,7 @@ impl Pin { #[inline(always)] pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&mut *self.pointer) } + unsafe { Pin::new_unchecked(&mut *self.__pointer) } } /// Assigns a new value to the memory location pointed to by the `Pin`. @@ -1455,7 +1461,7 @@ impl Pin { where Ptr::Target: Sized, { - *(self.pointer) = value; + *(self.__pointer) = value; } } @@ -1481,7 +1487,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { U: ?Sized, F: FnOnce(&T) -> &U, { - let pointer = &*self.pointer; + let pointer = &*self.__pointer; let new_pointer = func(pointer); // SAFETY: the safety contract for `new_unchecked` must be @@ -1511,7 +1517,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn get_ref(self) -> &'a T { - self.pointer + self.__pointer } } @@ -1522,7 +1528,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn into_ref(self) -> Pin<&'a T> { - Pin { pointer: self.pointer } + Pin { __pointer: self.__pointer } } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1542,7 +1548,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { where T: Unpin, { - self.pointer + self.__pointer } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1560,7 +1566,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { - self.pointer + self.__pointer } /// Construct a new pin by mapping the interior value. @@ -1684,21 +1690,21 @@ impl Receiver for Pin {} #[stable(feature = "pin", since = "1.33.0")] impl fmt::Debug for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.pointer, f) + fmt::Debug::fmt(&self.__pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Display for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.pointer, f) + fmt::Display::fmt(&self.__pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Pointer for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.pointer, f) + fmt::Pointer::fmt(&self.__pointer, f) } } @@ -1941,16 +1947,16 @@ pub macro pin($value:expr $(,)?) { // instead, dropped _at the end of the enscoping block_. // For instance, // ```rust - // let p = Pin { pointer: &mut }; + // let p = Pin { __pointer: &mut }; // ``` // becomes: // ```rust // let mut anon = ; - // let p = Pin { pointer: &mut anon }; + // let p = Pin { __pointer: &mut anon }; // ``` // which is *exactly* what we want. // // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension // for more info. - $crate::pin::Pin::<&mut _> { pointer: &mut { $value } } + $crate::pin::Pin::<&mut _> { __pointer: &mut { $value } } } diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 7dee30585e9c3..bf47d767a9277 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1384,6 +1384,30 @@ mod prim_usize {} /// work on references as well as they do on owned values! The implementations described here are /// meant for generic contexts, where the final type `T` is a type parameter or otherwise not /// locally known. +/// +/// # Safety +/// +/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API +/// boundary, the following invariants must generally be upheld: +/// +/// * `t` is aligned to `align_of_val(t)` +/// * `t` is dereferenceable for `size_of_val(t)` many bytes +/// +/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range +/// `[a, a + N)` is all contained within a single [allocated object]. +/// +/// For instance, this means that unsafe code in a safe function may assume these invariants are +/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured +/// of return values from any safe functions it calls. In most cases, the inverse is also true: +/// unsafe code must not violate these invariants when passing arguments to safe functions or +/// returning values from safe functions; such violations may result in undefined behavior. Where +/// exceptions to this latter requirement exist, they will be called out explicitly in documentation. +/// +/// It is not decided yet whether unsafe code may violate these invariants temporarily on internal +/// data. As a consequence, unsafe code which violates these invariants temporarily on internal data +/// may become unsound in future versions of Rust depending on how this question is decided. +/// +/// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] mod prim_ref {} diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 12ff64de8790a..1d5d683fa16cc 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -220,7 +220,7 @@ impl *const T { /// provenance. (Reconstructing address space information, if required, is your responsibility.) /// /// Using this method means that code is *not* following [Strict - /// Provenance][../index.html#strict-provenance] rules. Supporting + /// Provenance][super#strict-provenance] rules. Supporting /// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by /// tools that help you to stay conformant with the Rust memory model, so it is recommended to /// use [`addr`][pointer::addr] wherever possible. @@ -232,7 +232,7 @@ impl *const T { /// available. /// /// It is unclear whether this method can be given a satisfying unambiguous specification. This - /// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance]. + /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance]. /// /// [`from_exposed_addr`]: from_exposed_addr #[must_use] @@ -285,7 +285,7 @@ impl *const T { self.with_addr(f(self.addr())) } - /// Decompose a (possibly wide) pointer into its address and metadata components. + /// Decompose a (possibly wide) pointer into its data pointer and metadata components. /// /// The pointer can be later reconstructed with [`from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] @@ -1284,7 +1284,7 @@ impl *const T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1304,7 +1304,7 @@ impl *const T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 040aa06978748..a6a390db043b6 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -39,13 +39,13 @@ use crate::hash::{Hash, Hasher}; /// /// # Usage /// -/// Raw pointers can be decomposed into the data address and metadata components +/// Raw pointers can be decomposed into the data pointer and metadata components /// with their [`to_raw_parts`] method. /// /// Alternatively, metadata alone can be extracted with the [`metadata`] function. /// A reference can be passed to [`metadata`] and implicitly coerced. /// -/// A (possibly-wide) pointer can be put back together from its address and metadata +/// A (possibly-wide) pointer can be put back together from its data pointer and metadata /// with [`from_raw_parts`] or [`from_raw_parts_mut`]. /// /// [`to_raw_parts`]: *const::to_raw_parts @@ -98,7 +98,7 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { unsafe { PtrRepr { const_ptr: ptr }.components.metadata } } -/// Forms a (possibly-wide) raw pointer from a data address and metadata. +/// Forms a (possibly-wide) raw pointer from a data pointer and metadata. /// /// This function is safe but the returned pointer is not necessarily safe to dereference. /// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements. @@ -109,13 +109,13 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts( - data_address: *const (), + data_pointer: *const (), metadata: ::Metadata, ) -> *const T { // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T // and PtrComponents have the same memory layouts. Only std can make this // guarantee. - unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } + unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.const_ptr } } /// Performs the same functionality as [`from_raw_parts`], except that a @@ -126,13 +126,13 @@ pub const fn from_raw_parts( #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts_mut( - data_address: *mut (), + data_pointer: *mut (), metadata: ::Metadata, ) -> *mut T { // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T // and PtrComponents have the same memory layouts. Only std can make this // guarantee. - unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr } + unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.mut_ptr } } #[repr(C)] @@ -144,7 +144,7 @@ union PtrRepr { #[repr(C)] struct PtrComponents { - data_address: *const (), + data_pointer: *const (), metadata: ::Metadata, } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index a9078854125c3..bc05b5b07def3 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -649,7 +649,7 @@ pub const fn invalid_mut(addr: usize) -> *mut T { /// address makes sense in the address space that this pointer will be used with. /// /// Using this function means that code is *not* following [Strict -/// Provenance][../index.html#strict-provenance] rules. "Guessing" a +/// Provenance][self#strict-provenance] rules. "Guessing" a /// suitable provenance complicates specification and reasoning and may not be supported by /// tools that help you to stay conformant with the Rust memory model, so it is recommended to /// use [`with_addr`][pointer::with_addr] wherever possible. @@ -660,7 +660,7 @@ pub const fn invalid_mut(addr: usize) -> *mut T { /// pointer has to pick up. /// /// It is unclear whether this function can be given a satisfying unambiguous specification. This -/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance]. +/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance]. #[must_use] #[inline(always)] #[unstable(feature = "exposed_provenance", issue = "95228")] @@ -689,7 +689,7 @@ where /// address makes sense in the address space that this pointer will be used with. /// /// Using this function means that code is *not* following [Strict -/// Provenance][../index.html#strict-provenance] rules. "Guessing" a +/// Provenance][self#strict-provenance] rules. "Guessing" a /// suitable provenance complicates specification and reasoning and may not be supported by /// tools that help you to stay conformant with the Rust memory model, so it is recommended to /// use [`with_addr`][pointer::with_addr] wherever possible. @@ -700,7 +700,7 @@ where /// pointer has to pick up. /// /// It is unclear whether this function can be given a satisfying unambiguous specification. This -/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance]. +/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance]. #[must_use] #[inline(always)] #[unstable(feature = "exposed_provenance", issue = "95228")] @@ -1176,7 +1176,6 @@ pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_read"] pub const unsafe fn read(src: *const T) -> T { @@ -1294,7 +1293,11 @@ pub const unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)] +#[rustc_allow_const_fn_unstable( + const_mut_refs, + const_maybe_uninit_as_mut_ptr, + const_intrinsic_copy +)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_read_unaligned"] pub const unsafe fn read_unaligned(src: *const T) -> T { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 4f5fca4367d08..376673d67c10b 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -227,7 +227,7 @@ impl *mut T { /// provenance. (Reconstructing address space information, if required, is your responsibility.) /// /// Using this method means that code is *not* following [Strict - /// Provenance][../index.html#strict-provenance] rules. Supporting + /// Provenance][super#strict-provenance] rules. Supporting /// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported /// by tools that help you to stay conformant with the Rust memory model, so it is recommended /// to use [`addr`][pointer::addr] wherever possible. @@ -239,7 +239,7 @@ impl *mut T { /// available. /// /// It is unclear whether this method can be given a satisfying unambiguous specification. This - /// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance]. + /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance]. /// /// [`from_exposed_addr_mut`]: from_exposed_addr_mut #[must_use] @@ -292,7 +292,7 @@ impl *mut T { self.with_addr(f(self.addr())) } - /// Decompose a (possibly wide) pointer into its address and metadata components. + /// Decompose a (possibly wide) pointer into its data pointer and metadata components. /// /// The pointer can be later reconstructed with [`from_raw_parts_mut`]. #[unstable(feature = "ptr_metadata", issue = "81513")] @@ -1385,7 +1385,7 @@ impl *mut T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1405,7 +1405,7 @@ impl *mut T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1425,7 +1425,7 @@ impl *mut T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1445,7 +1445,7 @@ impl *mut T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 427a9f3f49456..d18082c3048f1 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -259,16 +259,16 @@ impl NonNull { #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts( - data_address: NonNull<()>, + data_pointer: NonNull<()>, metadata: ::Metadata, ) -> NonNull { - // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_address` is. + // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is. unsafe { - NonNull::new_unchecked(super::from_raw_parts_mut(data_address.as_ptr(), metadata)) + NonNull::new_unchecked(super::from_raw_parts_mut(data_pointer.as_ptr(), metadata)) } } - /// Decompose a (possibly wide) pointer into its address and metadata components. + /// Decompose a (possibly wide) pointer into its data pointer and metadata components. /// /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index ce04a9f40898e..5c4f0bf9b2b49 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -5,6 +5,7 @@ use crate::fmt::{self, Write}; use crate::iter; use crate::mem; use crate::ops; +use core::ascii::EscapeDefault; #[cfg(not(test))] impl [u8] { @@ -253,7 +254,45 @@ impl<'a> iter::FusedIterator for EscapeAscii<'a> {} #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.clone().try_for_each(|b| f.write_char(b as char)) + // disassemble iterator, including front/back parts of flatmap in case it has been partially consumed + let (front, slice, back) = self.clone().inner.into_parts(); + let front = front.unwrap_or(EscapeDefault::empty()); + let mut bytes = slice.unwrap_or_default().as_slice(); + let back = back.unwrap_or(EscapeDefault::empty()); + + // usually empty, so the formatter won't have to do any work + for byte in front { + f.write_char(byte as char)?; + } + + fn needs_escape(b: u8) -> bool { + b > 0x7E || b < 0x20 || b == b'\\' || b == b'\'' || b == b'"' + } + + while bytes.len() > 0 { + // fast path for the printable, non-escaped subset of ascii + let prefix = bytes.iter().take_while(|&&b| !needs_escape(b)).count(); + // SAFETY: prefix length was derived by counting bytes in the same splice, so it's in-bounds + let (prefix, remainder) = unsafe { bytes.split_at_unchecked(prefix) }; + // SAFETY: prefix is a valid utf8 sequence, as it's a subset of ASCII + let prefix = unsafe { crate::str::from_utf8_unchecked(prefix) }; + + f.write_str(prefix)?; // the fast part + + bytes = remainder; + + if let Some(&b) = bytes.first() { + // guaranteed to be non-empty, better to write it as a str + f.write_str(ascii::escape_default(b).as_str())?; + bytes = &bytes[1..]; + } + } + + // also usually empty + for byte in back { + f.write_char(byte as char)?; + } + Ok(()) } } #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 8a8d634c0072a..e8b0010ba1574 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -8,15 +8,15 @@ use super::from_raw_parts; use super::memchr; #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B]> for [A] +impl PartialEq<[U]> for [T] where - A: PartialEq, + T: PartialEq, { - fn eq(&self, other: &[B]) -> bool { + fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) } - fn ne(&self, other: &[B]) -> bool { + fn ne(&self, other: &[U]) -> bool { SlicePartialEq::not_equal(self, other) } } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 373b4aee47a06..fb9be396eab80 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -234,7 +234,7 @@ unsafe impl SliceIndex<[T]> for usize { // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - crate::intrinsics::assume(self < slice.len()); + crate::hint::assert_unchecked(self < slice.len()); slice.as_ptr().add(self) } } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 4a64faf9b3f2a..2d4c7e78aea17 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -4,9 +4,8 @@ mod macros; use crate::cmp; -use crate::cmp::Ordering; use crate::fmt; -use crate::intrinsics::assume; +use crate::hint::assert_unchecked; use crate::iter::{ FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, UncheckedIterator, }; @@ -133,7 +132,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, as_ref, { fn is_sorted_by(self, mut compare: F) -> bool where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, + F: FnMut(&Self::Item, &Self::Item) -> bool, { self.as_slice().is_sorted_by(|a, b| compare(&a, &b)) } @@ -3249,26 +3248,26 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { /// An iterator over slice in (non-overlapping) chunks separated by a predicate. /// -/// This struct is created by the [`group_by`] method on [slices]. +/// This struct is created by the [`chunk_by`] method on [slices]. /// -/// [`group_by`]: slice::group_by +/// [`chunk_by`]: slice::chunk_by /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupBy<'a, T: 'a, P> { +pub struct ChunkBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkBy<'a, T, P> { pub(super) fn new(slice: &'a [T], predicate: P) -> Self { - GroupBy { slice, predicate } + ChunkBy { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3301,8 +3300,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3323,39 +3322,39 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupBy").field("slice", &self.slice).finish() + f.debug_struct("ChunkBy").field("slice", &self.slice).finish() } } /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. /// -/// This struct is created by the [`group_by_mut`] method on [slices]. +/// This struct is created by the [`chunk_by_mut`] method on [slices]. /// -/// [`group_by_mut`]: slice::group_by_mut +/// [`chunk_by_mut`]: slice::chunk_by_mut /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupByMut<'a, T: 'a, P> { +pub struct ChunkByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkByMut<'a, T, P> { pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self { - GroupByMut { slice, predicate } + ChunkByMut { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3389,8 +3388,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3412,12 +3411,12 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkByMut<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupByMut").field("slice", &self.slice).finish() + f.debug_struct("ChunkByMut").field("slice", &self.slice).finish() } } diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 95bcd123b824f..fc6af45fb9077 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -338,7 +338,7 @@ macro_rules! iterator { if predicate(x) { // SAFETY: we are guaranteed to be in bounds by the loop invariant: // when `i >= n`, `self.next()` returns `None` and the loop breaks. - unsafe { assume(i < n) }; + unsafe { assert_unchecked(i < n) }; return Some(i); } i += 1; @@ -361,7 +361,7 @@ macro_rules! iterator { if predicate(x) { // SAFETY: `i` must be lower than `n` since it starts at `n` // and is only decreasing. - unsafe { assume(i < n) }; + unsafe { assert_unchecked(i < n) }; return Some(i); } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5edc89e4cb53b..4ed22ede03ab5 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,6 +8,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::fmt; +use crate::hint; use crate::intrinsics::exact_div; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZeroUsize; @@ -67,8 +68,8 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "array_windows", issue = "75027")] pub use iter::ArrayWindows; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use iter::{GroupBy, GroupByMut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use iter::{ChunkBy, ChunkByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; @@ -296,7 +297,7 @@ impl [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns a mutable pointer to the last item in the slice. + /// Returns a mutable reference to the last item in the slice. /// /// # Examples /// @@ -316,13 +317,13 @@ impl [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns the first `N` elements of the slice, or `None` if it has fewer than `N` elements. + /// Return an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let u = [10, 40, 30]; /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); /// @@ -332,27 +333,26 @@ impl [T] { /// let w: &[i32] = &[]; /// assert_eq!(Some(&[]), w.first_chunk::<0>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn first_chunk(&self) -> Option<&[T; N]> { if self.len() < N { None } else { // SAFETY: We explicitly check for the correct number of elements, // and do not let the reference outlive the slice. - Some(unsafe { &*(self.as_ptr() as *const [T; N]) }) + Some(unsafe { &*(self.as_ptr().cast::<[T; N]>()) }) } } - /// Returns a mutable reference to the first `N` elements of the slice, - /// or `None` if it has fewer than `N` elements. + /// Return a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some(first) = x.first_chunk_mut::<2>() { @@ -360,10 +360,12 @@ impl [T] { /// first[1] = 4; /// } /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -371,28 +373,29 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(self.as_mut_ptr() as *mut [T; N]) }) + Some(unsafe { &mut *(self.as_mut_ptr().cast::<[T; N]>()) }) } } - /// Returns the first `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &[0, 1, 2]; /// /// if let Some((first, elements)) = x.split_first_chunk::<2>() { /// assert_eq!(first, &[0, 1]); /// assert_eq!(elements, &[2]); /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { if self.len() < N { None @@ -402,18 +405,18 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(first.as_ptr() as *const [T; N]) }, tail)) + Some((unsafe { &*(first.as_ptr().cast::<[T; N]>()) }, tail)) } } - /// Returns a mutable reference to the first `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { @@ -422,10 +425,12 @@ impl [T] { /// elements[0] = 5; /// } /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn split_first_chunk_mut( &mut self, ) -> Option<(&mut [T; N], &mut [T])> { @@ -438,29 +443,30 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(first.as_mut_ptr() as *mut [T; N]) }, tail)) + Some((unsafe { &mut *(first.as_mut_ptr().cast::<[T; N]>()) }, tail)) } } - /// Returns the last `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &[0, 1, 2]; /// - /// if let Some((last, elements)) = x.split_last_chunk::<2>() { - /// assert_eq!(last, &[1, 2]); + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] - pub const fn split_last_chunk(&self) -> Option<(&[T; N], &[T])> { + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { if self.len() < N { None } else { @@ -469,32 +475,35 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(last.as_ptr() as *const [T; N]) }, init)) + Some((init, unsafe { &*(last.as_ptr().cast::<[T; N]>()) })) } } - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// Return a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// - /// if let Some((last, elements)) = x.split_last_chunk_mut::<2>() { + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { /// last[0] = 3; /// last[1] = 4; /// elements[0] = 5; /// } /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn split_last_chunk_mut( &mut self, - ) -> Option<(&mut [T; N], &mut [T])> { + ) -> Option<(&mut [T], &mut [T; N])> { if self.len() < N { None } else { @@ -504,17 +513,17 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }, init)) + Some((init, unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) })) } } - /// Returns the last element of the slice, or `None` if it is empty. + /// Return an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let u = [10, 40, 30]; /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); /// @@ -524,9 +533,9 @@ impl [T] { /// let w: &[i32] = &[]; /// assert_eq!(Some(&[]), w.last_chunk::<0>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn last_chunk(&self) -> Option<&[T; N]> { if self.len() < N { None @@ -537,17 +546,17 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some(unsafe { &*(last.as_ptr() as *const [T; N]) }) + Some(unsafe { &*(last.as_ptr().cast::<[T; N]>()) }) } } - /// Returns a mutable pointer to the last item in the slice. + /// Return a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some(last) = x.last_chunk_mut::<2>() { @@ -555,10 +564,12 @@ impl [T] { /// last[1] = 20; /// } /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -570,7 +581,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }) + Some(unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) }) } } @@ -1737,18 +1748,16 @@ impl [T] { /// Returns an iterator over the slice producing non-overlapping runs /// of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by(|a, b| a == b); + /// let mut iter = slice.chunk_by(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1759,41 +1768,37 @@ impl [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by(|a, b| a <= b); + /// let mut iter = slice.chunk_by(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> + pub fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupBy::new(self, pred) + ChunkBy::new(self, pred) } /// Returns an iterator over the slice producing non-overlapping mutable /// runs of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by_mut(|a, b| a == b); + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); @@ -1804,24 +1809,22 @@ impl [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by_mut(|a, b| a <= b); + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> + pub fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupByMut::new(self, pred) + ChunkByMut::new(self, pred) } /// Divides one slice into two at an index. @@ -1832,7 +1835,8 @@ impl [T] { /// /// # Panics /// - /// Panics if `mid > len`. + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_checked`](slice::split_at_checked). /// /// # Examples /// @@ -1859,15 +1863,15 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] - #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)] + #[rustc_allow_const_fn_unstable(split_at_checked)] #[inline] #[track_caller] #[must_use] pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { - assert!(mid <= self.len()); - // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `split_at_unchecked`. - unsafe { self.split_at_unchecked(mid) } + match self.split_at_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } } /// Divides one mutable slice into two at an index. @@ -1878,7 +1882,8 @@ impl [T] { /// /// # Panics /// - /// Panics if `mid > len`. + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_mut_checked`](slice::split_at_mut_checked). /// /// # Examples /// @@ -1897,10 +1902,10 @@ impl [T] { #[must_use] #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - assert!(mid <= self.len()); - // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. - unsafe { self.split_at_mut_unchecked(mid) } + match self.split_at_mut_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } } /// Divides one slice into two at an index, without doing bounds checking. @@ -1946,7 +1951,10 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] - #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")] + #[rustc_const_stable( + feature = "const_slice_split_at_unchecked", + since = "CURRENT_RUSTC_VERSION" + )] #[inline] #[must_use] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { @@ -2019,162 +2027,96 @@ impl [T] { unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } - /// Divides one slice into an array and a remainder slice at an index. + /// Divides one slice into two at an index, returning `None` if the slice is + /// too short. /// - /// The array will contain all indices from `[0, N)` (excluding - /// the index `N` itself) and the slice will contain all - /// indices from `[N, len)` (excluding the index `len` itself). - /// - /// # Panics + /// If `mid ≤ len` returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). /// - /// Panics if `N > len`. + /// Otherwise, if `mid > len`, returns `None`. /// /// # Examples /// /// ``` - /// #![feature(split_array)] + /// #![feature(split_at_checked)] /// - /// let v = &[1, 2, 3, 4, 5, 6][..]; + /// let v = [1, -2, 3, -4, 5, -6]; /// /// { - /// let (left, right) = v.split_array_ref::<0>(); - /// assert_eq!(left, &[]); - /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// let (left, right) = v.split_at_checked(0).unwrap(); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, -2, 3, -4, 5, -6]); /// } /// /// { - /// let (left, right) = v.split_array_ref::<2>(); - /// assert_eq!(left, &[1, 2]); - /// assert_eq!(right, [3, 4, 5, 6]); + /// let (left, right) = v.split_at_checked(2).unwrap(); + /// assert_eq!(left, [1, -2]); + /// assert_eq!(right, [3, -4, 5, -6]); /// } /// /// { - /// let (left, right) = v.split_array_ref::<6>(); - /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]); + /// let (left, right) = v.split_at_checked(6).unwrap(); + /// assert_eq!(left, [1, -2, 3, -4, 5, -6]); /// assert_eq!(right, []); /// } - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[track_caller] - #[must_use] - pub fn split_array_ref(&self) -> (&[T; N], &[T]) { - let (a, b) = self.split_at(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (&*(a.as_ptr() as *const [T; N]), b) } - } - - /// Divides one mutable slice into an array and a remainder slice at an index. - /// - /// The array will contain all indices from `[0, N)` (excluding - /// the index `N` itself) and the slice will contain all - /// indices from `[N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples /// + /// assert_eq!(None, v.split_at_checked(7)); /// ``` - /// #![feature(split_array)] - /// - /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.split_array_mut::<2>(); - /// assert_eq!(left, &mut [1, 0]); - /// assert_eq!(right, [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] + #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")] + #[rustc_const_unstable(feature = "split_at_checked", issue = "119128")] #[inline] - #[track_caller] #[must_use] - pub fn split_array_mut(&mut self) -> (&mut [T; N], &mut [T]) { - let (a, b) = self.split_at_mut(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) } + pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_unchecked(mid) }) + } else { + None + } } - /// Divides one slice into an array and a remainder slice at an index from - /// the end. - /// - /// The slice will contain all indices from `[0, len - N)` (excluding - /// the index `len - N` itself) and the array will contain all - /// indices from `[len - N, len)` (excluding the index `len` itself). + /// Divides one mutable slice into two at an index, returning `None` if the + /// slice is too short. /// - /// # Panics + /// If `mid ≤ len` returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). /// - /// Panics if `N > len`. + /// Otherwise, if `mid > len`, returns `None`. /// /// # Examples /// /// ``` - /// #![feature(split_array)] - /// - /// let v = &[1, 2, 3, 4, 5, 6][..]; - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<0>(); - /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, &[]); - /// } + /// #![feature(split_at_checked)] /// - /// { - /// let (left, right) = v.rsplit_array_ref::<2>(); - /// assert_eq!(left, [1, 2, 3, 4]); - /// assert_eq!(right, &[5, 6]); - /// } + /// let mut v = [1, 0, 3, 0, 5, 6]; /// - /// { - /// let (left, right) = v.rsplit_array_ref::<6>(); - /// assert_eq!(left, []); - /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); + /// if let Some((left, right)) = v.split_at_mut_checked(2) { + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; /// } - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[must_use] - pub fn rsplit_array_ref(&self) -> (&[T], &[T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (a, &*(b.as_ptr() as *const [T; N])) } - } - - /// Divides one mutable slice into an array and a remainder slice at an - /// index from the end. - /// - /// The slice will contain all indices from `[0, len - N)` (excluding - /// the index `N` itself) and the array will contain all - /// indices from `[len - N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.rsplit_array_mut::<4>(); - /// assert_eq!(left, [1, 0]); - /// assert_eq!(right, &mut [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!(None, v.split_at_mut_checked(7)); /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] + #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")] + #[rustc_const_unstable(feature = "split_at_checked", issue = "119128")] #[inline] #[must_use] - pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at_mut(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) } + pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_mut_unchecked(mid) }) + } else { + None + } } /// Returns an iterator over subslices separated by elements that match @@ -2850,7 +2792,7 @@ impl [T] { right = if cmp == Greater { mid } else { right }; if cmp == Equal { // SAFETY: same as the `get_unchecked` above - unsafe { crate::intrinsics::assume(mid < self.len()) }; + unsafe { hint::assert_unchecked(mid < self.len()) }; return Ok(mid); } @@ -2859,7 +2801,7 @@ impl [T] { // SAFETY: directly true from the overall invariant. // Note that this is `<=`, unlike the assume in the `Ok` path. - unsafe { crate::intrinsics::assume(left <= self.len()) }; + unsafe { hint::assert_unchecked(left <= self.len()) }; Err(left) } @@ -3047,7 +2989,7 @@ impl [T] { sort::quicksort(self, |a, b| f(a).lt(&f(b))); } - /// Reorder the slice such that the element at `index` is at its final sorted position. + /// Reorder the slice such that the element at `index` after the reordering is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is @@ -3075,7 +3017,7 @@ impl [T] { /// # Examples /// /// ``` - /// let mut v = [-5i32, 4, 1, -3, 2]; + /// let mut v = [-5i32, 4, 2, -3, 1]; /// /// // Find the median /// v.select_nth_unstable(2); @@ -3096,8 +3038,8 @@ impl [T] { select::partition_at_index(self, index, T::lt) } - /// Reorder the slice with a comparator function such that the element at `index` is at its - /// final sorted position. + /// Reorder the slice with a comparator function such that the element at `index` after the reordering is at + /// its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the comparator function. @@ -3126,7 +3068,7 @@ impl [T] { /// # Examples /// /// ``` - /// let mut v = [-5i32, 4, 1, -3, 2]; + /// let mut v = [-5i32, 4, 2, -3, 1]; /// /// // Find the median as if the slice were sorted in descending order. /// v.select_nth_unstable_by(2, |a, b| b.cmp(a)); @@ -3151,8 +3093,8 @@ impl [T] { select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) } - /// Reorder the slice with a key extraction function such that the element at `index` is at its - /// final sorted position. + /// Reorder the slice with a key extraction function such that the element at `index` after the reordering is + /// at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the key extraction function. @@ -4103,23 +4045,36 @@ impl [T] { where T: PartialOrd, { - self.is_sorted_by(|a, b| a.partial_cmp(b)) + self.is_sorted_by(|a, b| a <= b) } /// Checks if the elements of this slice are sorted using the given comparator function. /// /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` - /// function to determine the ordering of two elements. Apart from that, it's equivalent to - /// [`is_sorted`]; see its documentation for more information. + /// function to determine whether two elements are to be considered in sorted order. /// - /// [`is_sorted`]: slice::is_sorted + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// + /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); + /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); + /// + /// assert!([0].is_sorted_by(|a, b| true)); + /// assert!([0].is_sorted_by(|a, b| false)); + /// + /// let empty: [i32; 0] = []; + /// assert!(empty.is_sorted_by(|a, b| false)); + /// assert!(empty.is_sorted_by(|a, b| true)); + /// ``` #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] #[must_use] pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool where - F: FnMut(&'a T, &'a T) -> Option, + F: FnMut(&'a T, &'a T) -> bool, { - self.array_windows().all(|[a, b]| compare(a, b).map_or(false, Ordering::is_le)) + self.array_windows().all(|[a, b]| compare(a, b)) } /// Checks if the elements of this slice are sorted using the given key extraction function. diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 0f23cf7ae239f..ba282f09d2067 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,6 +1,6 @@ //! Ways to create a `str` from bytes slice. -use crate::mem; +use crate::{mem, ptr}; use super::validations::run_utf8_validation; use super::Utf8Error; @@ -205,3 +205,41 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // comes from a reference which is guaranteed to be valid for writes. unsafe { &mut *(v as *mut [u8] as *mut str) } } + +/// Creates an `&str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8(slice::from_raw_parts(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts`](crate::slice::from_raw_parts). +/// See that function's documentation for safety concerns and examples. +/// +/// The mutable version of this function is [`from_raw_parts_mut`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")] +pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::from_raw_parts(ptr.cast(), len) } +} + +/// Creates an `&mut str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8_mut(slice::from_raw_parts_mut(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts_mut`](crate::slice::from_raw_parts_mut). +/// See that function's documentation for safety concerns and examples. +/// +/// The immutable version of this function is [`from_raw_parts`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")] +pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::from_raw_parts_mut(ptr.cast(), len) } +} diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index dd2efb0051672..4d6239e11a399 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1187,6 +1187,31 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Lines<'_> {} +impl<'a> Lines<'a> { + /// Returns the remaining lines of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_lines_remainder)] + /// + /// let mut lines = "a\nb\nc\nd".lines(); + /// assert_eq!(lines.remainder(), Some("a\nb\nc\nd")); + /// + /// lines.next(); + /// assert_eq!(lines.remainder(), Some("b\nc\nd")); + /// + /// lines.by_ref().for_each(drop); + /// assert_eq!(lines.remainder(), None); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "str_lines_remainder", issue = "77998")] + pub fn remainder(&self) -> Option<&'a str> { + self.0.iter.remainder() + } +} + /// Created with the method [`lines_any`]. /// /// [`lines_any`]: str::lines_any diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index a22c46edce254..ecc0613d7b9e5 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -33,6 +33,9 @@ pub use converts::{from_utf8, from_utf8_unchecked}; #[stable(feature = "str_mut_extras", since = "1.20.0")] pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use converts::{from_raw_parts, from_raw_parts_mut}; + #[stable(feature = "rust1", since = "1.0.0")] pub use error::{ParseBoolError, Utf8Error}; @@ -641,8 +644,9 @@ impl str { /// /// # Panics /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// past the end of the last code point of the string slice. + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is past + /// the end of the last code point of the string slice. For a non-panicking + /// alternative see [`split_at_checked`](str::split_at_checked). /// /// # Examples /// @@ -658,12 +662,9 @@ impl str { #[must_use] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at(&self, mid: usize) -> (&str, &str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - // SAFETY: just checked that `mid` is on a char boundary. - unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) } - } else { - slice_error_fail(self, 0, mid) + match self.split_at_checked(mid) { + None => slice_error_fail(self, 0, mid), + Some(pair) => pair, } } @@ -681,8 +682,9 @@ impl str { /// /// # Panics /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// past the end of the last code point of the string slice. + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is past + /// the end of the last code point of the string slice. For a non-panicking + /// alternative see [`split_at_mut_checked`](str::split_at_mut_checked). /// /// # Examples /// @@ -702,20 +704,114 @@ impl str { pub 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) { - let len = self.len(); - let ptr = self.as_mut_ptr(); // SAFETY: just checked that `mid` is on a char boundary. - unsafe { - ( - from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), - from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)), - ) - } + unsafe { self.split_at_mut_unchecked(mid) } } else { slice_error_fail(self, 0, mid) } } + /// Divide one string slice into two at an index. + /// + /// The argument, `mid`, should be a valid byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. The + /// method returns `None` if that’s not the case. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get mutable string slices instead, see the [`split_at_mut_checked`] + /// method. + /// + /// [`split_at_mut_checked`]: str::split_at_mut_checked + /// + /// # Examples + /// + /// ``` + /// #![feature(split_at_checked)] + /// + /// let s = "Per Martin-Löf"; + /// + /// let (first, last) = s.split_at_checked(3).unwrap(); + /// assert_eq!("Per", first); + /// assert_eq!(" Martin-Löf", last); + /// + /// assert_eq!(None, s.split_at_checked(13)); // Inside “ö” + /// assert_eq!(None, s.split_at_checked(16)); // Beyond the string length + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")] + pub 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) { + // SAFETY: just checked that `mid` is on a char boundary. + Some(unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }) + } else { + None + } + } + + /// Divide one mutable string slice into two at an index. + /// + /// The argument, `mid`, should be a valid byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. The + /// method returns `None` if that’s not the case. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get immutable string slices instead, see the [`split_at_checked`] method. + /// + /// [`split_at_checked`]: str::split_at_checked + /// + /// # Examples + /// + /// ``` + /// #![feature(split_at_checked)] + /// + /// let mut s = "Per Martin-Löf".to_string(); + /// if let Some((first, last)) = s.split_at_mut_checked(3) { + /// first.make_ascii_uppercase(); + /// assert_eq!("PER", first); + /// assert_eq!(" Martin-Löf", last); + /// } + /// assert_eq!("PER Martin-Löf", s); + /// + /// assert_eq!(None, s.split_at_mut_checked(13)); // Inside “ö” + /// assert_eq!(None, s.split_at_mut_checked(16)); // Beyond the string length + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")] + pub 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) { + // SAFETY: just checked that `mid` is on a char boundary. + Some(unsafe { self.split_at_mut_unchecked(mid) }) + } else { + None + } + } + + /// Divide one string slice into two at an index. + /// + /// # Safety + /// + /// The caller must ensure that `mid` is a valid byte offset from the start + /// of the string and falls on the boundary of a UTF-8 code point. + unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + // SAFETY: caller guarantees `mid` is on a char boundary. + unsafe { + ( + from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), + from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)), + ) + } + } + /// Returns an iterator over the [`char`]s of a string slice. /// /// As a string slice consists of valid UTF-8, we can iterate through a diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index 3f0080e3832e1..f1a789e32a7a7 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -8,7 +8,7 @@ pub use self::poll::Poll; mod wake; #[stable(feature = "futures_api", since = "1.36.0")] -pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; +pub use self::wake::{Context, ContextBuilder, LocalWaker, RawWaker, RawWakerVTable, Waker}; mod ready; #[stable(feature = "ready_macro", since = "1.64.0")] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 9c41b8b4f46a6..9ad71e394eacf 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -1,11 +1,13 @@ #![stable(feature = "futures_api", since = "1.36.0")] +use crate::mem::transmute; + use crate::fmt; use crate::marker::PhantomData; use crate::ptr; /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] -/// which provides customized wakeup behavior. +/// or a [`LocalWaker`] which provides customized wakeup behavior. /// /// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table /// @@ -33,9 +35,18 @@ impl RawWaker { /// The value of this pointer will get passed to all functions that are part /// of the `vtable` as the first parameter. /// + /// It is important to consider that the `data` pointer must point to a + /// thread safe type such as an `[Arc]` + /// when used to construct a [`Waker`]. This restriction is lifted when + /// constructing a [`LocalWaker`], which allows using types that do not implement + /// [Send] + [Sync] like `[Rc]`. + /// /// The `vtable` customizes the behavior of a `Waker` which gets created /// from a `RawWaker`. For each operation on the `Waker`, the associated /// function in the `vtable` of the underlying `RawWaker` will be called. + /// + /// [`Arc`]: std::sync::Arc + /// [`Rc`]: std::rc::Rc #[inline] #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] @@ -60,6 +71,21 @@ impl RawWaker { pub fn vtable(&self) -> &'static RawWakerVTable { self.vtable } + + #[unstable(feature = "noop_waker", issue = "98286")] + const NOOP: RawWaker = { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| RawWaker::NOOP, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + RawWaker::new(ptr::null(), &VTABLE) + }; } /// A virtual function pointer table (vtable) that specifies the behavior @@ -73,11 +99,19 @@ impl RawWaker { /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. /// -/// These functions must all be thread-safe (even though [`RawWaker`] is -/// \![Send] + \![Sync]) -/// because [`Waker`] is [Send] + [Sync], and thus wakers may be moved to -/// arbitrary threads or invoked by `&` reference. For example, this means that if the -/// `clone` and `drop` functions manage a reference count, they must do so atomically. +/// # Thread safety +/// If the [`RawWaker`] will be used to construct a [`Waker`] then +/// these functions must all be thread-safe (even though [`RawWaker`] is +/// \![Send] + \![Sync]). This is because [`Waker`] is [Send] + [Sync], +/// and it may be moved to arbitrary threads or invoked by `&` reference. For example, +/// this means that if the `clone` and `drop` functions manage a reference count, +/// they must do so atomically. +/// +/// However, if the [`RawWaker`] will be used to construct a [`LocalWaker`] instead, then +/// these functions don't need to be thread safe. This means that \![Send] + \![Sync] +/// data can be stored in the data pointer, and reference counting does not need any atomic +/// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot +/// be sent across threads. #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -117,16 +151,22 @@ impl RawWakerVTable { /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, /// `wake_by_ref`, and `drop` functions. /// - /// These functions must all be thread-safe (even though [`RawWaker`] is - /// \![Send] + \![Sync]) - /// because [`Waker`] is [Send] + [Sync], and thus wakers may be moved to - /// arbitrary threads or invoked by `&` reference. For example, this means that if the - /// `clone` and `drop` functions manage a reference count, they must do so atomically. - /// + /// If the [`RawWaker`] will be used to construct a [`Waker`] then + /// these functions must all be thread-safe (even though [`RawWaker`] is + /// \![Send] + \![Sync]). This is because [`Waker`] is [Send] + [Sync], + /// and it may be moved to arbitrary threads or invoked by `&` reference. For example, + /// this means that if the `clone` and `drop` functions manage a reference count, + /// they must do so atomically. + /// + /// However, if the [`RawWaker`] will be used to construct a [`LocalWaker`] instead, then + /// these functions don't need to be thread safe. This means that \![Send] + \![Sync] + /// data can be stored in the data pointer, and reference counting does not need any atomic + /// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot + /// be sent across threads. /// # `clone` /// /// This function will be called when the [`RawWaker`] gets cloned, e.g. when - /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned. + /// the [`Waker`]/[`LocalWaker`] in which the [`RawWaker`] is stored gets cloned. /// /// The implementation of this function must retain all resources that are /// required for this additional instance of a [`RawWaker`] and associated @@ -152,7 +192,7 @@ impl RawWakerVTable { /// /// # `drop` /// - /// This function gets called when a [`Waker`] gets dropped. + /// This function gets called when a [`Waker`]/[`LocalWaker`] gets dropped. /// /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and @@ -178,6 +218,7 @@ impl RawWakerVTable { #[lang = "Context"] pub struct Context<'a> { waker: &'a Waker, + local_waker: &'a LocalWaker, // Ensure we future-proof against variance changes by forcing // the lifetime to be invariant (argument-position lifetimes // are contravariant while return-position lifetimes are @@ -195,17 +236,24 @@ impl<'a> Context<'a> { #[must_use] #[inline] pub const fn from_waker(waker: &'a Waker) -> Self { - Context { waker, _marker: PhantomData, _marker2: PhantomData } + ContextBuilder::from_waker(waker).build() } /// Returns a reference to the [`Waker`] for the current task. + #[inline] + #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] - #[must_use] - #[inline] pub const fn waker(&self) -> &'a Waker { &self.waker } + /// Returns a reference to the [`LocalWaker`] for the current task. + #[inline] + #[unstable(feature = "local_waker", issue = "118959")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const fn local_waker(&self) -> &'a LocalWaker { + &self.local_waker + } } #[stable(feature = "futures_api", since = "1.36.0")] @@ -215,6 +263,72 @@ impl fmt::Debug for Context<'_> { } } +/// A Builder used to construct a `Context` instance +/// with support for `LocalWaker`. +/// +/// # Examples +/// ``` +/// #![feature(local_waker)] +/// #![feature(noop_waker)] +/// use std::task::{ContextBuilder, LocalWaker, Waker, Poll}; +/// use std::future::Future; +/// +/// let local_waker = LocalWaker::noop(); +/// let waker = Waker::noop(); +/// +/// let mut cx = ContextBuilder::from_waker(&waker) +/// .local_waker(&local_waker) +/// .build(); +/// +/// let mut future = std::pin::pin!(async { 20 }); +/// let poll = future.as_mut().poll(&mut cx); +/// assert_eq!(poll, Poll::Ready(20)); +/// +/// ``` +#[unstable(feature = "local_waker", issue = "118959")] +#[derive(Debug)] +pub struct ContextBuilder<'a> { + waker: &'a Waker, + local_waker: &'a LocalWaker, + // Ensure we future-proof against variance changes by forcing + // the lifetime to be invariant (argument-position lifetimes + // are contravariant while return-position lifetimes are + // covariant). + _marker: PhantomData &'a ()>, + // Ensure `Context` is `!Send` and `!Sync` in order to allow + // for future `!Send` and / or `!Sync` fields. + _marker2: PhantomData<*mut ()>, +} + +impl<'a> ContextBuilder<'a> { + /// Create a ContextBuilder from a Waker. + #[inline] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[unstable(feature = "local_waker", issue = "118959")] + pub const fn from_waker(waker: &'a Waker) -> Self { + // SAFETY: LocalWaker is just Waker without thread safety + let local_waker = unsafe { transmute(waker) }; + Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData } + } + + /// This method is used to set the value for the local waker on `Context`. + #[inline] + #[unstable(feature = "local_waker", issue = "118959")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self { + Self { local_waker, ..self } + } + + /// Builds the `Context`. + #[inline] + #[unstable(feature = "local_waker", issue = "118959")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const fn build(self) -> Context<'a> { + let ContextBuilder { waker, local_waker, _marker, _marker2 } = self; + Context { waker, local_waker, _marker, _marker2 } + } +} + /// A `Waker` is a handle for waking up a task by notifying its executor that it /// is ready to be run. /// @@ -329,12 +443,14 @@ impl Waker { Waker { waker } } - /// Creates a new `Waker` that does nothing when `wake` is called. + /// Returns a reference to a `Waker` that does nothing when used. /// /// This is mostly useful for writing tests that need a [`Context`] to poll /// some futures, but are not expecting those futures to wake the waker or /// do not need to do anything specific if it happens. /// + /// If an owned `Waker` is needed, `clone()` this one. + /// /// # Examples /// /// ``` @@ -343,8 +459,7 @@ impl Waker { /// use std::future::Future; /// use std::task; /// - /// let waker = task::Waker::noop(); - /// let mut cx = task::Context::from_waker(&waker); + /// let mut cx = task::Context::from_waker(task::Waker::noop()); /// /// let mut future = Box::pin(async { 10 }); /// assert_eq!(future.as_mut().poll(&mut cx), task::Poll::Ready(10)); @@ -352,20 +467,9 @@ impl Waker { #[inline] #[must_use] #[unstable(feature = "noop_waker", issue = "98286")] - pub const fn noop() -> Waker { - const VTABLE: RawWakerVTable = RawWakerVTable::new( - // Cloning just returns a new no-op raw waker - |_| RAW, - // `wake` does nothing - |_| {}, - // `wake_by_ref` does nothing - |_| {}, - // Dropping does nothing as we don't allocate anything - |_| {}, - ); - const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); - - Waker { waker: RAW } + pub const fn noop() -> &'static Waker { + const WAKER: &Waker = &Waker { waker: RawWaker::NOOP }; + WAKER } /// Get a reference to the underlying [`RawWaker`]. @@ -418,3 +522,222 @@ impl fmt::Debug for Waker { .finish() } } + +/// A `LocalWaker` is analogous to a [`Waker`], but it does not implement [`Send`] or [`Sync`]. +/// +/// This handle encapsulates a [`RawWaker`] instance, which defines the +/// executor-specific wakeup behavior. +/// +/// Local wakers can be requested from a `Context` with the [`local_waker`] method. +/// +/// The typical life of a `LocalWaker` is that it is constructed by an executor, wrapped in a +/// [`Context`] using [`ContextBuilder`], then passed to [`Future::poll()`]. Then, if the future chooses to return +/// [`Poll::Pending`], it must also store the waker somehow and call [`LocalWaker::wake()`] when +/// the future should be polled again. +/// +/// Implements [`Clone`], but neither [`Send`] nor [`Sync`]; therefore, a local waker may +/// not be moved to other threads. In general, when deciding to use wakers or local wakers, +/// local wakers are preferable unless the waker needs to be sent across threads. This is because +/// wakers can incur in additional cost related to memory synchronization. +/// +/// Note that it is preferable to use `local_waker.clone_from(&new_waker)` instead +/// of `*local_waker = new_waker.clone()`, as the former will avoid cloning the waker +/// unnecessarily if the two wakers [wake the same task](Self::will_wake). +/// +/// # Examples +/// Usage of a local waker to implement a future analogous to `std::thread::yield_now()`. +/// ``` +/// #![feature(local_waker)] +/// use std::future::{Future, poll_fn}; +/// use std::task::Poll; +/// +/// // a future that returns pending once. +/// fn yield_now() -> impl Future + Unpin { +/// let mut yielded = false; +/// poll_fn(move |cx| { +/// if !yielded { +/// yielded = true; +/// cx.local_waker().wake_by_ref(); +/// return Poll::Pending; +/// } +/// return Poll::Ready(()) +/// }) +/// } +/// +/// # async fn __() { +/// yield_now().await; +/// # } +/// ``` +/// +/// [`Future::poll()`]: core::future::Future::poll +/// [`Poll::Pending`]: core::task::Poll::Pending +/// [`local_waker`]: core::task::Context::local_waker +#[unstable(feature = "local_waker", issue = "118959")] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401 +pub struct LocalWaker { + waker: RawWaker, +} + +#[unstable(feature = "local_waker", issue = "118959")] +impl Unpin for LocalWaker {} + +impl LocalWaker { + /// Wake up the task associated with this `LocalWaker`. + /// + /// As long as the executor keeps running and the task is not finished, it is + /// guaranteed that each invocation of [`wake()`](Self::wake) (or + /// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one + /// [`poll()`] of the task to which this `LocalWaker` belongs. This makes + /// it possible to temporarily yield to other tasks while running potentially + /// unbounded processing loops. + /// + /// Note that the above implies that multiple wake-ups may be coalesced into a + /// single [`poll()`] invocation by the runtime. + /// + /// Also note that yielding to competing tasks is not guaranteed: it is the + /// executor’s choice which task to run and the executor may choose to run the + /// current task again. + /// + /// [`poll()`]: crate::future::Future::poll + #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] + pub fn wake(self) { + // The actual wakeup call is delegated through a virtual function call + // to the implementation which is defined by the executor. + let wake = self.waker.vtable.wake; + let data = self.waker.data; + + // Don't call `drop` -- the waker will be consumed by `wake`. + crate::mem::forget(self); + + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + unsafe { (wake)(data) }; + } + + /// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`. + /// + /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in + /// the case where an owned `Waker` is available. This method should be preferred to + /// calling `waker.clone().wake()`. + #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] + pub fn wake_by_ref(&self) { + // The actual wakeup call is delegated through a virtual function call + // to the implementation which is defined by the executor. + + // SAFETY: see `wake` + unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) } + } + + /// Returns `true` if this `LocalWaker` and another `LocalWaker` would awake the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task. + /// + /// This function is primarily used for optimization purposes — for example, + /// this type's [`clone_from`](Self::clone_from) implementation uses it to + /// avoid cloning the waker when they would wake the same task anyway. + #[inline] + #[must_use] + #[stable(feature = "futures_api", since = "1.36.0")] + pub fn will_wake(&self, other: &LocalWaker) -> bool { + self.waker == other.waker + } + + /// Creates a new `LocalWaker` from [`RawWaker`]. + /// + /// The behavior of the returned `LocalWaker` is undefined if the contract defined + /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. + /// Therefore this method is unsafe. + #[inline] + #[must_use] + #[stable(feature = "futures_api", since = "1.36.0")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker { + Self { waker } + } + + /// Creates a new `LocalWaker` that does nothing when `wake` is called. + /// + /// This is mostly useful for writing tests that need a [`Context`] to poll + /// some futures, but are not expecting those futures to wake the waker or + /// do not need to do anything specific if it happens. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_waker)] + /// #![feature(noop_waker)] + /// + /// use std::future::Future; + /// use std::task::{ContextBuilder, LocalWaker, Waker, Poll}; + /// + /// let mut cx = ContextBuilder::from_waker(Waker::noop()) + /// .local_waker(LocalWaker::noop()) + /// .build(); + /// + /// let mut future = Box::pin(async { 10 }); + /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Ready(10)); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "noop_waker", issue = "98286")] + pub const fn noop() -> &'static LocalWaker { + const WAKER: &LocalWaker = &LocalWaker { waker: RawWaker::NOOP }; + WAKER + } + + /// Get a reference to the underlying [`RawWaker`]. + #[inline] + #[must_use] + #[unstable(feature = "waker_getters", issue = "96992")] + pub fn as_raw(&self) -> &RawWaker { + &self.waker + } +} +#[unstable(feature = "local_waker", issue = "118959")] +impl Clone for LocalWaker { + #[inline] + fn clone(&self) -> Self { + LocalWaker { + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `clone` and `data` requiring the user to acknowledge + // that the contract of [`RawWaker`] is upheld. + waker: unsafe { (self.waker.vtable.clone)(self.waker.data) }, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + if !self.will_wake(source) { + *self = source.clone(); + } + } +} + +#[unstable(feature = "local_waker", issue = "118959")] +impl AsRef for Waker { + fn as_ref(&self) -> &LocalWaker { + // SAFETY: LocalWaker is just Waker without thread safety + unsafe { transmute(self) } + } +} + +#[stable(feature = "futures_api", since = "1.36.0")] +impl fmt::Debug for LocalWaker { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let vtable_ptr = self.waker.vtable as *const RawWakerVTable; + f.debug_struct("LocalWaker") + .field("data", &self.waker.data) + .field("vtable", &vtable_ptr) + .finish() + } +} + +#[unstable(feature = "local_waker", issue = "118959")] +impl !Send for LocalWaker {} +#[unstable(feature = "local_waker", issue = "118959")] +impl !Sync for LocalWaker {} diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index e1b77e34f211d..47e27bdc73533 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -2,7 +2,7 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::ConstParamTy; -use crate::marker::{StructuralEq, StructuralPartialEq}; +use crate::marker::StructuralPartialEq; // Recursive macro for implementing n-ary tuple functions and operations // @@ -64,7 +64,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[unstable(feature = "structural_match", issue = "31434")] - impl<$($T),+> StructuralEq for ($($T,)+) + #[cfg(bootstrap)] + impl<$($T),+> crate::marker::StructuralEq for ($($T,)+) {} } diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index f5f2dd0477885..3d3f8ac10c603 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -479,3 +479,13 @@ fn ascii_ctype_const() { is_ascii_control => [false, false, false, false, false]; } } + +#[test] +fn test_ascii_display() { + assert_eq!(b"foo'bar".escape_ascii().to_string(), r#"foo\'bar"#); + assert_eq!(b"\0\xff".escape_ascii().to_string(), r#"\x00\xff"#); + let mut it = b"\0fastpath\xffremainder\xff".escape_ascii(); + let _ = it.advance_by(4); + let _ = it.advance_back_by(4); + assert_eq!(it.to_string(), r#"fastpath\xffremainder"#); +} diff --git a/library/core/tests/async_iter/mod.rs b/library/core/tests/async_iter/mod.rs index 0c30bd1dfeac9..4f425d7286d09 100644 --- a/library/core/tests/async_iter/mod.rs +++ b/library/core/tests/async_iter/mod.rs @@ -7,8 +7,7 @@ fn into_async_iter() { let async_iter = async_iter::from_iter(0..3); let mut async_iter = pin!(async_iter.into_async_iter()); - let waker = core::task::Waker::noop(); - let mut cx = &mut core::task::Context::from_waker(&waker); + let mut cx = &mut core::task::Context::from_waker(core::task::Waker::noop()); assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(0))); assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(1))); diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs index 70c9906163ae8..b4d61d28cb2e0 100644 --- a/library/core/tests/iter/adapters/step_by.rs +++ b/library/core/tests/iter/adapters/step_by.rs @@ -220,7 +220,8 @@ fn test_iterator_step_by_size_hint() { assert_eq!(it.len(), 3); // Cannot be TrustedLen as a step greater than one makes an iterator - // with (usize::MAX, None) no longer meet the safety requirements + // with (usize::MAX, None) no longer meet the safety requirements. + // Exception: The inner iterator is known to have a len() <= usize::MAX trait TrustedLenCheck { fn test(self) -> bool; } @@ -235,7 +236,9 @@ fn test_iterator_step_by_size_hint() { } } assert!(TrustedLenCheck::test(a.iter())); - assert!(!TrustedLenCheck::test(a.iter().step_by(1))); + assert!(TrustedLenCheck::test(a.iter().step_by(1))); + assert!(TrustedLenCheck::test(a.iter().chain(a.iter()))); + assert!(!TrustedLenCheck::test(a.iter().chain(a.iter()).step_by(1))); } #[test] diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 5b87d6c1fa0e3..a6b9f1cb7c889 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -474,6 +474,16 @@ fn test_range_inclusive_size_hint() { assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None)); } +#[test] +fn test_range_trusted_random_access() { + let mut range = 0..10; + unsafe { + assert_eq!(range.next(), Some(0)); + assert_eq!(range.__iterator_get_unchecked(0), 1); + assert_eq!(range.__iterator_get_unchecked(1), 2); + } +} + #[test] fn test_double_ended_range() { assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index 9c1dce7b66dff..4c2d843eaa0dc 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -1,4 +1,3 @@ -use core::cmp::Ordering; use core::num::NonZeroUsize; /// A wrapper struct that implements `Eq` and `Ord` based on the wrapped @@ -408,7 +407,7 @@ fn test_is_sorted() { // Tests for is_sorted_by assert!(![6, 2, 8, 5, 1, -60, 1337].iter().is_sorted()); - assert!([6, 2, 8, 5, 1, -60, 1337].iter().is_sorted_by(|_, _| Some(Ordering::Less))); + assert!([6, 2, 8, 5, 1, -60, 1337].iter().is_sorted_by(|_, _| true)); // Tests for is_sorted_by_key assert!([-2, -1, 0, 3].iter().is_sorted()); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8604d41eb6860..15298e1c81622 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,6 +1,5 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] @@ -15,6 +14,7 @@ #![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] +#![feature(const_intrinsic_copy)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_nonnull_new)] #![feature(const_pointer_is_aligned)] @@ -59,6 +59,7 @@ #![feature(noop_waker)] #![feature(numfmt)] #![feature(num_midpoint)] +#![cfg_attr(not(bootstrap), feature(offset_of_nested))] #![feature(isqrt)] #![feature(step_trait)] #![feature(str_internals)] @@ -100,7 +101,6 @@ #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] -#![feature(slice_group_by)] #![feature(split_array)] #![feature(strict_provenance)] #![feature(strict_provenance_atomic_ptr)] @@ -112,10 +112,10 @@ #![feature(slice_flatten)] #![feature(error_generic_member_access)] #![feature(error_in_core)] +#![cfg_attr(not(bootstrap), feature(trait_upcasting))] #![feature(utf8_chunks)] #![feature(is_ascii_octdigit)] #![feature(get_many_mut)] -#![feature(offset_of)] #![feature(iter_map_windows)] #![allow(internal_features)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index eb886def164ac..09994fbcbdb78 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -1,3 +1,4 @@ +#[allow(dead_code)] trait Trait { fn blah(&self); } diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index 3d13bffba92af..f9b351ef1980b 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -516,6 +516,7 @@ fn ipv6_properties() { | multicast_realm_local | multicast_site_local | multicast_organization_local; + let ipv4_mapped: u32 = 1 << 17; if ($mask & unspecified) == unspecified { assert!(ip!($s).is_unspecified()); @@ -592,6 +593,11 @@ fn ipv6_properties() { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::Global); } + if ($mask & ipv4_mapped) == ipv4_mapped { + assert!(ip!($s).is_ipv4_mapped()); + } else { + assert!(!ip!($s).is_ipv4_mapped()); + } } } @@ -610,6 +616,7 @@ fn ipv6_properties() { let multicast_site_local: u32 = 1 << 13; let multicast_organization_local: u32 = 1 << 14; let multicast_global: u32 = 1 << 15; + let ipv4_mapped: u32 = 1 << 17; check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); @@ -622,7 +629,7 @@ fn ipv6_properties() { check!( "::ffff:127.0.0.1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], - unicast_global + unicast_global | ipv4_mapped ); check!( @@ -996,6 +1003,9 @@ fn ipv6_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); + const IS_IPV4_MAPPED: bool = IP_ADDRESS.is_ipv4_mapped(); + assert!(!IS_IPV4_MAPPED); + const IP_V4: Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); } diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index cc1fc7e4d7ea1..bcf7b5e59775a 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2307,7 +2307,7 @@ fn test_is_sorted() { // Tests for is_sorted_by assert!(![6, 2, 8, 5, 1, -60, 1337].is_sorted()); - assert!([6, 2, 8, 5, 1, -60, 1337].is_sorted_by(|_, _| Some(Ordering::Less))); + assert!([6, 2, 8, 5, 1, -60, 1337].is_sorted_by(|_, _| true)); // Tests for is_sorted_by_key assert!([-2, -1, 0, 3].is_sorted()); @@ -2398,37 +2398,45 @@ mod swap_panics { } #[test] -fn slice_split_array_mut() { +fn slice_split_first_chunk_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.split_array_mut::<0>(); + let (left, right) = v.split_first_chunk_mut::<0>().unwrap(); assert_eq!(left, &mut []); assert_eq!(right, [1, 2, 3, 4, 5, 6]); } { - let (left, right) = v.split_array_mut::<6>(); + let (left, right) = v.split_first_chunk_mut::<6>().unwrap(); assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); assert_eq!(right, []); } + + { + assert!(v.split_first_chunk_mut::<7>().is_none()); + } } #[test] -fn slice_rsplit_array_mut() { +fn slice_split_last_chunk_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.rsplit_array_mut::<0>(); + let (left, right) = v.split_last_chunk_mut::<0>().unwrap(); assert_eq!(left, [1, 2, 3, 4, 5, 6]); assert_eq!(right, &mut []); } { - let (left, right) = v.rsplit_array_mut::<6>(); + let (left, right) = v.split_last_chunk_mut::<6>().unwrap(); assert_eq!(left, []); assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); } + + { + assert!(v.split_last_chunk_mut::<7>().is_none()); + } } #[test] @@ -2443,38 +2451,6 @@ fn split_as_slice() { assert_eq!(split.as_slice(), &[]); } -#[should_panic] -#[test] -fn slice_split_array_ref_out_of_bounds() { - let v = &[1, 2, 3, 4, 5, 6][..]; - - let _ = v.split_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn slice_split_array_mut_out_of_bounds() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - let _ = v.split_array_mut::<7>(); -} - -#[should_panic] -#[test] -fn slice_rsplit_array_ref_out_of_bounds() { - let v = &[1, 2, 3, 4, 5, 6][..]; - - let _ = v.rsplit_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn slice_rsplit_array_mut_out_of_bounds() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - let _ = v.rsplit_array_mut::<7>(); -} - #[test] fn slice_split_once() { let v = &[1, 2, 3, 2, 4][..]; diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 8fd64279ac5a7..c44f23eea8094 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -19,6 +19,9 @@ #[cfg(target_os = "android")] mod android; +#[cfg(target_os = "zkvm")] +mod zkvm; + use core::any::Any; use core::panic::PanicPayload; @@ -34,6 +37,8 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { // Android has the ability to attach a message as part of the abort. #[cfg(target_os = "android")] android::android_set_abort_message(_payload); + #[cfg(target_os = "zkvm")] + zkvm::zkvm_set_abort_message(_payload); abort(); diff --git a/library/panic_abort/src/zkvm.rs b/library/panic_abort/src/zkvm.rs new file mode 100644 index 0000000000000..a6a02abf10976 --- /dev/null +++ b/library/panic_abort/src/zkvm.rs @@ -0,0 +1,24 @@ +use alloc::string::String; +use core::panic::PanicPayload; + +// Forward the abort message to zkVM's sys_panic. This is implemented by RISC Zero's +// platform crate which exposes system calls specifically for the zkVM. +pub(crate) unsafe fn zkvm_set_abort_message(payload: &mut dyn PanicPayload) { + let payload = payload.get(); + let msg = match payload.downcast_ref::<&'static str>() { + Some(msg) => msg.as_bytes(), + None => match payload.downcast_ref::() { + Some(msg) => msg.as_bytes(), + None => &[], + }, + }; + if msg.is_empty() { + return; + } + + extern "C" { + fn sys_panic(msg_ptr: *const u8, len: usize) -> !; + } + + sys_panic(msg.as_ptr(), msg.len()); +} diff --git a/library/portable-simd/crates/core_simd/src/vendor/arm.rs b/library/portable-simd/crates/core_simd/src/vendor/arm.rs index ff3b69ccf9592..ee5c642137367 100644 --- a/library/portable-simd/crates/core_simd/src/vendor/arm.rs +++ b/library/portable-simd/crates/core_simd/src/vendor/arm.rs @@ -7,9 +7,12 @@ use core::arch::arm::*; #[cfg(target_arch = "aarch64")] use core::arch::aarch64::*; -#[cfg(any( - target_arch = "aarch64", - all(target_arch = "arm", target_feature = "v7"), +#[cfg(all( + any( + target_arch = "aarch64", + all(target_arch = "arm", target_feature = "v7"), + ), + target_endian = "little" ))] mod neon { use super::*; diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 52a08cad9110f..9255c3abc8a02 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -3,6 +3,7 @@ use super::*; use std::marker::PhantomData; +use std::sync::atomic::AtomicU32; macro_rules! define_handles { ( @@ -12,8 +13,8 @@ macro_rules! define_handles { #[repr(C)] #[allow(non_snake_case)] pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* + $($oty: AtomicU32,)* + $($ity: AtomicU32,)* } impl HandleCounters { @@ -21,8 +22,8 @@ macro_rules! define_handles { // a wrapper `fn` pointer, once `const fn` can reference `static`s. extern "C" fn get() -> &'static Self { static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* + $($oty: AtomicU32::new(1),)* + $($ity: AtomicU32::new(1),)* }; &COUNTERS } diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs index 00954107b7769..b3a763069974f 100644 --- a/library/proc_macro/src/bridge/handle.rs +++ b/library/proc_macro/src/bridge/handle.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use std::hash::Hash; use std::num::NonZeroU32; use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; use super::fxhash::FxHashMap; @@ -13,12 +13,12 @@ pub(super) type Handle = NonZeroU32; /// A store that associates values of type `T` with numeric handles. A value can /// be looked up using its handle. pub(super) struct OwnedStore { - counter: &'static AtomicUsize, + counter: &'static AtomicU32, data: BTreeMap, } impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { + pub(super) fn new(counter: &'static AtomicU32) -> Self { // Ensure the handle counter isn't 0, which would panic later, // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. assert_ne!(counter.load(Ordering::SeqCst), 0); @@ -30,7 +30,7 @@ impl OwnedStore { impl OwnedStore { pub(super) fn alloc(&mut self, x: T) -> Handle { let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); + let handle = Handle::new(counter).expect("`proc_macro` handle counter overflowed"); assert!(self.data.insert(handle, x).is_none()); handle } @@ -60,7 +60,7 @@ pub(super) struct InternedStore { } impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { + pub(super) fn new(counter: &'static AtomicU32) -> Self { InternedStore { owned: OwnedStore::new(counter), interner: FxHashMap::default() } } diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 75bf3329786a4..55e24b6491c79 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -16,7 +16,6 @@ use std::mem; use std::ops::Bound; use std::ops::Range; use std::panic; -use std::sync::atomic::AtomicUsize; use std::sync::Once; use std::thread; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ca83e2be5c147..87e89a464bc1a 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -191,6 +191,14 @@ impl ToString for TokenStream { /// Prints the token stream as a string that is supposed to be losslessly convertible back /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. +/// +/// Note: the exact form of the output is subject to change, e.g. there might +/// be changes in the whitespace used between tokens. Therefore, you should +/// *not* do any kind of simple substring matching on the output string (as +/// produced by `to_string`) to implement a proc macro, because that matching +/// might stop working if such changes happen. Instead, you should work at the +/// `TokenTree` level, e.g. matching against `TokenTree::Ident`, +/// `TokenTree::Punct`, or `TokenTree::Literal`. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -758,6 +766,14 @@ impl ToString for TokenTree { /// Prints the token tree as a string that is supposed to be losslessly convertible back /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. +/// +/// Note: the exact form of the output is subject to change, e.g. there might +/// be changes in the whitespace used between tokens. Therefore, you should +/// *not* do any kind of simple substring matching on the output string (as +/// produced by `to_string`) to implement a proc macro, because that matching +/// might stop working if such changes happen. Instead, you should work at the +/// `TokenTree` level, e.g. matching against `TokenTree::Ident`, +/// `TokenTree::Punct`, or `TokenTree::Literal`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for TokenTree { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 5b32bc5117c0c..20f4310603a05 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,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 } -libc = { version = "0.2.150", default-features = false, features = ['rustc-dep-of-std'], public = true } +libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true } compiler_builtins = { version = "0.1.105" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/library/std/build.rs b/library/std/build.rs index 0f5068b59b7e5..60c097db2f4bf 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -35,6 +35,7 @@ fn main() { || target.contains("hurd") || target.contains("uefi") || target.contains("teeos") + || target.contains("zkvm") // See src/bootstrap/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() { diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index bb786bd59dc84..a834b36697c00 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -56,7 +56,7 @@ #![deny(unsafe_op_in_unsafe_fn)] #![stable(feature = "alloc_module", since = "1.28.0")] -use core::intrinsics; +use core::hint; use core::ptr::NonNull; use core::sync::atomic::{AtomicPtr, Ordering}; use core::{mem, ptr}; @@ -172,7 +172,7 @@ impl System { let new_size = new_layout.size(); // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. - intrinsics::assume(new_size >= old_layout.size()); + hint::assert_unchecked(new_size >= old_layout.size()); let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; @@ -264,7 +264,7 @@ unsafe impl Allocator for System { // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller new_size if old_layout.align() == new_layout.align() => unsafe { // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. - intrinsics::assume(new_size <= old_layout.size()); + hint::assert_unchecked(new_size <= old_layout.size()); let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 39e94902cfe5f..0d4c1fa05cc87 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -356,6 +356,7 @@ impl HashMap { /// /// In the current implementation, iterating over keys takes O(capacity) time /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn keys(&self) -> Keys<'_, K, V> { Keys { inner: self.iter() } @@ -417,6 +418,7 @@ impl HashMap { /// /// In the current implementation, iterating over values takes O(capacity) time /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn values(&self) -> Values<'_, K, V> { Values { inner: self.iter() } @@ -449,6 +451,7 @@ impl HashMap { /// /// In the current implementation, iterating over values takes O(capacity) time /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] #[stable(feature = "map_values_mut", since = "1.10.0")] pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { ValuesMut { inner: self.iter_mut() } @@ -2232,6 +2235,18 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K, V> { @@ -2256,6 +2271,18 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IterMut<'_, K, V> { @@ -2290,6 +2317,18 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { @@ -2320,6 +2359,18 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Keys<'_, K, V> { @@ -2343,6 +2394,18 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Values<'_, K, V> { @@ -2366,6 +2429,18 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } #[stable(feature = "map_values_mut", since = "1.10.0")] impl ExactSizeIterator for ValuesMut<'_, K, V> { @@ -2396,6 +2471,18 @@ impl Iterator for IntoKeys { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoKeys { @@ -2426,6 +2513,18 @@ impl Iterator for IntoValues { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoValues { @@ -2456,6 +2555,14 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "drain", since = "1.6.0")] impl ExactSizeIterator for Drain<'_, K, V> { diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 8bc5960829066..dcb2fa0f771b0 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1500,6 +1500,18 @@ impl<'a, K> Iterator for Iter<'a, K> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K> { @@ -1530,6 +1542,18 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { @@ -1560,6 +1584,14 @@ impl<'a, K> Iterator for Drain<'a, K> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Drain<'_, K> { @@ -1639,6 +1671,15 @@ where let (_, upper) = self.iter.size_hint(); (0, upper) } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| if self.other.contains(elt) { f(acc, elt) } else { acc }) + } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -1691,6 +1732,15 @@ where let (_, upper) = self.iter.size_hint(); (0, upper) } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| if self.other.contains(elt) { acc } else { f(acc, elt) }) + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1736,6 +1786,14 @@ where fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1800,6 +1858,18 @@ where fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn count(self) -> usize { + self.iter.count() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } #[allow(dead_code)] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c3506175715fe..1b38ba721147c 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -102,8 +102,6 @@ impl f32 { /// # Examples /// /// ``` - /// #![feature(round_ties_even)] - /// /// let f = 3.3_f32; /// let g = -3.3_f32; /// let h = 3.5_f32; @@ -116,7 +114,7 @@ impl f32 { /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "round_ties_even", issue = "96710")] + #[stable(feature = "round_ties_even", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn round_ties_even(self) -> f32 { unsafe { intrinsics::rintf32(self) } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index e4b7bfeeb84af..f8fc84440ae5c 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -102,8 +102,6 @@ impl f64 { /// # Examples /// /// ``` - /// #![feature(round_ties_even)] - /// /// let f = 3.3_f64; /// let g = -3.3_f64; /// let h = 3.5_f64; @@ -116,7 +114,7 @@ impl f64 { /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "round_ties_even", issue = "96710")] + #[stable(feature = "round_ties_even", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn round_ties_even(self) -> f64 { unsafe { intrinsics::rintf64(self) } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c4a92927937a1..80d369eb067d4 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -260,7 +260,8 @@ pub fn read>(path: P) -> io::Result> { fn inner(path: &Path) -> io::Result> { let mut file = File::open(path)?; let size = file.metadata().map(|m| m.len() as usize).ok(); - let mut bytes = Vec::with_capacity(size.unwrap_or(0)); + let mut bytes = Vec::new(); + bytes.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_end(&mut file, &mut bytes, size)?; Ok(bytes) } @@ -302,7 +303,8 @@ pub fn read_to_string>(path: P) -> io::Result { fn inner(path: &Path) -> io::Result { let mut file = File::open(path)?; let size = file.metadata().map(|m| m.len() as usize).ok(); - let mut string = String::with_capacity(size.unwrap_or(0)); + let mut string = String::new(); + string.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_string(&mut file, &mut string, size)?; Ok(string) } @@ -774,14 +776,14 @@ impl Read for &File { // Reserves space in the buffer based on the file size when available. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let size = buffer_capacity_required(self); - buf.reserve(size.unwrap_or(0)); + buf.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_end(self, buf, size) } // Reserves space in the buffer based on the file size when available. fn read_to_string(&mut self, buf: &mut String) -> io::Result { let size = buffer_capacity_required(self); - buf.reserve(size.unwrap_or(0)); + buf.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_string(self, buf, size) } } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 6c7494a6a6ff9..e920500d7d07f 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -345,6 +345,7 @@ impl Read for BufReader { // delegate to the inner implementation. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let inner_buf = self.buffer(); + buf.try_reserve(inner_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?; buf.extend_from_slice(inner_buf); let nread = inner_buf.len(); self.discard_buffer(); diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index b63091deac27e..13cc0511e103e 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -816,12 +816,12 @@ impl Error { } } - /// Attempt to downgrade the inner error to `E` if any. + /// Attempt to downcast the inner error to `E` if any. /// /// If this [`Error`] was constructed via [`new`] then this function will /// attempt to perform downgrade on it, otherwise it will return [`Err`]. /// - /// If downgrade succeeds, it will return [`Ok`], otherwise it will also + /// If the downcast succeeds, it will return [`Ok`], otherwise it will also /// return [`Err`]. /// /// [`new`]: Error::new @@ -852,13 +852,39 @@ impl Error { /// impl From for E { /// fn from(err: io::Error) -> E { /// err.downcast::() - /// .map(|b| *b) /// .unwrap_or_else(E::Io) /// } /// } + /// + /// impl From for io::Error { + /// fn from(err: E) -> io::Error { + /// match err { + /// E::Io(io_error) => io_error, + /// e => io::Error::new(io::ErrorKind::Other, e), + /// } + /// } + /// } + /// + /// # fn main() { + /// let e = E::SomeOtherVariant; + /// // Convert it to an io::Error + /// let io_error = io::Error::from(e); + /// // Cast it back to the original variant + /// let e = E::from(io_error); + /// assert!(matches!(e, E::SomeOtherVariant)); + /// + /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists); + /// // Convert it to E + /// let e = E::from(io_error); + /// // Cast it back to the original variant + /// let io_error = io::Error::from(e); + /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists); + /// assert!(io_error.get_ref().is_none()); + /// assert!(io_error.raw_os_error().is_none()); + /// # } /// ``` #[unstable(feature = "io_error_downcast", issue = "99262")] - pub fn downcast(self) -> result::Result, Self> + pub fn downcast(self) -> result::Result where E: error::Error + Send + Sync + 'static, { @@ -872,7 +898,7 @@ impl Error { // And the compiler should be able to eliminate the branch // that produces `Err` here since b.error.is::() // returns true. - Ok(res.unwrap()) + Ok(*res.unwrap()) } repr_data => Err(Self { repr: Repr::new(repr_data) }), } diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 36d52aef03cb7..fc6db2825e811 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -157,7 +157,7 @@ impl error::Error for E {} fn test_std_io_error_downcast() { // Case 1: custom error, downcast succeeds let io_error = Error::new(ErrorKind::Other, Bojji(true)); - let e: Box = io_error.downcast().unwrap(); + let e: Bojji = io_error.downcast().unwrap(); assert!(e.0); // Case 2: custom error, downcast fails @@ -166,7 +166,7 @@ fn test_std_io_error_downcast() { // ensures that the custom error is intact assert_eq!(ErrorKind::Other, io_error.kind()); - let e: Box = io_error.downcast().unwrap(); + let e: Bojji = io_error.downcast().unwrap(); assert!(e.0); // Case 3: os error diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index d8c8d933eb403..557e64dc8674e 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -303,8 +303,9 @@ impl Read for &[u8] { #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - buf.extend_from_slice(*self); let len = self.len(); + buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?; + buf.extend_from_slice(*self); *self = &self[len..]; Ok(len) } @@ -451,7 +452,7 @@ impl Read for VecDeque { fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { // The total len is known upfront so we can reserve it in a single call. let len = self.len(); - buf.reserve(len); + buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?; let (front, back) = self.as_slices(); buf.extend_from_slice(front); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e3aa973741f1f..a238e74ed95cf 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -430,6 +430,8 @@ pub(crate) fn default_read_to_end( loop { match r.read(&mut probe) { Ok(n) => { + // there is no way to recover from allocation failure here + // because the data has already been read. buf.extend_from_slice(&probe[..n]); return Ok(n); } @@ -462,7 +464,8 @@ pub(crate) fn default_read_to_end( } if buf.len() == buf.capacity() { - buf.reserve(PROBE_SIZE); // buf is full, need more space + // buf is full, need more space + buf.try_reserve(PROBE_SIZE).map_err(|_| ErrorKind::OutOfMemory)?; } let mut spare = buf.spare_capacity_mut(); @@ -575,8 +578,13 @@ where F: FnOnce(&mut [u8]) -> Result, { let n = read(cursor.ensure_init().init_mut())?; + assert!( + n <= cursor.capacity(), + "read should not return more bytes than there is capacity for in the read buffer" + ); unsafe { - // SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to. + // SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to + // and we have checked that the read amount is not over capacity (see #120603) cursor.advance(n); } Ok(()) @@ -815,6 +823,39 @@ pub trait Read { /// file.) /// /// [`std::fs::read`]: crate::fs::read + /// + /// ## Implementing `read_to_end` + /// + /// When implementing the `io::Read` trait, it is recommended to allocate + /// memory using [`Vec::try_reserve`]. However, this behavior is not guaranteed + /// by all implementations, and `read_to_end` may not handle out-of-memory + /// situations gracefully. + /// + /// ```no_run + /// # use std::io::{self, BufRead}; + /// # struct Example { example_datasource: io::Empty } impl Example { + /// # fn get_some_data_for_the_example(&self) -> &'static [u8] { &[] } + /// fn read_to_end(&mut self, dest_vec: &mut Vec) -> io::Result { + /// let initial_vec_len = dest_vec.len(); + /// loop { + /// let src_buf = self.example_datasource.fill_buf()?; + /// if src_buf.is_empty() { + /// break; + /// } + /// dest_vec.try_reserve(src_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?; + /// dest_vec.extend_from_slice(src_buf); + /// + /// // Any irreversible side effects should happen after `try_reserve` succeeds, + /// // to avoid losing data on allocation error. + /// let read = src_buf.len(); + /// self.example_datasource.consume(read); + /// } + /// Ok(dest_vec.len() - initial_vec_len) + /// } + /// # } + /// ``` + /// + /// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec) -> Result { default_read_to_end(self, buf, None) @@ -958,7 +999,10 @@ pub trait Read { } if cursor.written() == prev_written { - return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer")); + return Err(error::const_io_error!( + ErrorKind::UnexpectedEof, + "failed to fill whole buffer" + )); } } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 05b21eeb40f71..261b570dee74f 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,9 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::fs::File; -use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; +use crate::io::{ + self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte, +}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; use crate::sys::stdio; @@ -483,6 +485,13 @@ impl Read for StdinLock<'_> { } } +impl SpecReadByte for StdinLock<'_> { + #[inline] + fn spec_read_byte(&mut self) -> Option> { + BufReader::spec_read_byte(&mut *self.inner) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for StdinLock<'_> { fn fill_buf(&mut self) -> io::Result<&[u8]> { diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index bda5b721adc63..33e9d8efed511 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,6 +1,6 @@ use super::{repeat, BorrowedBuf, Cursor, SeekFrom}; use crate::cmp::{self, min}; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut, DEFAULT_BUF_SIZE}; use crate::io::{BufRead, BufReader, Read, Seek, Write}; use crate::mem::MaybeUninit; use crate::ops::Deref; @@ -652,3 +652,32 @@ fn bench_take_read_buf(b: &mut test::Bencher) { [255; 128].take(64).read_buf(buf.unfilled()).unwrap(); }); } + +// Issue #120603 +#[test] +#[should_panic = "read should not return more bytes than there is capacity for in the read buffer"] +fn read_buf_broken_read() { + struct MalformedRead; + + impl Read for MalformedRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // broken length calculation + Ok(buf.len() + 1) + } + } + + let _ = BufReader::new(MalformedRead).fill_buf(); +} + +#[test] +fn read_buf_full_read() { + struct FullRead; + + impl Read for FullRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + Ok(buf.len()) + } + } + + assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE); +} diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 6bc8f181c905f..a04bc4811460b 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -204,6 +204,16 @@ impl Read for Repeat { Ok(()) } + /// This function is not supported by `io::Repeat`, because there's no end of its data + fn read_to_end(&mut self, _: &mut Vec) -> io::Result { + Err(io::Error::from(io::ErrorKind::OutOfMemory)) + } + + /// This function is not supported by `io::Repeat`, because there's no end of its data + fn read_to_string(&mut self, _: &mut String) -> io::Result { + Err(io::Error::from(io::ErrorKind::OutOfMemory)) + } + #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nwritten = 0; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7a8d9d0ceeca6..f98654e4d1868 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -262,6 +262,7 @@ )] #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))] #![cfg_attr(target_os = "xous", feature(slice_ptr_len))] +#![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] // // Language features: // tidy-alphabetical-start @@ -323,13 +324,14 @@ #![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(float_next_up_down)] +#![feature(generic_nonzero)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] +#![feature(hint_assert_unchecked)] #![feature(ip)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] -#![feature(offset_of)] #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] @@ -337,8 +339,6 @@ #![feature(portable_simd)] #![feature(prelude_2024)] #![feature(ptr_as_uninit)] -#![feature(raw_os_nonzero)] -#![feature(round_ties_even)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_range)] @@ -365,6 +365,11 @@ #![feature(panic_unwind)] // tidy-alphabetical-end // +// Library features (std_detect): +// tidy-alphabetical-start +#![feature(stdarch_internal)] +// tidy-alphabetical-end +// // Only for re-exporting: // tidy-alphabetical-start #![feature(assert_matches)] @@ -380,7 +385,6 @@ #![feature(get_many_mut)] #![feature(lazy_cell)] #![feature(log_syntax)] -#![feature(stdsimd)] #![feature(test)] #![feature(trace_macros)] // tidy-alphabetical-end @@ -619,13 +623,16 @@ pub mod arch { #[stable(feature = "simd_aarch64", since = "1.60.0")] pub use std_detect::is_aarch64_feature_detected; + #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] + pub use std_detect::is_arm_feature_detected; + #[unstable(feature = "is_riscv_feature_detected", issue = "111192")] + pub use std_detect::is_riscv_feature_detected; #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; - #[unstable(feature = "stdsimd", issue = "48556")] - pub use std_detect::{ - is_arm_feature_detected, is_mips64_feature_detected, is_mips_feature_detected, - is_powerpc64_feature_detected, is_powerpc_feature_detected, is_riscv_feature_detected, - }; + #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] + pub use std_detect::{is_mips64_feature_detected, is_mips_feature_detected}; + #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] + pub use std_detect::{is_powerpc64_feature_detected, is_powerpc_feature_detected}; } // This was stabilized in the crate root so we have to keep it there. diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 55f6ddcf77fbf..1343fdfd1dfdd 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -16,6 +16,16 @@ pub use core::num::Wrapping; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError}; +#[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +pub use core::num::ZeroablePrimitive; + +#[unstable(feature = "generic_nonzero", issue = "120257")] +pub use core::num::NonZero; + #[stable(feature = "signed_nonzero", since = "1.34.0")] pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; #[stable(feature = "nonzero", since = "1.28.0")] diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index 51af432d0568d..2ba67a6dd1aa9 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -149,8 +149,7 @@ pub trait CommandExt: Sealed { /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`]. /// /// A pidfd will only be created if it is possible to do so - /// in a guaranteed race-free manner (e.g. if the `clone3` system call - /// is supported). Otherwise, [`pidfd`] will return an error. + /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error. /// /// If a pidfd has been successfully created and not been taken from the `Child` /// then calls to `kill()`, `wait()` and `try_wait()` will use the pidfd diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 8bf1e2dca6f7b..ecc0bbce5437a 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -80,7 +80,12 @@ impl UnixListener { target_os = "horizon" ))] const backlog: libc::c_int = 128; - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any( + target_os = "linux", + target_os = "freebsd", + target_os = "openbsd", + target_os = "macos" + ))] const backlog: libc::c_int = -1; #[cfg(not(any( target_os = "windows", @@ -88,6 +93,7 @@ impl UnixListener { target_os = "linux", target_os = "freebsd", target_os = "openbsd", + target_os = "macos", target_os = "espidf", target_os = "horizon" )))] diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 1b013d1c154c9..e9d7a13e9d5b2 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -59,7 +59,7 @@ pub trait FileExt { /// function, it is set to the end of the write. /// /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are left uninitialized. + /// extended and the intermediate bytes are set to zero. /// /// Note that similar to `File::write`, it is not an error to return a /// short write. When returning from such a short write, the file pointer diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs index 8be7fbb102f3e..7fe84db515c34 100644 --- a/library/std/src/os/xous/ffi.rs +++ b/library/std/src/os/xous/ffi.rs @@ -88,29 +88,31 @@ fn lend_impl( let a3 = opcode; let a4 = data.as_ptr() as usize; let a5 = data.len(); - let mut a6 = arg1; - let mut a7 = arg2; + let a6 = arg1; + let a7 = arg2; + let mut ret1; + let mut ret2; unsafe { core::arch::asm!( "ecall", inlateout("a0") a0, - inlateout("a1") a1 => _, - inlateout("a2") a2 => _, + inlateout("a1") a1 => ret1, + inlateout("a2") a2 => ret2, inlateout("a3") a3 => _, inlateout("a4") a4 => _, inlateout("a5") a5 => _, - inlateout("a6") a6, - inlateout("a7") a7, + inlateout("a6") a6 => _, + inlateout("a7") a7 => _, ) }; let result = a0; if result == SyscallResult::MemoryReturned as usize { - Ok((a6, a7)) + Ok((ret1, ret2)) } else if result == SyscallResult::Error as usize { - Err(a1.into()) + Err(ret1.into()) } else { Err(Error::InternalError) } @@ -405,7 +407,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(); + let a2 = range.len() * core::mem::size_of::(); let a3 = 0; let a4 = 0; let a5 = 0; @@ -450,7 +452,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(); + let a2 = range.len() * core::mem::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.rs b/library/std/src/os/xous/services.rs index 5c219f1fbb95e..a75be1b857003 100644 --- a/library/std/src/os/xous/services.rs +++ b/library/std/src/os/xous/services.rs @@ -1,9 +1,15 @@ use crate::os::xous::ffi::Connection; use core::sync::atomic::{AtomicU32, Ordering}; +mod dns; +pub(crate) use dns::*; + mod log; pub(crate) use log::*; +mod net; +pub(crate) use net::*; + mod systime; pub(crate) use systime::*; diff --git a/library/std/src/os/xous/services/dns.rs b/library/std/src/os/xous/services/dns.rs new file mode 100644 index 0000000000000..a7d88f4892cda --- /dev/null +++ b/library/std/src/os/xous/services/dns.rs @@ -0,0 +1,28 @@ +use crate::os::xous::ffi::Connection; +use crate::os::xous::services::connect; +use core::sync::atomic::{AtomicU32, Ordering}; + +#[repr(usize)] +pub(crate) enum DnsLendMut { + RawLookup = 6, +} + +impl Into for DnsLendMut { + fn into(self) -> usize { + self as usize + } +} + +/// Return a `Connection` to the DNS lookup server. This server is used for +/// querying domain name values. +pub(crate) fn dns_server() -> Connection { + static DNS_CONNECTION: AtomicU32 = AtomicU32::new(0); + let cid = DNS_CONNECTION.load(Ordering::Relaxed); + if cid != 0 { + return cid.into(); + } + + let cid = connect("_DNS Resolver Middleware_").unwrap(); + DNS_CONNECTION.store(cid.into(), Ordering::Relaxed); + cid +} diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs index e6bae929eac0e..55a501dc7d00e 100644 --- a/library/std/src/os/xous/services/log.rs +++ b/library/std/src/os/xous/services/log.rs @@ -45,6 +45,17 @@ impl<'a> Into<[usize; 5]> for LogScalar<'a> { } } +pub(crate) enum LogLend { + StandardOutput = 1, + StandardError = 2, +} + +impl Into for LogLend { + fn into(self) -> usize { + self as usize + } +} + /// Return a `Connection` to the log server, which is used for printing messages to /// the console and reporting panics. If the log server has not yet started, this /// will block until the server is running. It is safe to call this multiple times, diff --git a/library/std/src/os/xous/services/net.rs b/library/std/src/os/xous/services/net.rs new file mode 100644 index 0000000000000..26d337dcef168 --- /dev/null +++ b/library/std/src/os/xous/services/net.rs @@ -0,0 +1,95 @@ +use crate::os::xous::ffi::Connection; +use crate::os::xous::services::connect; +use core::sync::atomic::{AtomicU32, Ordering}; + +pub(crate) enum NetBlockingScalar { + StdGetTtlUdp(u16 /* fd */), /* 36 */ + StdSetTtlUdp(u16 /* fd */, u32 /* ttl */), /* 37 */ + StdGetTtlTcp(u16 /* fd */), /* 36 */ + StdSetTtlTcp(u16 /* fd */, u32 /* ttl */), /* 37 */ + StdGetNodelay(u16 /* fd */), /* 38 */ + StdSetNodelay(u16 /* fd */, bool), /* 39 */ + StdTcpClose(u16 /* fd */), /* 34 */ + StdUdpClose(u16 /* fd */), /* 41 */ + StdTcpStreamShutdown(u16 /* fd */, crate::net::Shutdown /* how */), /* 46 */ +} + +pub(crate) enum NetLendMut { + StdTcpConnect, /* 30 */ + StdTcpTx(u16 /* fd */), /* 31 */ + StdTcpPeek(u16 /* fd */, bool /* nonblocking */), /* 32 */ + StdTcpRx(u16 /* fd */, bool /* nonblocking */), /* 33 */ + StdGetAddress(u16 /* fd */), /* 35 */ + StdUdpBind, /* 40 */ + StdUdpRx(u16 /* fd */), /* 42 */ + StdUdpTx(u16 /* fd */), /* 43 */ + StdTcpListen, /* 44 */ + StdTcpAccept(u16 /* fd */), /* 45 */ +} + +impl Into for NetLendMut { + fn into(self) -> usize { + match self { + NetLendMut::StdTcpConnect => 30, + NetLendMut::StdTcpTx(fd) => 31 | ((fd as usize) << 16), + NetLendMut::StdTcpPeek(fd, blocking) => { + 32 | ((fd as usize) << 16) | if blocking { 0x8000 } else { 0 } + } + NetLendMut::StdTcpRx(fd, blocking) => { + 33 | ((fd as usize) << 16) | if blocking { 0x8000 } else { 0 } + } + NetLendMut::StdGetAddress(fd) => 35 | ((fd as usize) << 16), + NetLendMut::StdUdpBind => 40, + NetLendMut::StdUdpRx(fd) => 42 | ((fd as usize) << 16), + NetLendMut::StdUdpTx(fd) => 43 | ((fd as usize) << 16), + NetLendMut::StdTcpListen => 44, + NetLendMut::StdTcpAccept(fd) => 45 | ((fd as usize) << 16), + } + } +} + +impl<'a> Into<[usize; 5]> for NetBlockingScalar { + fn into(self) -> [usize; 5] { + match self { + NetBlockingScalar::StdGetTtlTcp(fd) => [36 | ((fd as usize) << 16), 0, 0, 0, 0], + NetBlockingScalar::StdGetTtlUdp(fd) => [36 | ((fd as usize) << 16), 0, 0, 0, 1], + NetBlockingScalar::StdSetTtlTcp(fd, ttl) => { + [37 | ((fd as usize) << 16), ttl as _, 0, 0, 0] + } + NetBlockingScalar::StdSetTtlUdp(fd, ttl) => { + [37 | ((fd as usize) << 16), ttl as _, 0, 0, 1] + } + NetBlockingScalar::StdGetNodelay(fd) => [38 | ((fd as usize) << 16), 0, 0, 0, 0], + NetBlockingScalar::StdSetNodelay(fd, enabled) => { + [39 | ((fd as usize) << 16), if enabled { 1 } else { 0 }, 0, 0, 1] + } + NetBlockingScalar::StdTcpClose(fd) => [34 | ((fd as usize) << 16), 0, 0, 0, 0], + NetBlockingScalar::StdUdpClose(fd) => [41 | ((fd as usize) << 16), 0, 0, 0, 0], + NetBlockingScalar::StdTcpStreamShutdown(fd, how) => [ + 46 | ((fd as usize) << 16), + match how { + crate::net::Shutdown::Read => 1, + crate::net::Shutdown::Write => 2, + crate::net::Shutdown::Both => 3, + }, + 0, + 0, + 0, + ], + } + } +} + +/// Return a `Connection` to the Network server. This server provides all +/// OS-level networking functions. +pub(crate) fn net_server() -> Connection { + static NET_CONNECTION: AtomicU32 = AtomicU32::new(0); + let cid = NET_CONNECTION.load(Ordering::Relaxed); + if cid != 0 { + return cid.into(); + } + + let cid = connect("_Middleware Network Server_").unwrap(); + NET_CONNECTION.store(cid.into(), Ordering::Relaxed); + cid +} diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 7f6b563d72959..3728d5b64b865 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -5,7 +5,7 @@ use crate::any::Any; use crate::collections; use crate::panicking; -use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicU8, Ordering}; use crate::sync::{Mutex, RwLock}; use crate::thread::Result; @@ -228,7 +228,7 @@ impl BacktraceStyle { if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None } } - fn as_usize(self) -> usize { + fn as_u8(self) -> u8 { match self { BacktraceStyle::Short => 1, BacktraceStyle::Full => 2, @@ -236,7 +236,7 @@ impl BacktraceStyle { } } - fn from_usize(s: usize) -> Option { + fn from_u8(s: u8) -> Option { Some(match s { 0 => return None, 1 => BacktraceStyle::Short, @@ -251,7 +251,7 @@ impl BacktraceStyle { // that backtrace. // // Internally stores equivalent of an Option. -static SHOULD_CAPTURE: AtomicUsize = AtomicUsize::new(0); +static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0); /// Configure whether the default panic hook will capture and display a /// backtrace. @@ -264,7 +264,7 @@ pub fn set_backtrace_style(style: BacktraceStyle) { // If the `backtrace` feature of this crate isn't enabled, skip setting. return; } - SHOULD_CAPTURE.store(style.as_usize(), Ordering::Release); + SHOULD_CAPTURE.store(style.as_u8(), Ordering::Release); } /// Checks whether the standard library's panic hook will capture and print a @@ -296,7 +296,7 @@ pub fn get_backtrace_style() -> Option { // to optimize away callers. return None; } - if let Some(style) = BacktraceStyle::from_usize(SHOULD_CAPTURE.load(Ordering::Acquire)) { + if let Some(style) = BacktraceStyle::from_u8(SHOULD_CAPTURE.load(Ordering::Acquire)) { return Some(style); } diff --git a/library/std/src/sys/pal/unix/cmath.rs b/library/std/src/sys/cmath/builtins.rs similarity index 98% rename from library/std/src/sys/pal/unix/cmath.rs rename to library/std/src/sys/cmath/builtins.rs index 5346d229116f7..c680132efa4ba 100644 --- a/library/std/src/sys/pal/unix/cmath.rs +++ b/library/std/src/sys/cmath/builtins.rs @@ -1,5 +1,3 @@ -#![cfg(not(test))] - // These symbols are all defined by `libm`, // or by `compiler-builtins` on unsupported platforms. diff --git a/library/std/src/sys/cmath/mod.rs b/library/std/src/sys/cmath/mod.rs new file mode 100644 index 0000000000000..79d5021dd8dc3 --- /dev/null +++ b/library/std/src/sys/cmath/mod.rs @@ -0,0 +1,11 @@ +#![cfg(not(test))] + +cfg_if::cfg_if! { + if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else { + mod builtins; + pub use builtins::*; + } +} diff --git a/library/std/src/sys/pal/windows/cmath.rs b/library/std/src/sys/cmath/windows.rs similarity index 99% rename from library/std/src/sys/pal/windows/cmath.rs rename to library/std/src/sys/cmath/windows.rs index 36578d5a34e14..712097f06ff30 100644 --- a/library/std/src/sys/pal/windows/cmath.rs +++ b/library/std/src/sys/cmath/windows.rs @@ -1,5 +1,3 @@ -#![cfg(not(test))] - use core::ffi::{c_double, c_float, c_int}; extern "C" { diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index bbdcb32606ccc..e03e98b18d29f 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -5,6 +5,9 @@ mod pal; mod personality; +pub mod cmath; +pub mod os_str; + // FIXME(117276): remove this, move feature implementations into individual // submodules. pub use pal::*; diff --git a/library/std/src/sys/pal/unix/os_str.rs b/library/std/src/sys/os_str/bytes.rs similarity index 99% rename from library/std/src/sys/pal/unix/os_str.rs rename to library/std/src/sys/os_str/bytes.rs index 7bd2f656a24e5..3a75ce9ebb781 100644 --- a/library/std/src/sys/pal/unix/os_str.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -14,7 +14,6 @@ use crate::sys_common::{AsInner, IntoInner}; use core::str::Utf8Chunks; #[cfg(test)] -#[path = "../unix/os_str/tests.rs"] mod tests; #[derive(Hash)] diff --git a/library/std/src/sys/pal/unix/os_str/tests.rs b/library/std/src/sys/os_str/bytes/tests.rs similarity index 100% rename from library/std/src/sys/pal/unix/os_str/tests.rs rename to library/std/src/sys/os_str/bytes/tests.rs diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs new file mode 100644 index 0000000000000..b509729475bf7 --- /dev/null +++ b/library/std/src/sys/os_str/mod.rs @@ -0,0 +1,12 @@ +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "windows", + target_os = "uefi", + ))] { + mod wtf8; + pub use wtf8::{Buf, Slice}; + } else { + mod bytes; + pub use bytes::{Buf, Slice}; + } +} diff --git a/library/std/src/sys/pal/windows/os_str.rs b/library/std/src/sys/os_str/wtf8.rs similarity index 100% rename from library/std/src/sys/pal/windows/os_str.rs rename to library/std/src/sys/os_str/wtf8.rs diff --git a/library/std/src/sys/pal/common/alloc.rs b/library/std/src/sys/pal/common/alloc.rs index b7357460f3931..8cf9ef6804724 100644 --- a/library/std/src/sys/pal/common/alloc.rs +++ b/library/std/src/sys/pal/common/alloc.rs @@ -16,7 +16,7 @@ use crate::ptr; target_arch = "sparc", target_arch = "wasm32", target_arch = "hexagon", - all(target_arch = "riscv32", not(target_os = "espidf")), + all(target_arch = "riscv32", not(any(target_os = "espidf", target_os = "zkvm"))), all(target_arch = "xtensa", not(target_os = "espidf")), ))] pub const MIN_ALIGN: usize = 8; @@ -32,11 +32,11 @@ pub const MIN_ALIGN: usize = 8; target_arch = "wasm64", ))] pub const MIN_ALIGN: usize = 16; -// The allocator on the esp-idf platform guarantees 4 byte alignment. -#[cfg(any( - all(target_arch = "riscv32", target_os = "espidf"), +// The allocator on the esp-idf and zkvm platforms guarantee 4 byte alignment. +#[cfg(all(any( + all(target_arch = "riscv32", any(target_os = "espidf", target_os = "zkvm")), all(target_arch = "xtensa", target_os = "espidf"), -))] +)))] pub const MIN_ALIGN: usize = 4; pub unsafe fn realloc_fallback( diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 937603cfd8a0b..3c83afa280be5 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -19,8 +19,6 @@ use crate::os::raw::c_char; pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; pub mod fs; @@ -30,8 +28,6 @@ pub mod io; pub mod memchr; pub mod net; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 66b2a4b888502..041b7c355822a 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -55,6 +55,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "teeos")] { mod teeos; pub use self::teeos::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use self::zkvm::*; } else { mod unsupported; pub use self::unsupported::*; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 09d3f7638ca2d..a769fc1ef5932 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -13,8 +13,6 @@ mod waitqueue; pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; #[path = "../unsupported/fs.rs"] @@ -24,8 +22,6 @@ pub mod io; pub mod memchr; pub mod net; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs index 03620a08f2c03..c4d5da1627cb2 100644 --- a/library/std/src/sys/pal/sgx/net.rs +++ b/library/std/src/sys/pal/sgx/net.rs @@ -542,7 +542,4 @@ pub mod netc { pub sin6_flowinfo: u32, pub sin6_scope_id: u32, } - - #[derive(Copy, Clone)] - pub struct sockaddr {} } diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 5af83653cf849..46699e64169f5 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -21,8 +21,6 @@ mod itron { pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` @@ -31,8 +29,6 @@ pub mod fs; pub mod io; pub mod net; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index ed8c54b2c36fb..95a5b97ea4237 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -11,8 +11,6 @@ pub use self::rand::hashmap_random_keys; pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; #[path = "../unsupported/env.rs"] pub mod env; pub mod locks; @@ -27,8 +25,6 @@ pub mod net; #[path = "../unsupported/once.rs"] pub mod once; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/teeos/net.rs b/library/std/src/sys/pal/teeos/net.rs index 0df681dbfa552..fed95205027a7 100644 --- a/library/std/src/sys/pal/teeos/net.rs +++ b/library/std/src/sys/pal/teeos/net.rs @@ -364,9 +364,6 @@ pub mod netc { pub sin6_flowinfo: u32, pub sin6_scope_id: u32, } - - #[derive(Copy, Clone)] - pub struct sockaddr {} } pub type Socket = UdpSocket; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 4edc00e3ea022..9ee753aa1a0c1 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -14,8 +14,6 @@ pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; @@ -28,8 +26,6 @@ pub mod net; #[path = "../unsupported/once.rs"] pub mod once; pub mod os; -#[path = "../windows/os_str.rs"] -pub mod os_str; pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index 9f7dcc0416e52..78e82d9c194c4 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -201,9 +201,9 @@ mod imp { // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs // and use underscores in their names - they're most probably - // are considered private and therefore should be avoided - // Here is another way to get arguments using Objective C - // runtime + // are considered private and therefore should be avoided. + // Here is another way to get arguments using the Objective-C + // runtime. // // In general it looks like: // res = Vec::new() @@ -213,53 +213,60 @@ mod imp { // res #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn args() -> Args { - use crate::ffi::OsString; + use crate::ffi::{c_char, c_void, OsString}; use crate::mem; use crate::str; - extern "C" { - fn sel_registerName(name: *const libc::c_uchar) -> Sel; - fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; - } + type Sel = *const c_void; + type NsId = *const c_void; + type NSUInteger = usize; - #[cfg(target_arch = "aarch64")] extern "C" { - fn objc_msgSend(obj: NsId, sel: Sel) -> NsId; - #[allow(clashing_extern_declarations)] - #[link_name = "objc_msgSend"] - fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId; - } + fn sel_registerName(name: *const c_char) -> Sel; + fn objc_getClass(class_name: *const c_char) -> NsId; - #[cfg(not(target_arch = "aarch64"))] - extern "C" { - fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; - #[allow(clashing_extern_declarations)] - #[link_name = "objc_msgSend"] - fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId; + // This must be transmuted to an appropriate function pointer type before being called. + fn objc_msgSend(); } - type Sel = *const libc::c_void; - type NsId = *const libc::c_void; + const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend; + const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void = + unsafe { mem::transmute(MSG_SEND_PTR) }; + const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn( + NsId, + Sel, + ) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) }; + const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn( + NsId, + Sel, + NSUInteger, + ) + -> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) }; let mut res = Vec::new(); unsafe { - let process_info_sel = - sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar); - let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar); - let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar); - let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar); - let object_at_sel = - sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar); - - let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar); - let info = objc_msgSend(klass, process_info_sel); - let args = objc_msgSend(info, arguments_sel); - - let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); + let process_info_sel = sel_registerName(c"processInfo".as_ptr()); + let arguments_sel = sel_registerName(c"arguments".as_ptr()); + let count_sel = sel_registerName(c"count".as_ptr()); + let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr()); + let utf8string_sel = sel_registerName(c"UTF8String".as_ptr()); + + let klass = objc_getClass(c"NSProcessInfo".as_ptr()); + // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`. + let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel); + + // `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`. + let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel); + + let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel); for i in 0..cnt { - let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong); - let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel)); + // `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`. + let ns_string = + MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i); + // The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below. + let utf_c_str: *const c_char = + MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast(); let bytes = CStr::from_ptr(utf_c_str).to_bytes(); res.push(OsString::from(str::from_utf8(bytes).unwrap())) } diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index b5da5f870ec12..43cb9d89be9dd 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -11,8 +11,6 @@ pub mod weak; pub mod alloc; pub mod android; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; pub mod fs; @@ -29,7 +27,6 @@ pub mod net; #[cfg(target_os = "l4re")] pub use self::l4re::net; pub mod os; -pub mod os_str; pub mod path; pub mod pipe; pub mod process; 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 fac6d92439ee8..94c4c56bd51cf 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -1,11 +1,10 @@ use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::mem; -use crate::num::NonZeroI32; +use crate::num::{NonZero, NonZeroI32}; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; -use core::ffi::NonZero_c_int; #[cfg(target_os = "linux")] use crate::os::linux::process::PidFd; @@ -147,8 +146,7 @@ impl Command { #[cfg(not(target_os = "linux"))] let pidfd = -1; - // Safety: We obtained the pidfd from calling `clone3` with - // `CLONE_PIDFD` so it's valid an otherwise unowned. + // Safety: We obtained the pidfd (on Linux) using SOCK_SEQPACKET, so it's valid. let mut p = unsafe { Process::new(pid, pidfd) }; let mut bytes = [0; 8]; @@ -936,7 +934,7 @@ impl ExitStatus { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not // true for a platform pretending to be Unix, the tests (our doctests, and also // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. - match NonZero_c_int::try_from(self.0) { + match NonZero::try_from(self.0) { /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), /* was zero, couldn't convert */ Err(_) => Ok(()), } @@ -1093,7 +1091,7 @@ impl fmt::Display for ExitStatus { } #[derive(PartialEq, Eq, Clone, Copy)] -pub struct ExitStatusError(NonZero_c_int); +pub struct ExitStatusError(NonZero); impl Into for ExitStatusError { fn into(self) -> ExitStatus { diff --git a/library/std/src/sys/pal/unix/process/process_unix/tests.rs b/library/std/src/sys/pal/unix/process/process_unix/tests.rs index 6e952ed7c42af..0a6c6ec19fc7e 100644 --- a/library/std/src/sys/pal/unix/process/process_unix/tests.rs +++ b/library/std/src/sys/pal/unix/process/process_unix/tests.rs @@ -62,13 +62,14 @@ fn test_command_fork_no_unwind() { } #[test] -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux")] // pidfds are a linux-specific concept fn test_command_pidfd() { use crate::assert_matches::assert_matches; use crate::os::fd::{AsRawFd, RawFd}; use crate::os::linux::process::{ChildExt, CommandExt}; use crate::process::Command; + // pidfds require the pidfd_open syscall let our_pid = crate::process::id(); let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; let pidfd_open_available = if pidfd >= 0 { @@ -81,7 +82,9 @@ fn test_command_pidfd() { // always exercise creation attempts let mut child = Command::new("false").create_pidfd(true).spawn().unwrap(); - // but only check if we know that the kernel supports pidfds + // but only check if we know that the kernel supports pidfds. + // We don't assert the precise value, since the standard library + // might have opened other file descriptors before our code runs. if pidfd_open_available { assert!(child.pidfd().is_ok()); } @@ -97,4 +100,17 @@ fn test_command_pidfd() { child.kill().expect("failed to kill child"); let status = child.wait().expect("error waiting on pidfd"); assert_eq!(status.signal(), Some(libc::SIGKILL)); + + let _ = Command::new("echo") + .create_pidfd(false) + .spawn() + .unwrap() + .pidfd() + .expect_err("pidfd should not have been created when create_pid(false) is set"); + + let _ = Command::new("echo") + .spawn() + .unwrap() + .pidfd() + .expect_err("pidfd should not have been created"); } diff --git a/library/std/src/sys/pal/unix/process/process_unsupported.rs b/library/std/src/sys/pal/unix/process/process_unsupported.rs index 9453c8a384e24..89a2a0c6e567b 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported.rs +++ b/library/std/src/sys/pal/unix/process/process_unsupported.rs @@ -1,9 +1,8 @@ use crate::fmt; use crate::io; -use crate::num::NonZeroI32; +use crate::num::{NonZero, NonZeroI32}; use crate::sys::pal::unix::unsupported::*; use crate::sys::process::process_common::*; -use core::ffi::NonZero_c_int; use libc::{c_int, pid_t}; @@ -59,7 +58,7 @@ mod wait_status; pub use wait_status::ExitStatus; #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatusError(NonZero_c_int); +pub struct ExitStatusError(NonZero); impl Into for ExitStatusError { fn into(self) -> ExitStatus { diff --git a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs index 72b7ae18cff27..e6dfadcf4a4cf 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs +++ b/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs @@ -1,10 +1,9 @@ //! Emulated wait status for non-Unix #[cfg(unix) platforms //! //! Separate module to facilitate testing against a real Unix implementation. -use core::ffi::NonZero_c_int; - use crate::ffi::c_int; use crate::fmt; +use crate::num::NonZero; use super::ExitStatusError; @@ -50,7 +49,7 @@ impl ExitStatus { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not // true for a platform pretending to be Unix, the tests (our doctests, and also // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. - match NonZero_c_int::try_from(self.wait_status) { + match NonZero::try_from(self.wait_status) { /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), /* was zero, couldn't convert */ Err(_) => Ok(()), } diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs index 1ff2b2fb3833f..5b4e94d0f1b97 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs @@ -1,11 +1,10 @@ use crate::fmt; use crate::io::{self, Error, ErrorKind}; -use crate::num::NonZeroI32; +use crate::num::{NonZero, NonZeroI32}; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; use crate::sys_common::thread; -use core::ffi::NonZero_c_int; use libc::RTP_ID; use libc::{self, c_char, c_int}; @@ -197,7 +196,7 @@ impl ExitStatus { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not // true for a platform pretending to be Unix, the tests (our doctests, and also // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. - match NonZero_c_int::try_from(self.0) { + match NonZero::try_from(self.0) { Ok(failure) => Err(ExitStatusError(failure)), Err(_) => Ok(()), } @@ -249,7 +248,7 @@ impl fmt::Display for ExitStatus { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatusError(NonZero_c_int); +pub struct ExitStatusError(NonZero); impl Into for ExitStatusError { fn into(self) -> ExitStatus { diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs index cf0fe0f47c53f..1dba1ccf64e68 100644 --- a/library/std/src/sys/pal/unix/rand.rs +++ b/library/std/src/sys/pal/unix/rand.rs @@ -106,7 +106,18 @@ mod imp { // supported on the current kernel. // // Also fall back in case it is disabled by something like - // seccomp or inside of virtual machines. + // seccomp or inside of docker. + // + // If the `getrandom` syscall is not implemented in the current kernel version it should return an + // `ENOSYS` error. Docker also blocks the whole syscall inside unprivileged containers, and + // returns `EPERM` (instead of `ENOSYS`) when a program tries to invoke the syscall. Because of + // that we need to check for *both* `ENOSYS` and `EPERM`. + // + // Note that Docker's behavior is breaking other projects (notably glibc), so they're planning + // to update their filtering to return `ENOSYS` in a future release: + // + // https://github.com/moby/moby/issues/42680 + // GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed); return false; } else if err == libc::EAGAIN { diff --git a/library/std/src/sys/pal/unix/thread_local_dtor.rs b/library/std/src/sys/pal/unix/thread_local_dtor.rs index 58f7ab84101ae..4bf8f20670dbe 100644 --- a/library/std/src/sys/pal/unix/thread_local_dtor.rs +++ b/library/std/src/sys/pal/unix/thread_local_dtor.rs @@ -17,7 +17,9 @@ target_os = "android", target_os = "fuchsia", target_os = "redox", - target_os = "hurd" + target_os = "hurd", + target_os = "netbsd", + target_os = "dragonfly" ))] // FIXME: The Rust compiler currently omits weakly function definitions (i.e., // __cxa_thread_atexit_impl) and its metadata from LLVM IR. @@ -115,7 +117,8 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { target_os = "vxworks", target_os = "horizon", target_os = "emscripten", - target_os = "aix" + target_os = "aix", + target_os = "freebsd", ))] #[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten) pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index e1a38de647116..b56ded8579c4d 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -2,8 +2,6 @@ pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fs; pub mod io; @@ -11,8 +9,6 @@ pub mod locks; pub mod net; pub mod once; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; #[path = "../unix/path.rs"] pub mod path; pub mod pipe; diff --git a/library/std/src/sys/pal/unsupported/net.rs b/library/std/src/sys/pal/unsupported/net.rs index bbc52703f9632..931fe9ba24655 100644 --- a/library/std/src/sys/pal/unsupported/net.rs +++ b/library/std/src/sys/pal/unsupported/net.rs @@ -364,7 +364,4 @@ pub mod netc { pub sin6_flowinfo: u32, pub sin6_scope_id: u32, } - - #[derive(Copy, Clone)] - pub struct sockaddr {} } diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 5919cc506d921..4ffc8ecdd67ee 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -20,8 +20,6 @@ use crate::mem; #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; pub mod fs; @@ -32,8 +30,6 @@ pub mod io; pub mod net; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/pal/wasi/net.rs index 2239880ffbef4..2098d05db0bc7 100644 --- a/library/std/src/sys/pal/wasi/net.rs +++ b/library/std/src/sys/pal/wasi/net.rs @@ -538,7 +538,4 @@ pub mod netc { pub sin6_flowinfo: u32, pub sin6_scope_id: u32, } - - #[derive(Copy, Clone)] - pub struct sockaddr {} } diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 6c05b56e1bfc0..76306b618d82b 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -19,8 +19,6 @@ pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; @@ -30,8 +28,6 @@ pub mod io; pub mod net; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index d53ea16005fab..270eca37b14d6 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -95,7 +95,7 @@ static HEAP: AtomicPtr = AtomicPtr::new(ptr::null_mut()); #[inline] fn init_or_get_process_heap() -> c::HANDLE { let heap = HEAP.load(Ordering::Relaxed); - if heap.is_null() { + if core::intrinsics::unlikely(heap.is_null()) { // `HEAP` has not yet been successfully initialized let heap = unsafe { GetProcessHeap() }; if !heap.is_null() { @@ -115,6 +115,16 @@ fn init_or_get_process_heap() -> c::HANDLE { } } +#[inline(never)] +fn process_heap_alloc(flags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID { + let heap = init_or_get_process_heap(); + if core::intrinsics::unlikely(heap.is_null()) { + return ptr::null_mut(); + } + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. + unsafe { HeapAlloc(heap, flags, dwBytes) } +} + // Get a non-null handle to the default heap of the current process. // SAFETY: `HEAP` must have been successfully initialized. #[inline] @@ -133,25 +143,17 @@ struct Header(*mut u8); // initialized. #[inline] unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 { - let heap = init_or_get_process_heap(); - if heap.is_null() { - // Allocation has failed, could not get the current process heap. - return ptr::null_mut(); - } - // Allocated memory will be either zeroed or uninitialized. let flags = if zeroed { HEAP_ZERO_MEMORY } else { 0 }; if layout.align() <= MIN_ALIGN { - // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. // The returned pointer points to the start of an allocated block. - unsafe { HeapAlloc(heap, flags, layout.size()) as *mut u8 } + process_heap_alloc(flags, layout.size()) as *mut u8 } else { // Allocate extra padding in order to be able to satisfy the alignment. let total = layout.align() + layout.size(); - // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. - let ptr = unsafe { HeapAlloc(heap, flags, total) as *mut u8 }; + let ptr = process_heap_alloc(flags, total) as *mut u8; if ptr.is_null() { // Allocation has failed. return ptr::null_mut(); diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index d55d9bace811c..1a59ac9a9cadf 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -7,17 +7,17 @@ use crate::ffi::CStr; use crate::mem; +use crate::num::NonZero; pub use crate::os::raw::c_int; use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; -use core::ffi::NonZero_c_ulong; mod windows_sys; pub use windows_sys::*; pub type DWORD = c_ulong; -pub type NonZeroDWORD = NonZero_c_ulong; +pub type NonZeroDWORD = NonZero; pub type LARGE_INTEGER = c_longlong; #[cfg_attr(target_vendor = "uwp", allow(unused))] pub type LONG = c_long; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 4248454368644..2bdd3d96fa48c 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -112,6 +112,13 @@ impl fmt::Debug for ReadDir { impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { + if self.handle.0 == c::INVALID_HANDLE_VALUE { + // This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle. + // Simply return `None` because this is only the case when `FindFirstFileW` in + // the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means + // no matchhing files can be found. + return None; + } if let Some(first) = self.first.take() { if let Some(e) = DirEntry::new(&self.root, &first) { return Some(Ok(e)); @@ -1068,6 +1075,7 @@ pub fn readdir(p: &Path) -> io::Result { unsafe { let mut wfd = mem::zeroed(); let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); + if find_handle != c::INVALID_HANDLE_VALUE { Ok(ReadDir { handle: FindNextFileHandle(find_handle), @@ -1075,7 +1083,31 @@ pub fn readdir(p: &Path) -> io::Result { first: Some(wfd), }) } else { - Err(Error::last_os_error()) + // The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function + // if no matching files can be found, but not necessarily that the path to find the + // files in does not exist. + // + // Hence, a check for whether the path to search in exists is added when the last + // os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario. + // If that is the case, an empty `ReadDir` iterator is returned as it returns `None` + // in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been + // returned by the `FindNextFileW` function. + // + // See issue #120040: https://github.com/rust-lang/rust/issues/120040. + let last_error = api::get_last_error(); + if last_error.code == c::ERROR_FILE_NOT_FOUND { + return Ok(ReadDir { + handle: FindNextFileHandle(find_handle), + root: Arc::new(root), + first: None, + }); + } + + // Just return the error constructed from the raw OS error if the above is not the case. + // + // Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function + // when the path to search in does not exist in the first place. + Err(Error::from_raw_os_error(last_error.code as i32)) } } } diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 649826d25cef7..b73d9f3ff4c4a 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -97,20 +97,6 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { return true; } - // At this point, we *could* have a false negative. We can determine that this is a true - // negative if we can detect the presence of a console on any of the standard I/O streams. If - // another stream has a console, then we know we're in a Windows console and can therefore - // trust the negative. - for std_handle in [c::STD_INPUT_HANDLE, c::STD_OUTPUT_HANDLE, c::STD_ERROR_HANDLE] { - let std_handle = c::GetStdHandle(std_handle); - if !std_handle.is_null() - && std_handle != handle - && c::GetConsoleMode(std_handle, &mut out) != 0 - { - return false; - } - } - // Otherwise, we fall back to an msys hack to see if we can detect the presence of a pty. msys_tty_on(handle) } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 8b722f01a5d30..364521dba40ac 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -15,7 +15,6 @@ pub mod compat; pub mod alloc; pub mod args; pub mod c; -pub mod cmath; pub mod env; pub mod fs; pub mod handle; @@ -24,7 +23,6 @@ pub mod locks; pub mod memchr; pub mod net; pub mod os; -pub mod os_str; pub mod path; pub mod pipe; pub mod process; diff --git a/library/std/src/sys/pal/xous/alloc.rs b/library/std/src/sys/pal/xous/alloc.rs index b3a3e691e0d0c..0d540e9552072 100644 --- a/library/std/src/sys/pal/xous/alloc.rs +++ b/library/std/src/sys/pal/xous/alloc.rs @@ -1,7 +1,15 @@ use crate::alloc::{GlobalAlloc, Layout, System}; +#[cfg(not(test))] +#[export_name = "_ZN16__rust_internals3std3sys4xous5alloc8DLMALLOCE"] static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new(); +#[cfg(test)] +extern "Rust" { + #[link_name = "_ZN16__rust_internals3std3sys4xous5alloc8DLMALLOCE"] + static mut DLMALLOC: dlmalloc::Dlmalloc; +} + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] diff --git a/library/std/src/sys/pal/xous/locks/condvar.rs b/library/std/src/sys/pal/xous/locks/condvar.rs index 1bb38dfa34154..510235046e195 100644 --- a/library/std/src/sys/pal/xous/locks/condvar.rs +++ b/library/std/src/sys/pal/xous/locks/condvar.rs @@ -1,14 +1,17 @@ use super::mutex::Mutex; use crate::os::xous::ffi::{blocking_scalar, scalar}; -use crate::os::xous::services::ticktimer_server; -use crate::sync::Mutex as StdMutex; +use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; use crate::time::Duration; +use core::sync::atomic::{AtomicUsize, Ordering}; // The implementation is inspired by Andrew D. Birrell's paper // "Implementing Condition Variables with Semaphores" +const NOTIFY_TRIES: usize = 3; + pub struct Condvar { - counter: StdMutex, + counter: AtomicUsize, + timed_out: AtomicUsize, } unsafe impl Send for Condvar {} @@ -18,94 +21,128 @@ impl Condvar { #[inline] #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Condvar { - Condvar { counter: StdMutex::new(0) } + Condvar { counter: AtomicUsize::new(0), timed_out: AtomicUsize::new(0) } } - pub fn notify_one(&self) { - let mut counter = self.counter.lock().unwrap(); - if *counter <= 0 { + fn notify_some(&self, to_notify: usize) { + // Assumption: The Mutex protecting this condvar is locked throughout the + // entirety of this call, preventing calls to `wait` and `wait_timeout`. + + // Logic check: Ensure that there aren't any missing waiters. Remove any that + // timed-out, ensuring the counter doesn't underflow. + assert!(self.timed_out.load(Ordering::Relaxed) <= self.counter.load(Ordering::Relaxed)); + self.counter.fetch_sub(self.timed_out.swap(0, Ordering::Relaxed), Ordering::Relaxed); + + // Figure out how many threads to notify. Note that it is impossible for `counter` + // to increase during this operation because Mutex is locked. However, it is + // possible for `counter` to decrease due to a condvar timing out, in which + // case the corresponding `timed_out` will increase accordingly. + let Ok(waiter_count) = + self.counter.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |counter| { + if counter == 0 { + return None; + } else { + Some(counter - counter.min(to_notify)) + } + }) + else { + // No threads are waiting on this condvar return; - } else { - *counter -= 1; - } - let result = blocking_scalar( - ticktimer_server(), - crate::os::xous::services::TicktimerScalar::NotifyCondition(self.index(), 1).into(), - ); - drop(counter); - result.expect("failure to send NotifyCondition command"); - } + }; - pub fn notify_all(&self) { - let mut counter = self.counter.lock().unwrap(); - if *counter <= 0 { + let mut remaining_to_wake = waiter_count.min(to_notify); + if remaining_to_wake == 0 { return; } - let result = blocking_scalar( - ticktimer_server(), - crate::os::xous::services::TicktimerScalar::NotifyCondition(self.index(), *counter) - .into(), - ); - *counter = 0; - drop(counter); + for _wake_tries in 0..NOTIFY_TRIES { + let result = blocking_scalar( + ticktimer_server(), + TicktimerScalar::NotifyCondition(self.index(), remaining_to_wake).into(), + ) + .expect("failure to send NotifyCondition command"); + + // Remove the list of waiters that were notified + remaining_to_wake -= result[0]; + + // Also remove the number of waiters that timed out. Clamp it to 0 in order to + // ensure we don't wait forever in case the waiter woke up between the time + // we counted the remaining waiters and now. + remaining_to_wake = + remaining_to_wake.saturating_sub(self.timed_out.swap(0, Ordering::Relaxed)); + if remaining_to_wake == 0 { + return; + } + crate::thread::yield_now(); + } + } - result.expect("failure to send NotifyCondition command"); + pub fn notify_one(&self) { + self.notify_some(1) + } + + pub fn notify_all(&self) { + self.notify_some(self.counter.load(Ordering::Relaxed)) } fn index(&self) -> usize { - self as *const Condvar as usize + core::ptr::from_ref(self).addr() } - pub unsafe fn wait(&self, mutex: &Mutex) { - let mut counter = self.counter.lock().unwrap(); - *counter += 1; + /// Unlock the given Mutex and wait for the notification. Wait at most + /// `ms` milliseconds, or pass `0` to wait forever. + /// + /// Returns `true` if the condition was received, `false` if it timed out + fn wait_ms(&self, mutex: &Mutex, ms: usize) -> bool { + self.counter.fetch_add(1, Ordering::Relaxed); unsafe { mutex.unlock() }; - drop(counter); + // Threading concern: There is a chance that the `notify` thread wakes up here before + // we have a chance to wait for the condition. This is fine because we've recorded + // the fact that we're waiting by incrementing the counter. let result = blocking_scalar( ticktimer_server(), - crate::os::xous::services::TicktimerScalar::WaitForCondition(self.index(), 0).into(), + TicktimerScalar::WaitForCondition(self.index(), ms).into(), ); + let awoken = result.expect("Ticktimer: failure to send WaitForCondition command")[0] == 0; + + // If we awoke due to a timeout, increment the `timed_out` counter so that the + // main loop of `notify` knows there's a timeout. + // + // This is done with the Mutex still unlocked, because the Mutex might still + // be locked by the `notify` process above. + if !awoken { + self.timed_out.fetch_add(1, Ordering::Relaxed); + } + unsafe { mutex.lock() }; + awoken + } - result.expect("Ticktimer: failure to send WaitForCondition command"); + pub unsafe fn wait(&self, mutex: &Mutex) { + // Wait for 0 ms, which is a special case to "wait forever" + self.wait_ms(mutex, 0); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let mut counter = self.counter.lock().unwrap(); - *counter += 1; - unsafe { mutex.unlock() }; - drop(counter); - let mut millis = dur.as_millis() as usize; + // Ensure we don't wait for 0 ms, which would cause us to wait forever if millis == 0 { millis = 1; } - - let result = blocking_scalar( - ticktimer_server(), - crate::os::xous::services::TicktimerScalar::WaitForCondition(self.index(), millis) - .into(), - ); - unsafe { mutex.lock() }; - - let result = result.expect("Ticktimer: failure to send WaitForCondition command")[0] == 0; - - // If we awoke due to a timeout, decrement the wake count, as that would not have - // been done in the `notify()` call. - if !result { - *self.counter.lock().unwrap() -= 1; - } - result + self.wait_ms(mutex, millis) } } impl Drop for Condvar { fn drop(&mut self) { - scalar( - ticktimer_server(), - crate::os::xous::services::TicktimerScalar::FreeCondition(self.index()).into(), - ) - .ok(); + let remaining_count = self.counter.load(Ordering::Relaxed); + let timed_out = self.timed_out.load(Ordering::Relaxed); + assert!( + remaining_count - timed_out == 0, + "counter was {} and timed_out was {} not 0", + remaining_count, + timed_out + ); + scalar(ticktimer_server(), TicktimerScalar::FreeCondition(self.index()).into()).ok(); } } diff --git a/library/std/src/sys/pal/xous/locks/mutex.rs b/library/std/src/sys/pal/xous/locks/mutex.rs index ea51776d54eca..a8c9518ff0bcf 100644 --- a/library/std/src/sys/pal/xous/locks/mutex.rs +++ b/library/std/src/sys/pal/xous/locks/mutex.rs @@ -1,5 +1,5 @@ -use crate::os::xous::ffi::{blocking_scalar, do_yield, scalar}; -use crate::os::xous::services::ticktimer_server; +use crate::os::xous::ffi::{blocking_scalar, do_yield}; +use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed, Ordering::SeqCst}; pub struct Mutex { @@ -29,7 +29,7 @@ impl Mutex { } fn index(&self) -> usize { - self as *const Mutex as usize + core::ptr::from_ref(self).addr() } #[inline] @@ -83,11 +83,8 @@ impl Mutex { } // Unblock one thread that is waiting on this message. - scalar( - ticktimer_server(), - crate::os::xous::services::TicktimerScalar::UnlockMutex(self.index()).into(), - ) - .expect("failure to send UnlockMutex command"); + blocking_scalar(ticktimer_server(), TicktimerScalar::UnlockMutex(self.index()).into()) + .expect("failure to send UnlockMutex command"); } #[inline] @@ -106,11 +103,8 @@ impl Drop for Mutex { // If there was Mutex contention, then we involved the ticktimer. Free // the resources associated with this Mutex as it is deallocated. if self.contended.load(Relaxed) { - scalar( - ticktimer_server(), - crate::os::xous::services::TicktimerScalar::FreeMutex(self.index()).into(), - ) - .ok(); + blocking_scalar(ticktimer_server(), TicktimerScalar::FreeMutex(self.index()).into()) + .ok(); } } } diff --git a/library/std/src/sys/pal/xous/locks/rwlock.rs b/library/std/src/sys/pal/xous/locks/rwlock.rs index 618da758adfa7..ab45b33e1f69b 100644 --- a/library/std/src/sys/pal/xous/locks/rwlock.rs +++ b/library/std/src/sys/pal/xous/locks/rwlock.rs @@ -1,5 +1,5 @@ -use crate::os::xous::ffi::do_yield; -use crate::sync::atomic::{AtomicIsize, Ordering::SeqCst}; +use crate::sync::atomic::{AtomicIsize, Ordering::Acquire}; +use crate::thread::yield_now; pub struct RwLock { /// The "mode" value indicates how many threads are waiting on this @@ -14,6 +14,9 @@ pub struct RwLock { mode: AtomicIsize, } +const RWLOCK_WRITING: isize = -1; +const RWLOCK_FREE: isize = 0; + unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} @@ -21,52 +24,51 @@ impl RwLock { #[inline] #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> RwLock { - RwLock { mode: AtomicIsize::new(0) } + RwLock { mode: AtomicIsize::new(RWLOCK_FREE) } } #[inline] pub unsafe fn read(&self) { while !unsafe { self.try_read() } { - do_yield(); + yield_now(); } } #[inline] pub unsafe fn try_read(&self) -> bool { - // Non-atomically determine the current value. - let current = self.mode.load(SeqCst); - - // If it's currently locked for writing, then we cannot read. - if current < 0 { - return false; - } - - // Attempt to lock. If the `current` value has changed, then this - // operation will fail and we will not obtain the lock even if we - // could potentially keep it. - let new = current + 1; - self.mode.compare_exchange(current, new, SeqCst, SeqCst).is_ok() + self.mode + .fetch_update( + Acquire, + Acquire, + |v| if v == RWLOCK_WRITING { None } else { Some(v + 1) }, + ) + .is_ok() } #[inline] pub unsafe fn write(&self) { while !unsafe { self.try_write() } { - do_yield(); + yield_now(); } } #[inline] pub unsafe fn try_write(&self) -> bool { - self.mode.compare_exchange(0, -1, SeqCst, SeqCst).is_ok() + self.mode.compare_exchange(RWLOCK_FREE, RWLOCK_WRITING, Acquire, Acquire).is_ok() } #[inline] pub unsafe fn read_unlock(&self) { - self.mode.fetch_sub(1, SeqCst); + let previous = self.mode.fetch_sub(1, Acquire); + assert!(previous != RWLOCK_FREE); + assert!(previous != RWLOCK_WRITING); } #[inline] pub unsafe fn write_unlock(&self) { - assert_eq!(self.mode.compare_exchange(-1, 0, SeqCst, SeqCst), Ok(-1)); + assert_eq!( + self.mode.compare_exchange(RWLOCK_WRITING, RWLOCK_FREE, Acquire, Acquire), + Ok(RWLOCK_WRITING) + ); } } diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index c2550dcfd8315..b4948d7e583b4 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -3,8 +3,6 @@ pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; #[path = "../unsupported/env.rs"] pub mod env; #[path = "../unsupported/fs.rs"] @@ -12,13 +10,8 @@ pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; pub mod locks; -#[path = "../unsupported/net.rs"] pub mod net; -#[path = "../unsupported/once.rs"] -pub mod once; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs new file mode 100644 index 0000000000000..63056324bfbd9 --- /dev/null +++ b/library/std/src/sys/pal/xous/net/dns.rs @@ -0,0 +1,127 @@ +use crate::io; +use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::os::xous::ffi::lend_mut; +use crate::os::xous::services::{dns_server, DnsLendMut}; +use core::convert::{TryFrom, TryInto}; + +pub struct DnsError { + pub code: u8, +} + +#[repr(C, align(4096))] +struct LookupHostQuery([u8; 4096]); + +pub struct LookupHost { + data: LookupHostQuery, + port: u16, + offset: usize, + count: usize, +} + +impl LookupHost { + pub fn port(&self) -> u16 { + self.port + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + if self.offset >= self.data.0.len() { + return None; + } + match self.data.0.get(self.offset) { + Some(&4) => { + self.offset += 1; + if self.offset + 4 > self.data.0.len() { + return None; + } + let result = Some(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new( + self.data.0[self.offset], + self.data.0[self.offset + 1], + self.data.0[self.offset + 2], + self.data.0[self.offset + 3], + ), + self.port, + ))); + self.offset += 4; + result + } + Some(&6) => { + self.offset += 1; + if self.offset + 16 > self.data.0.len() { + return None; + } + let mut new_addr = [0u8; 16]; + for (src, octet) in self.data.0[(self.offset + 1)..(self.offset + 16 + 1)] + .iter() + .zip(new_addr.iter_mut()) + { + *octet = *src; + } + let result = + Some(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.port, 0, 0))); + self.offset += 16; + result + } + _ => None, + } + } +} + +pub fn lookup(query: &str, port: u16) -> Result { + let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port }; + + // Copy the query into the message that gets sent to the DNS server + for (query_byte, result_byte) in query.as_bytes().iter().zip(result.data.0.iter_mut()) { + *result_byte = *query_byte; + } + + lend_mut( + dns_server(), + DnsLendMut::RawLookup.into(), + &mut result.data.0, + 0, + query.as_bytes().len(), + ) + .unwrap(); + if result.data.0[0] != 0 { + return Err(DnsError { code: result.data.0[1] }); + } + assert_eq!(result.offset, 0); + result.count = result.data.0[1] as usize; + + // Advance the offset to the first record + result.offset = 2; + Ok(result) +} + +impl TryFrom<&str> for LookupHost { + type Error = io::Error; + + fn try_from(s: &str) -> io::Result { + macro_rules! try_opt { + ($e:expr, $msg:expr) => { + match $e { + Some(r) => r, + None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)), + } + }; + } + + // split the string by ':' and convert the second part to u16 + let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); + let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); + (host, port).try_into() + } +} + +impl TryFrom<(&str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(v: (&str, u16)) -> io::Result { + lookup(v.0, v.1) + .map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure")) + } +} diff --git a/library/std/src/sys/pal/xous/net/mod.rs b/library/std/src/sys/pal/xous/net/mod.rs new file mode 100644 index 0000000000000..dd8b765aa74ae --- /dev/null +++ b/library/std/src/sys/pal/xous/net/mod.rs @@ -0,0 +1,81 @@ +mod dns; + +mod tcpstream; +pub use tcpstream::*; + +mod tcplistener; +pub use tcplistener::*; + +mod udp; +pub use udp::*; + +// this structure needs to be synchronized with what's in net/src/api.rs +#[repr(C)] +#[derive(Debug)] +enum NetError { + // Ok = 0, + Unaddressable = 1, + SocketInUse = 2, + // AccessDenied = 3, + Invalid = 4, + // Finished = 5, + LibraryError = 6, + // AlreadyUsed = 7, + TimedOut = 8, + WouldBlock = 9, +} + +#[repr(C, align(4096))] +struct ConnectRequest { + raw: [u8; 4096], +} + +#[repr(C, align(4096))] +struct SendData { + raw: [u8; 4096], +} + +#[repr(C, align(4096))] +pub struct ReceiveData { + raw: [u8; 4096], +} + +#[repr(C, align(4096))] +pub struct GetAddress { + raw: [u8; 4096], +} + +pub use dns::LookupHost; + +#[allow(nonstandard_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } +} diff --git a/library/std/src/sys/pal/xous/net/tcplistener.rs b/library/std/src/sys/pal/xous/net/tcplistener.rs new file mode 100644 index 0000000000000..47305013083c8 --- /dev/null +++ b/library/std/src/sys/pal/xous/net/tcplistener.rs @@ -0,0 +1,247 @@ +use super::*; +use crate::fmt; +use crate::io; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use crate::os::xous::services; +use crate::sync::Arc; +use core::convert::TryInto; +use core::sync::atomic::{AtomicBool, AtomicU16, AtomicUsize, Ordering}; + +macro_rules! unimpl { + () => { + return Err(io::const_io_error!( + io::ErrorKind::Unsupported, + &"This function is not yet implemented", + )); + }; +} + +#[derive(Clone)] +pub struct TcpListener { + fd: Arc, + local: SocketAddr, + handle_count: Arc, + nonblocking: Arc, +} + +impl TcpListener { + pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result { + let mut addr = *socketaddr?; + + let fd = TcpListener::bind_inner(&mut addr)?; + return Ok(TcpListener { + fd: Arc::new(AtomicU16::new(fd)), + local: addr, + handle_count: Arc::new(AtomicUsize::new(1)), + nonblocking: Arc::new(AtomicBool::new(false)), + }); + } + + /// This returns the raw fd of a Listener, so that it can also be used by the + /// accept routine to replenish the Listener object after its handle has been converted into + /// a TcpStream object. + fn bind_inner(addr: &mut SocketAddr) -> io::Result { + // Construct the request + let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; + + // Serialize the StdUdpBind structure. This is done "manually" because we don't want to + // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous. + let port_bytes = addr.port().to_le_bytes(); + connect_request.raw[0] = port_bytes[0]; + connect_request.raw[1] = port_bytes[1]; + match addr.ip() { + IpAddr::V4(addr) => { + connect_request.raw[2] = 4; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + IpAddr::V6(addr) => { + connect_request.raw[2] = 6; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + } + + let Ok((_, valid)) = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdTcpListen.into(), + &mut connect_request.raw, + 0, + 4096, + ) else { + return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")); + }; + + // The first four bytes should be zero upon success, and will be nonzero + // for an error. + let response = connect_request.raw; + if response[0] != 0 || valid == 0 { + let errcode = response[1]; + if errcode == NetError::SocketInUse as u8 { + return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); + } else if errcode == NetError::Invalid as u8 { + return Err(io::const_io_error!( + io::ErrorKind::AddrNotAvailable, + &"Invalid address" + )); + } else if errcode == NetError::LibraryError as u8 { + return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + } else { + return Err(io::const_io_error!( + io::ErrorKind::Other, + &"Unable to connect or internal error" + )); + } + } + let fd = response[1] as usize; + if addr.port() == 0 { + // oddly enough, this is a valid port and it means "give me something valid, up to you what that is" + let assigned_port = u16::from_le_bytes(response[2..4].try_into().unwrap()); + addr.set_port(assigned_port); + } + // println!("TcpListening with file handle of {}\r\n", fd); + Ok(fd.try_into().unwrap()) + } + + pub fn socket_addr(&self) -> io::Result { + Ok(self.local) + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + let mut receive_request = ReceiveData { raw: [0u8; 4096] }; + + if self.nonblocking.load(Ordering::Relaxed) { + // nonblocking + receive_request.raw[0] = 0; + } else { + // blocking + receive_request.raw[0] = 1; + } + + if let Ok((_offset, _valid)) = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdTcpAccept(self.fd.load(Ordering::Relaxed)).into(), + &mut receive_request.raw, + 0, + 0, + ) { + if receive_request.raw[0] != 0 { + // error case + if receive_request.raw[1] == NetError::TimedOut as u8 { + return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"accept timed out",)); + } else if receive_request.raw[1] == NetError::WouldBlock as u8 { + return Err(io::const_io_error!( + io::ErrorKind::WouldBlock, + &"accept would block", + )); + } else if receive_request.raw[1] == NetError::LibraryError as u8 { + return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + } else { + return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + } + } else { + // accept successful + let rr = &receive_request.raw; + let stream_fd = u16::from_le_bytes(rr[1..3].try_into().unwrap()); + let port = u16::from_le_bytes(rr[20..22].try_into().unwrap()); + let addr = if rr[3] == 4 { + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(rr[4], rr[5], rr[6], rr[7])), port) + } else if rr[3] == 6 { + SocketAddr::new( + IpAddr::V6(Ipv6Addr::new( + u16::from_be_bytes(rr[4..6].try_into().unwrap()), + u16::from_be_bytes(rr[6..8].try_into().unwrap()), + u16::from_be_bytes(rr[8..10].try_into().unwrap()), + u16::from_be_bytes(rr[10..12].try_into().unwrap()), + u16::from_be_bytes(rr[12..14].try_into().unwrap()), + u16::from_be_bytes(rr[14..16].try_into().unwrap()), + u16::from_be_bytes(rr[16..18].try_into().unwrap()), + u16::from_be_bytes(rr[18..20].try_into().unwrap()), + )), + port, + ) + } else { + return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + }; + + // replenish the listener + let mut local_copy = self.local.clone(); // port is non-0 by this time, but the method signature needs a mut + let new_fd = TcpListener::bind_inner(&mut local_copy)?; + self.fd.store(new_fd, Ordering::Relaxed); + + // now return a stream converted from the old stream's fd + Ok((TcpStream::from_listener(stream_fd, self.local.port(), port, addr), addr)) + } + } else { + Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unable to accept")) + } + } + + pub fn duplicate(&self) -> io::Result { + self.handle_count.fetch_add(1, Ordering::Relaxed); + Ok(self.clone()) + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + if ttl > 255 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "TTL must be less than 256")); + } + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdSetTtlTcp(self.fd.load(Ordering::Relaxed), ttl).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|_| ()) + } + + pub fn ttl(&self) -> io::Result { + Ok(crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdGetTtlTcp(self.fd.load(Ordering::Relaxed)).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|res| res[0] as _)?) + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + unimpl!(); + } + + pub fn only_v6(&self) -> io::Result { + unimpl!(); + } + + pub fn take_error(&self) -> io::Result> { + // this call doesn't have a meaning on our platform, but we can at least not panic if it's used. + Ok(None) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.nonblocking.store(nonblocking, Ordering::Relaxed); + Ok(()) + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TCP listening on {:?}", self.local) + } +} + +impl Drop for TcpListener { + fn drop(&mut self) { + if self.handle_count.fetch_sub(1, Ordering::Relaxed) == 1 { + // only drop if we're the last clone + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + crate::os::xous::services::NetBlockingScalar::StdTcpClose( + self.fd.load(Ordering::Relaxed), + ) + .into(), + ) + .unwrap(); + } + } +} diff --git a/library/std/src/sys/pal/xous/net/tcpstream.rs b/library/std/src/sys/pal/xous/net/tcpstream.rs new file mode 100644 index 0000000000000..7149678118ab6 --- /dev/null +++ b/library/std/src/sys/pal/xous/net/tcpstream.rs @@ -0,0 +1,435 @@ +use super::*; +use crate::fmt; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::os::xous::services; +use crate::sync::Arc; +use crate::time::Duration; +use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; + +macro_rules! unimpl { + () => { + return Err(io::const_io_error!( + io::ErrorKind::Unsupported, + &"This function is not yet implemented", + )); + }; +} + +enum ReadOrPeek { + Read, + Peek, +} + +#[derive(Clone)] +pub struct TcpStream { + fd: u16, + local_port: u16, + remote_port: u16, + peer_addr: SocketAddr, + // milliseconds + read_timeout: Arc, + // milliseconds + write_timeout: Arc, + handle_count: Arc, + nonblocking: Arc, +} + +fn sockaddr_to_buf(duration: Duration, addr: &SocketAddr, buf: &mut [u8]) { + // Construct the request. + let port_bytes = addr.port().to_le_bytes(); + buf[0] = port_bytes[0]; + buf[1] = port_bytes[1]; + for (dest, src) in buf[2..].iter_mut().zip((duration.as_millis() as u64).to_le_bytes()) { + *dest = src; + } + match addr.ip() { + IpAddr::V4(addr) => { + buf[10] = 4; + for (dest, src) in buf[11..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + IpAddr::V6(addr) => { + buf[10] = 6; + for (dest, src) in buf[11..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + } +} + +impl TcpStream { + pub(crate) fn from_listener( + fd: u16, + local_port: u16, + remote_port: u16, + peer_addr: SocketAddr, + ) -> TcpStream { + TcpStream { + fd, + local_port, + remote_port, + peer_addr, + read_timeout: Arc::new(AtomicU32::new(0)), + write_timeout: Arc::new(AtomicU32::new(0)), + handle_count: Arc::new(AtomicUsize::new(1)), + nonblocking: Arc::new(AtomicBool::new(false)), + } + } + + pub fn connect(socketaddr: io::Result<&SocketAddr>) -> io::Result { + Self::connect_timeout(socketaddr?, Duration::ZERO) + } + + pub fn connect_timeout(addr: &SocketAddr, duration: Duration) -> io::Result { + let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; + + // Construct the request. + sockaddr_to_buf(duration, &addr, &mut connect_request.raw); + + let Ok((_, valid)) = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdTcpConnect.into(), + &mut connect_request.raw, + 0, + 4096, + ) else { + return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")); + }; + + // The first four bytes should be zero upon success, and will be nonzero + // for an error. + let response = connect_request.raw; + if response[0] != 0 || valid == 0 { + // 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_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use",)); + } else if errcode == NetError::Unaddressable as u8 { + return Err(io::const_io_error!( + io::ErrorKind::AddrNotAvailable, + &"Invalid address", + )); + } else { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Unable to connect or internal error", + )); + } + } + let fd = u16::from_le_bytes([response[2], response[3]]); + let local_port = u16::from_le_bytes([response[4], response[5]]); + let remote_port = u16::from_le_bytes([response[6], response[7]]); + // println!( + // "Connected with local port of {}, remote port of {}, file handle of {}", + // local_port, remote_port, fd + // ); + Ok(TcpStream { + fd, + local_port, + remote_port, + peer_addr: *addr, + read_timeout: Arc::new(AtomicU32::new(0)), + write_timeout: Arc::new(AtomicU32::new(0)), + handle_count: Arc::new(AtomicUsize::new(1)), + nonblocking: Arc::new(AtomicBool::new(false)), + }) + } + + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + if let Some(to) = timeout { + if to.is_zero() { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Zero is an invalid timeout", + )); + } + } + self.read_timeout.store( + timeout.map(|t| t.as_millis().min(u32::MAX as u128) as u32).unwrap_or_default(), + Ordering::Relaxed, + ); + Ok(()) + } + + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + if let Some(to) = timeout { + if to.is_zero() { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Zero is an invalid timeout", + )); + } + } + self.write_timeout.store( + timeout.map(|t| t.as_millis().min(u32::MAX as u128) as u32).unwrap_or_default(), + Ordering::Relaxed, + ); + Ok(()) + } + + pub fn read_timeout(&self) -> io::Result> { + match self.read_timeout.load(Ordering::Relaxed) { + 0 => Ok(None), + t => Ok(Some(Duration::from_millis(t as u64))), + } + } + + pub fn write_timeout(&self) -> io::Result> { + match self.write_timeout.load(Ordering::Relaxed) { + 0 => Ok(None), + t => Ok(Some(Duration::from_millis(t as u64))), + } + } + + fn read_or_peek(&self, buf: &mut [u8], op: ReadOrPeek) -> io::Result { + let mut receive_request = ReceiveData { raw: [0u8; 4096] }; + let data_to_read = buf.len().min(receive_request.raw.len()); + + let opcode = match op { + ReadOrPeek::Read => { + services::NetLendMut::StdTcpRx(self.fd, self.nonblocking.load(Ordering::Relaxed)) + } + ReadOrPeek::Peek => { + services::NetLendMut::StdTcpPeek(self.fd, self.nonblocking.load(Ordering::Relaxed)) + } + }; + + let Ok((offset, length)) = crate::os::xous::ffi::lend_mut( + services::net_server(), + opcode.into(), + &mut receive_request.raw, + // Reuse the `offset` as the read timeout + self.read_timeout.load(Ordering::Relaxed) as usize, + data_to_read, + ) else { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Library failure: wrong message type or messaging error" + )); + }; + + if offset != 0 { + for (dest, src) in buf.iter_mut().zip(receive_request.raw[..length].iter()) { + *dest = *src; + } + Ok(length) + } else { + let result = receive_request.raw; + if result[0] != 0 { + if result[1] == 8 { + // timed out + return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"Timeout",)); + } + if result[1] == 9 { + // would block + return Err(io::const_io_error!(io::ErrorKind::WouldBlock, &"Would block",)); + } + } + Err(io::const_io_error!(io::ErrorKind::Other, &"recv_slice failure")) + } + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.read_or_peek(buf, ReadOrPeek::Peek) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.read_or_peek(buf, ReadOrPeek::Read) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|b| self.read(b), bufs) + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) + } + + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let mut send_request = SendData { raw: [0u8; 4096] }; + for (dest, src) in send_request.raw.iter_mut().zip(buf) { + *dest = *src; + } + let buf_len = send_request.raw.len().min(buf.len()); + + let (_offset, _valid) = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdTcpTx(self.fd).into(), + &mut send_request.raw, + // Reuse the offset as the timeout + self.write_timeout.load(Ordering::Relaxed) as usize, + buf_len, + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")))?; + + if send_request.raw[0] != 0 { + if send_request.raw[4] == 8 { + // timed out + return Err(io::const_io_error!( + io::ErrorKind::BrokenPipe, + &"Timeout or connection closed", + )); + } else if send_request.raw[4] == 9 { + // would block + return Err(io::const_io_error!(io::ErrorKind::WouldBlock, &"Would block",)); + } else { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Error when sending", + )); + } + } + Ok(u32::from_le_bytes([ + send_request.raw[4], + send_request.raw[5], + send_request.raw[6], + send_request.raw[7], + ]) as usize) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn peer_addr(&self) -> io::Result { + Ok(self.peer_addr) + } + + pub fn socket_addr(&self) -> io::Result { + let mut get_addr = GetAddress { raw: [0u8; 4096] }; + + let Ok((_offset, _valid)) = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdGetAddress(self.fd).into(), + &mut get_addr.raw, + 0, + 0, + ) else { + return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")); + }; + let mut i = get_addr.raw.iter(); + match *i.next().unwrap() { + 4 => Ok(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new( + *i.next().unwrap(), + *i.next().unwrap(), + *i.next().unwrap(), + *i.next().unwrap(), + ), + self.local_port, + ))), + 6 => { + let mut new_addr = [0u8; 16]; + for (src, octet) in i.zip(new_addr.iter_mut()) { + *octet = *src; + } + Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0))) + } + _ => Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")), + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdTcpStreamShutdown(self.fd, how).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|_| ()) + } + + pub fn duplicate(&self) -> io::Result { + self.handle_count.fetch_add(1, Ordering::Relaxed); + Ok(self.clone()) + } + + pub fn set_linger(&self, _: Option) -> io::Result<()> { + unimpl!(); + } + + pub fn linger(&self) -> io::Result> { + unimpl!(); + } + + pub fn set_nodelay(&self, enabled: bool) -> io::Result<()> { + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdSetNodelay(self.fd, enabled).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|_| ()) + } + + pub fn nodelay(&self) -> io::Result { + Ok(crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdGetNodelay(self.fd).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|res| res[0] != 0)?) + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + if ttl > 255 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "TTL must be less than 256")); + } + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdSetTtlTcp(self.fd, ttl).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|_| ()) + } + + pub fn ttl(&self) -> io::Result { + Ok(crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdGetTtlTcp(self.fd).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|res| res[0] as _)?) + } + + pub fn take_error(&self) -> io::Result> { + // this call doesn't have a meaning on our platform, but we can at least not panic if it's used. + Ok(None) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.nonblocking.store(nonblocking, Ordering::SeqCst); + Ok(()) + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "TCP connection to {:?} port {} to local port {}", + self.peer_addr, self.remote_port, self.local_port + ) + } +} + +impl Drop for TcpStream { + fn drop(&mut self) { + if self.handle_count.fetch_sub(1, Ordering::Relaxed) == 1 { + // only drop if we're the last clone + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdTcpClose(self.fd).into(), + ) + .unwrap(); + } + } +} diff --git a/library/std/src/sys/pal/xous/net/udp.rs b/library/std/src/sys/pal/xous/net/udp.rs new file mode 100644 index 0000000000000..cafa5b3bde829 --- /dev/null +++ b/library/std/src/sys/pal/xous/net/udp.rs @@ -0,0 +1,471 @@ +use super::*; +use crate::cell::Cell; +use crate::fmt; +use crate::io; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use crate::os::xous::services; +use crate::sync::Arc; +use crate::time::Duration; +use core::convert::TryInto; +use core::sync::atomic::{AtomicUsize, Ordering}; + +macro_rules! unimpl { + () => { + return Err(io::const_io_error!( + io::ErrorKind::Unsupported, + &"This function is not yet implemented", + )); + }; +} + +#[derive(Clone)] +pub struct UdpSocket { + fd: u16, + local: SocketAddr, + remote: Cell>, + // in milliseconds. The setting applies only to `recv` calls after the timeout is set. + read_timeout: Cell, + // in milliseconds. The setting applies only to `send` calls after the timeout is set. + write_timeout: Cell, + handle_count: Arc, + nonblocking: Cell, +} + +impl UdpSocket { + pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result { + let addr = socketaddr?; + // Construct the request + let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; + + // Serialize the StdUdpBind structure. This is done "manually" because we don't want to + // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous. + let port_bytes = addr.port().to_le_bytes(); + connect_request.raw[0] = port_bytes[0]; + connect_request.raw[1] = port_bytes[1]; + match addr.ip() { + IpAddr::V4(addr) => { + connect_request.raw[2] = 4; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + IpAddr::V6(addr) => { + connect_request.raw[2] = 6; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + } + + let response = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdUdpBind.into(), + &mut connect_request.raw, + 0, + 4096, + ); + + if let Ok((_, valid)) = response { + // The first four bytes should be zero upon success, and will be nonzero + // for an error. + let response = connect_request.raw; + if response[0] != 0 || valid == 0 { + let errcode = response[1]; + if errcode == NetError::SocketInUse as u8 { + return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); + } else if errcode == NetError::Invalid as u8 { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Port can't be 0 or invalid address" + )); + } else if errcode == NetError::LibraryError as u8 { + return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + } else { + return Err(io::const_io_error!( + io::ErrorKind::Other, + &"Unable to connect or internal error" + )); + } + } + let fd = response[1] as u16; + return Ok(UdpSocket { + fd, + local: *addr, + remote: Cell::new(None), + read_timeout: Cell::new(0), + write_timeout: Cell::new(0), + handle_count: Arc::new(AtomicUsize::new(1)), + nonblocking: Cell::new(false), + }); + } + Err(io::const_io_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_io_error!(io::ErrorKind::NotConnected, &"No peer specified")), + } + } + + pub fn socket_addr(&self) -> io::Result { + Ok(self.local) + } + + fn recv_inner(&self, buf: &mut [u8], do_peek: bool) -> io::Result<(usize, SocketAddr)> { + let mut receive_request = ReceiveData { raw: [0u8; 4096] }; + + if self.nonblocking.get() { + // nonblocking + receive_request.raw[0] = 0; + } else { + // blocking + receive_request.raw[0] = 1; + for (&s, d) in self + .read_timeout + .get() + .to_le_bytes() + .iter() + .zip(receive_request.raw[1..9].iter_mut()) + { + *d = s; + } + } + if let Ok((_offset, _valid)) = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdUdpRx(self.fd).into(), + &mut receive_request.raw, + if do_peek { 1 } else { 0 }, + 0, + ) { + if receive_request.raw[0] != 0 { + // error case + if receive_request.raw[1] == NetError::TimedOut as u8 { + return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"recv timed out",)); + } else if receive_request.raw[1] == NetError::WouldBlock as u8 { + return Err(io::const_io_error!( + io::ErrorKind::WouldBlock, + &"recv would block", + )); + } else if receive_request.raw[1] == NetError::LibraryError as u8 { + return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + } else { + return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + } + } else { + let rr = &receive_request.raw; + let rxlen = u16::from_le_bytes(rr[1..3].try_into().unwrap()); + let port = u16::from_le_bytes(rr[20..22].try_into().unwrap()); + let addr = if rr[3] == 4 { + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(rr[4], rr[5], rr[6], rr[7])), port) + } else if rr[3] == 6 { + SocketAddr::new( + IpAddr::V6(Ipv6Addr::new( + u16::from_be_bytes(rr[4..6].try_into().unwrap()), + u16::from_be_bytes(rr[6..8].try_into().unwrap()), + u16::from_be_bytes(rr[8..10].try_into().unwrap()), + u16::from_be_bytes(rr[10..12].try_into().unwrap()), + u16::from_be_bytes(rr[12..14].try_into().unwrap()), + u16::from_be_bytes(rr[14..16].try_into().unwrap()), + u16::from_be_bytes(rr[16..18].try_into().unwrap()), + u16::from_be_bytes(rr[18..20].try_into().unwrap()), + )), + port, + ) + } else { + return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + }; + for (&s, d) in rr[22..22 + rxlen as usize].iter().zip(buf.iter_mut()) { + *d = s; + } + Ok((rxlen as usize, addr)) + } + } else { + Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unable to recv")) + } + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_inner(buf, false) + } + + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + self.recv_from(buf).map(|(len, _addr)| len) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_inner(buf, true) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.peek_from(buf).map(|(len, _addr)| len) + } + + pub fn connect(&self, maybe_addr: io::Result<&SocketAddr>) -> io::Result<()> { + let addr = maybe_addr?; + self.remote.set(Some(*addr)); + Ok(()) + } + + pub fn send(&self, buf: &[u8]) -> io::Result { + if let Some(addr) = self.remote.get() { + self.send_to(buf, &addr) + } else { + Err(io::const_io_error!(io::ErrorKind::NotConnected, &"No remote specified")) + } + } + + pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> io::Result { + let mut tx_req = SendData { raw: [0u8; 4096] }; + + // Construct the request. + let port_bytes = addr.port().to_le_bytes(); + tx_req.raw[0] = port_bytes[0]; + tx_req.raw[1] = port_bytes[1]; + match addr.ip() { + IpAddr::V4(addr) => { + tx_req.raw[2] = 4; + for (dest, src) in tx_req.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + IpAddr::V6(addr) => { + tx_req.raw[2] = 6; + for (dest, src) in tx_req.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } + } + } + let len = buf.len() as u16; + let len_bytes = len.to_le_bytes(); + tx_req.raw[19] = len_bytes[0]; + tx_req.raw[20] = len_bytes[1]; + for (&s, d) in buf.iter().zip(tx_req.raw[21..].iter_mut()) { + *d = s; + } + + // let buf = unsafe { + // xous::MemoryRange::new( + // &mut tx_req as *mut SendData as usize, + // core::mem::size_of::(), + // ) + // .unwrap() + // }; + + // write time-outs are implemented on the caller side. Basically, if the Net crate server + // is too busy to take the call immediately: retry, until the timeout is reached. + let now = crate::time::Instant::now(); + let write_timeout = if self.nonblocking.get() { + // nonblocking + core::time::Duration::ZERO + } else { + // blocking + if self.write_timeout.get() == 0 { + // forever + core::time::Duration::from_millis(u64::MAX) + } else { + // or this amount of time + core::time::Duration::from_millis(self.write_timeout.get()) + } + }; + loop { + let response = crate::os::xous::ffi::try_lend_mut( + services::net_server(), + services::NetLendMut::StdUdpTx(self.fd).into(), + &mut tx_req.raw, + 0, + 4096, + ); + match response { + Ok((_, valid)) => { + let response = &tx_req.raw; + if response[0] != 0 || valid == 0 { + let errcode = response[1]; + if errcode == NetError::SocketInUse as u8 { + return Err(io::const_io_error!( + io::ErrorKind::ResourceBusy, + &"Socket in use" + )); + } else if errcode == NetError::Invalid as u8 { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Socket not valid" + )); + } else if errcode == NetError::LibraryError as u8 { + return Err(io::const_io_error!( + io::ErrorKind::Other, + &"Library error" + )); + } else { + return Err(io::const_io_error!( + io::ErrorKind::Other, + &"Unable to connect" + )); + } + } else { + // no error + return Ok(len as usize); + } + } + Err(crate::os::xous::ffi::Error::ServerQueueFull) => { + if now.elapsed() >= write_timeout { + return Err(io::const_io_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_io_error!(io::ErrorKind::Other, &"Library error")), + } + } + } + + pub fn duplicate(&self) -> io::Result { + self.handle_count.fetch_add(1, Ordering::Relaxed); + Ok(self.clone()) + } + + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + if let Some(d) = timeout { + if d.is_zero() { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Zero duration is invalid" + )); + } + } + self.read_timeout + .set(timeout.map(|t| t.as_millis().min(u64::MAX as u128) as u64).unwrap_or_default()); + Ok(()) + } + + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + if let Some(d) = timeout { + if d.is_zero() { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + &"Zero duration is invalid" + )); + } + } + self.write_timeout + .set(timeout.map(|t| t.as_millis().min(u64::MAX as u128) as u64).unwrap_or_default()); + Ok(()) + } + + pub fn read_timeout(&self) -> io::Result> { + match self.read_timeout.get() { + 0 => Ok(None), + t => Ok(Some(Duration::from_millis(t as u64))), + } + } + + pub fn write_timeout(&self) -> io::Result> { + match self.write_timeout.get() { + 0 => Ok(None), + t => Ok(Some(Duration::from_millis(t as u64))), + } + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + if ttl > 255 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "TTL must be less than 256")); + } + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdSetTtlUdp(self.fd, ttl).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|_| ()) + } + + pub fn ttl(&self) -> io::Result { + Ok(crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdGetTtlUdp(self.fd).into(), + ) + .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .map(|res| res[0] as _)?) + } + + pub fn take_error(&self) -> io::Result> { + // this call doesn't have a meaning on our platform, but we can at least not panic if it's used. + Ok(None) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.nonblocking.set(nonblocking); + Ok(()) + } + + // ------------- smoltcp base stack does not have multicast or broadcast support --------------- + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + unimpl!(); + } + + pub fn broadcast(&self) -> io::Result { + unimpl!(); + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + unimpl!(); + } + + pub fn multicast_loop_v4(&self) -> io::Result { + unimpl!(); + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + unimpl!(); + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + unimpl!(); + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + unimpl!(); + } + + pub fn multicast_loop_v6(&self) -> io::Result { + unimpl!(); + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + unimpl!(); + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + unimpl!(); + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + unimpl!(); + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + unimpl!(); + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "UDP listening on {:?} to {:?}", self.local, self.remote.get(),) + } +} + +impl Drop for UdpSocket { + fn drop(&mut self) { + if self.handle_count.fetch_sub(1, Ordering::Relaxed) == 1 { + // only drop if we're the last clone + crate::os::xous::ffi::blocking_scalar( + services::net_server(), + services::NetBlockingScalar::StdUdpClose(self.fd).into(), + ) + .unwrap(); + } + } +} diff --git a/library/std/src/sys/pal/xous/stdio.rs b/library/std/src/sys/pal/xous/stdio.rs index 2ac694641ba94..11608964b52e6 100644 --- a/library/std/src/sys/pal/xous/stdio.rs +++ b/library/std/src/sys/pal/xous/stdio.rs @@ -5,7 +5,7 @@ pub struct Stdout {} pub struct Stderr; use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection}; -use crate::os::xous::services::{log_server, try_connect, LogScalar}; +use crate::os::xous::services::{log_server, try_connect, LogLend, LogScalar}; impl Stdin { pub const fn new() -> Stdin { @@ -27,7 +27,7 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - #[repr(align(4096))] + #[repr(C, align(4096))] struct LendBuffer([u8; 4096]); let mut lend_buffer = LendBuffer([0u8; 4096]); let connection = log_server(); @@ -35,7 +35,8 @@ impl io::Write for Stdout { for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) { *dest = *src; } - lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); + lend(connection, LogLend::StandardOutput.into(), &lend_buffer.0, 0, chunk.len()) + .unwrap(); } Ok(buf.len()) } @@ -53,7 +54,7 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - #[repr(align(4096))] + #[repr(C, align(4096))] struct LendBuffer([u8; 4096]); let mut lend_buffer = LendBuffer([0u8; 4096]); let connection = log_server(); @@ -61,7 +62,8 @@ impl io::Write for Stderr { for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) { *dest = *src; } - lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); + lend(connection, LogLend::StandardError.into(), &lend_buffer.0, 0, chunk.len()) + .unwrap(); } Ok(buf.len()) } diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs index 78c68de7bf38d..0f452e07a5c58 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/pal/xous/thread.rs @@ -68,14 +68,18 @@ impl Thread { ) .map_err(|code| io::Error::from_raw_os_error(code as i32))?; - extern "C" fn thread_start(main: *mut usize, guard_page_pre: usize, stack_size: usize) { + extern "C" fn thread_start( + main: *mut usize, + guard_page_pre: usize, + stack_size: usize, + ) -> ! { unsafe { - // Finally, let's run some code. + // Run the contents of the new thread. Box::from_raw(main as *mut Box)(); } // Destroy TLS, which will free the TLS page and call the destructor for - // any thread local storage. + // any thread local storage (if any). unsafe { crate::sys::thread_local_key::destroy_tls(); } diff --git a/library/std/src/sys/pal/xous/thread_local_key.rs b/library/std/src/sys/pal/xous/thread_local_key.rs index 3771ea6570084..59a668c3df6ff 100644 --- a/library/std/src/sys/pal/xous/thread_local_key.rs +++ b/library/std/src/sys/pal/xous/thread_local_key.rs @@ -23,10 +23,25 @@ pub type Dtor = unsafe extern "C" fn(*mut u8); const TLS_MEMORY_SIZE: usize = 4096; -/// TLS keys start at `1` to mimic POSIX. +/// TLS keys start at `1`. Index `0` is unused +#[cfg(not(test))] +#[export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE"] static TLS_KEY_INDEX: AtomicUsize = AtomicUsize::new(1); -fn tls_ptr_addr() -> *mut usize { +#[cfg(not(test))] +#[export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE"] +static DTORS: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +#[cfg(test)] +extern "Rust" { + #[link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE"] + static TLS_KEY_INDEX: AtomicUsize; + + #[link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE"] + static DTORS: AtomicPtr; +} + +fn tls_ptr_addr() -> *mut *mut u8 { let mut tp: usize; unsafe { asm!( @@ -34,50 +49,50 @@ fn tls_ptr_addr() -> *mut usize { out(reg) tp, ); } - core::ptr::from_exposed_addr_mut::(tp) + core::ptr::from_exposed_addr_mut::<*mut u8>(tp) } /// Create an area of memory that's unique per thread. This area will /// contain all thread local pointers. -fn tls_ptr() -> *mut usize { - let mut tp = tls_ptr_addr(); +fn tls_table() -> &'static mut [*mut u8] { + let tp = tls_ptr_addr(); + if !tp.is_null() { + return unsafe { + core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / core::mem::size_of::<*mut u8>()) + }; + } // If the TP register is `0`, then this thread hasn't initialized // its TLS yet. Allocate a new page to store this memory. - if tp.is_null() { - tp = unsafe { - map_memory( - None, - None, - TLS_MEMORY_SIZE / core::mem::size_of::(), - MemoryFlags::R | MemoryFlags::W, - ) - } + let tp = unsafe { + map_memory( + None, + None, + TLS_MEMORY_SIZE / core::mem::size_of::<*mut u8>(), + MemoryFlags::R | MemoryFlags::W, + ) .expect("Unable to allocate memory for thread local storage") - .as_mut_ptr(); + }; - unsafe { - // Key #0 is currently unused. - (tp).write_volatile(0); + for val in tp.iter() { + assert!(*val as usize == 0); + } - // Set the thread's `$tp` register - asm!( - "mv tp, {}", - in(reg) tp as usize, - ); - } + unsafe { + // Set the thread's `$tp` register + asm!( + "mv tp, {}", + in(reg) tp.as_mut_ptr() as usize, + ); } tp } -/// Allocate a new TLS key. These keys are shared among all threads. -fn tls_alloc() -> usize { - TLS_KEY_INDEX.fetch_add(1, SeqCst) -} - #[inline] pub unsafe fn create(dtor: Option) -> Key { - let key = tls_alloc(); + // Allocate a new TLS key. These keys are shared among all threads. + #[allow(unused_unsafe)] + let key = unsafe { TLS_KEY_INDEX.fetch_add(1, SeqCst) }; if let Some(f) = dtor { unsafe { register_dtor(key, f) }; } @@ -87,18 +102,20 @@ pub unsafe fn create(dtor: Option) -> Key { #[inline] pub unsafe fn set(key: Key, value: *mut u8) { assert!((key < 1022) && (key >= 1)); - unsafe { tls_ptr().add(key).write_volatile(value as usize) }; + let table = tls_table(); + table[key] = value; } #[inline] pub unsafe fn get(key: Key) -> *mut u8 { assert!((key < 1022) && (key >= 1)); - core::ptr::from_exposed_addr_mut::(unsafe { tls_ptr().add(key).read_volatile() }) + tls_table()[key] } #[inline] pub unsafe fn destroy(_key: Key) { - panic!("can't destroy keys on Xous"); + // Just leak the key. Probably not great on long-running systems that create + // lots of TLS variables, but in practice that's not an issue. } // ------------------------------------------------------------------------- @@ -127,8 +144,6 @@ pub unsafe fn destroy(_key: Key) { // key but also a slot for the destructor queue on windows. An optimization for // another day! -static DTORS: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - struct Node { dtor: Dtor, key: Key, @@ -138,10 +153,12 @@ struct Node { unsafe fn register_dtor(key: Key, dtor: Dtor) { let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() })); - let mut head = DTORS.load(SeqCst); + #[allow(unused_unsafe)] + let mut head = unsafe { DTORS.load(SeqCst) }; loop { node.next = head; - match DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) { + #[allow(unused_unsafe)] + match unsafe { DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) } { Ok(_) => return, // nothing to drop, we successfully added the node to the list Err(cur) => head = cur, } @@ -155,6 +172,7 @@ pub unsafe fn destroy_tls() { if tp.is_null() { return; } + unsafe { run_dtors() }; // Finally, free the TLS array @@ -169,12 +187,19 @@ pub unsafe fn destroy_tls() { unsafe fn run_dtors() { let mut any_run = true; + + // Run the destructor "some" number of times. This is 5x on Windows, + // so we copy it here. This allows TLS variables to create new + // TLS variables upon destruction that will also get destroyed. + // Keep going until we run out of tries or until we have nothing + // left to destroy. for _ in 0..5 { if !any_run { break; } any_run = false; - let mut cur = DTORS.load(SeqCst); + #[allow(unused_unsafe)] + let mut cur = unsafe { DTORS.load(SeqCst) }; while !cur.is_null() { let ptr = unsafe { get((*cur).key) }; diff --git a/library/std/src/sys/pal/xous/thread_parking.rs b/library/std/src/sys/pal/xous/thread_parking.rs index aa39c6d27185f..0bd0462d77d35 100644 --- a/library/std/src/sys/pal/xous/thread_parking.rs +++ b/library/std/src/sys/pal/xous/thread_parking.rs @@ -29,31 +29,40 @@ impl Parker { // Change NOTIFIED to EMPTY and EMPTY to PARKED. let state = self.state.fetch_sub(1, Acquire); if state == NOTIFIED { + // The state has gone from NOTIFIED (1) to EMPTY (0) return; } + // The state has gone from EMPTY (0) to PARKED (-1) + assert!(state == EMPTY); - // The state was set to PARKED. Wait until the `unpark` wakes us up. + // The state is now PARKED (-1). Wait until the `unpark` wakes us up. blocking_scalar( ticktimer_server(), TicktimerScalar::WaitForCondition(self.index(), 0).into(), ) .expect("failed to send WaitForCondition command"); - self.state.swap(EMPTY, Acquire); + let state = self.state.swap(EMPTY, Acquire); + assert!(state == NOTIFIED || state == PARKED); } pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) { // Change NOTIFIED to EMPTY and EMPTY to PARKED. let state = self.state.fetch_sub(1, Acquire); if state == NOTIFIED { + // The state has gone from NOTIFIED (1) to EMPTY (0) return; } + // The state has gone from EMPTY (0) to PARKED (-1) + assert!(state == EMPTY); // A value of zero indicates an indefinite wait. Clamp the number of // milliseconds to the allowed range. let millis = usize::max(timeout.as_millis().try_into().unwrap_or(usize::MAX), 1); - let was_timeout = blocking_scalar( + // The state is now PARKED (-1). Wait until the `unpark` wakes us up, + // or things time out. + let _was_timeout = blocking_scalar( ticktimer_server(), TicktimerScalar::WaitForCondition(self.index(), millis).into(), ) @@ -61,28 +70,37 @@ impl Parker { != 0; let state = self.state.swap(EMPTY, Acquire); - if was_timeout && state == NOTIFIED { - // The state was set to NOTIFIED after we returned from the wait - // but before we reset the state. Therefore, a wakeup is on its - // way, which we need to consume here. - // NOTICE: this is a priority hole. - blocking_scalar( - ticktimer_server(), - TicktimerScalar::WaitForCondition(self.index(), 0).into(), - ) - .expect("failed to send WaitForCondition command"); - } + assert!(state == PARKED || state == NOTIFIED); } pub fn unpark(self: Pin<&Self>) { - let state = self.state.swap(NOTIFIED, Release); - if state == PARKED { - // The thread is parked, wake it up. - blocking_scalar( - ticktimer_server(), - TicktimerScalar::NotifyCondition(self.index(), 1).into(), - ) - .expect("failed to send NotifyCondition command"); + // If the state is already `NOTIFIED`, then another thread has + // indicated it wants to wake up the target thread. + // + // If the state is `EMPTY` then there is nothing to wake up, and + // the target thread will immediately exit from `park()` the + // next time that function is called. + if self.state.swap(NOTIFIED, Release) != PARKED { + return; + } + + // The thread is parked, wake it up. Keep trying until we wake something up. + // This will happen when the `NotifyCondition` call returns the fact that + // 1 condition was notified. + // Alternately, keep going until the state is seen as `EMPTY`, indicating + // the thread woke up and kept going. This can happen when the Park + // times out before we can send the NotifyCondition message. + while blocking_scalar( + ticktimer_server(), + TicktimerScalar::NotifyCondition(self.index(), 1).into(), + ) + .expect("failed to send NotifyCondition command")[0] + == 0 + && self.state.load(Acquire) != EMPTY + { + // The target thread hasn't yet hit the `WaitForCondition` call. + // Yield to let the target thread run some more. + crate::thread::yield_now(); } } } diff --git a/library/std/src/sys/pal/zkvm/abi.rs b/library/std/src/sys/pal/zkvm/abi.rs new file mode 100644 index 0000000000000..53332d90e02c0 --- /dev/null +++ b/library/std/src/sys/pal/zkvm/abi.rs @@ -0,0 +1,55 @@ +//! ABI definitions for symbols exported by risc0-zkvm-platform. + +// Included here so we don't have to depend on risc0-zkvm-platform. +// +// FIXME: Should we move this to the "libc" crate? It seems like other +// architectures put a lot of this kind of stuff there. But there's +// currently no risc0 fork of the libc crate, so we'd either have to +// fork it or upstream it. + +#![allow(dead_code)] +pub const DIGEST_WORDS: usize = 8; + +/// Standard IO file descriptors for use with sys_read and sys_write. +pub mod fileno { + pub const STDIN: u32 = 0; + pub const STDOUT: u32 = 1; + pub const STDERR: u32 = 2; + pub const JOURNAL: u32 = 3; +} + +extern "C" { + // Wrappers around syscalls provided by risc0-zkvm-platform: + pub fn sys_halt(); + pub fn sys_output(output_id: u32, output_value: u32); + pub fn sys_sha_compress( + out_state: *mut [u32; DIGEST_WORDS], + in_state: *const [u32; DIGEST_WORDS], + block1_ptr: *const [u32; DIGEST_WORDS], + block2_ptr: *const [u32; DIGEST_WORDS], + ); + pub fn sys_sha_buffer( + out_state: *mut [u32; DIGEST_WORDS], + in_state: *const [u32; DIGEST_WORDS], + buf: *const u8, + count: u32, + ); + pub fn sys_rand(recv_buf: *mut u32, words: usize); + pub fn sys_panic(msg_ptr: *const u8, len: usize) -> !; + pub fn sys_log(msg_ptr: *const u8, len: usize); + pub fn sys_cycle_count() -> usize; + pub fn sys_read(fd: u32, recv_buf: *mut u8, nrequested: usize) -> usize; + pub fn sys_write(fd: u32, write_buf: *const u8, nbytes: usize); + pub fn sys_getenv( + recv_buf: *mut u32, + words: usize, + varname: *const u8, + varname_len: usize, + ) -> usize; + pub fn sys_argc() -> usize; + pub fn sys_argv(out_words: *mut u32, out_nwords: usize, arg_index: usize) -> usize; + + // Allocate memory from global HEAP. + pub fn sys_alloc_words(nwords: usize) -> *mut u32; + pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8; +} diff --git a/library/std/src/sys/pal/zkvm/alloc.rs b/library/std/src/sys/pal/zkvm/alloc.rs new file mode 100644 index 0000000000000..fd333f1215150 --- /dev/null +++ b/library/std/src/sys/pal/zkvm/alloc.rs @@ -0,0 +1,15 @@ +use super::abi; +use crate::alloc::{GlobalAlloc, Layout, System}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + abi::sys_alloc_aligned(layout.size(), layout.align()) + } + + #[inline] + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + // this allocator never deallocates memory + } +} diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/pal/zkvm/args.rs new file mode 100644 index 0000000000000..7753cf63840e3 --- /dev/null +++ b/library/std/src/sys/pal/zkvm/args.rs @@ -0,0 +1,80 @@ +use super::{abi, WORD_SIZE}; +use crate::ffi::OsString; +use crate::fmt; +use crate::sys_common::FromInner; + +pub struct Args { + i_forward: usize, + i_back: usize, + count: usize, +} + +pub fn args() -> Args { + let count = unsafe { abi::sys_argc() }; + Args { i_forward: 0, i_back: 0, count } +} + +impl Args { + /// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc + /// and will not return if the index is out of bounds. + fn argv(i: usize) -> OsString { + let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) }; + + let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE; + let words = unsafe { abi::sys_alloc_words(arg_len_words) }; + + let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) }; + debug_assert_eq!(arg_len, arg_len2); + + // Convert to OsString. + // + // FIXME: We can probably get rid of the extra copy here if we + // reimplement "os_str" instead of just using the generic unix + // "os_str". + let arg_bytes: &[u8] = + unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) }; + OsString::from_inner(super::os_str::Buf { inner: arg_bytes.to_vec() }) + } +} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().finish() + } +} + +impl Iterator for Args { + type Item = OsString; + + fn next(&mut self) -> Option { + if self.i_forward >= self.count - self.i_back { + None + } else { + let arg = Self::argv(self.i_forward); + self.i_forward += 1; + Some(arg) + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.count + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + if self.i_back >= self.count - self.i_forward { + None + } else { + let arg = Self::argv(self.count - 1 - self.i_back); + self.i_back += 1; + Some(arg) + } + } +} diff --git a/library/std/src/sys/pal/zkvm/env.rs b/library/std/src/sys/pal/zkvm/env.rs new file mode 100644 index 0000000000000..b85153642b1c9 --- /dev/null +++ b/library/std/src/sys/pal/zkvm/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".elf"; + pub const DLL_EXTENSION: &str = "elf"; + pub const EXE_SUFFIX: &str = ".elf"; + pub const EXE_EXTENSION: &str = "elf"; +} diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs new file mode 100644 index 0000000000000..7f221dc4fd98a --- /dev/null +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -0,0 +1,93 @@ +//! System bindings for the risc0 zkvm platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for zkvm. +//! +//! This is all super highly experimental and not actually intended for +//! wide/production use yet, it's still all in the experimental category. This +//! will likely change over time. + +const WORD_SIZE: usize = core::mem::size_of::(); + +pub mod alloc; +#[path = "../zkvm/args.rs"] +pub mod args; +#[path = "../unix/cmath.rs"] +pub mod cmath; +pub mod env; +#[path = "../unsupported/fs.rs"] +pub mod fs; +#[path = "../unsupported/io.rs"] +pub mod io; +#[path = "../unsupported/net.rs"] +pub mod net; +#[path = "../unsupported/once.rs"] +pub mod once; +pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; +#[path = "../unix/path.rs"] +pub mod path; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +pub mod stdio; +pub mod thread_local_key; +#[path = "../unsupported/time.rs"] +pub mod time; + +#[path = "../unsupported/locks/mod.rs"] +pub mod locks; +#[path = "../unsupported/thread.rs"] +pub mod thread; + +#[path = "../unsupported/thread_parking.rs"] +pub mod thread_parking; + +mod abi; + +use crate::io as std_io; + +pub mod memchr { + pub use core::slice::memchr::{memchr, memrchr}; +} + +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} + +// SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub unsafe fn cleanup() {} + +pub fn unsupported() -> std_io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> std_io::Error { + std_io::const_io_error!( + std_io::ErrorKind::Unsupported, + "operation not supported on this platform", + ) +} + +pub fn is_interrupted(_code: i32) -> bool { + false +} + +pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { + crate::io::ErrorKind::Uncategorized +} + +pub fn abort_internal() -> ! { + core::intrinsics::abort(); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + let mut buf = [0u32; 4]; + unsafe { + abi::sys_rand(buf.as_mut_ptr(), 4); + }; + ((buf[0] as u64) << 32 + buf[1] as u64, (buf[2] as u64) << 32 + buf[3] as u64) +} diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs new file mode 100644 index 0000000000000..d8739ee38246e --- /dev/null +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -0,0 +1,139 @@ +use super::{abi, unsupported, WORD_SIZE}; +use crate::error::Error as StdError; +use crate::ffi::{OsStr, OsString}; +use crate::fmt; +use crate::io; +use crate::marker::PhantomData; +use crate::path::{self, PathBuf}; +use crate::sys_common::FromInner; + +pub fn errno() -> i32 { + 0 +} + +pub fn error_string(_errno: i32) -> String { + "operation successful".to_string() +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + self.0 + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result +where + I: Iterator, + T: AsRef, +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +pub struct Env(!); + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.0 + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self(inner) = self; + match *inner {} + } +} + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(inner) = self; + match *inner {} + } +} + +pub fn getenv(varname: &OsStr) -> Option { + let varname = varname.as_encoded_bytes(); + let nbytes = + unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) }; + if nbytes == usize::MAX { + return None; + } + + let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE; + let words = unsafe { abi::sys_alloc_words(nwords) }; + + let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) }; + debug_assert_eq!(nbytes, nbytes2); + + // Convert to OsString. + // + // FIXME: We can probably get rid of the extra copy here if we + // reimplement "os_str" instead of just using the generic unix + // "os_str". + let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; + Some(OsString::from_inner(super::os_str::Buf { inner: u8s.to_vec() })) +} + +pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +} + +pub fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on this platform") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(_code: i32) -> ! { + crate::intrinsics::abort() +} + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff --git a/library/std/src/sys/pal/zkvm/stdio.rs b/library/std/src/sys/pal/zkvm/stdio.rs new file mode 100644 index 0000000000000..e771ed0de28db --- /dev/null +++ b/library/std/src/sys/pal/zkvm/stdio.rs @@ -0,0 +1,64 @@ +use super::{abi, abi::fileno}; +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(unsafe { abi::sys_read(fileno::STDIN, buf.as_mut_ptr(), buf.len()) }) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::sys_write(fileno::STDOUT, buf.as_ptr(), buf.len()) } + + Ok(buf.len()) + } + + 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 { abi::sys_write(fileno::STDERR, buf.as_ptr(), buf.len()) } + + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(Stderr::new()) +} diff --git a/library/std/src/sys/pal/zkvm/thread_local_key.rs b/library/std/src/sys/pal/zkvm/thread_local_key.rs new file mode 100644 index 0000000000000..3ffe6247344e8 --- /dev/null +++ b/library/std/src/sys/pal/zkvm/thread_local_key.rs @@ -0,0 +1,23 @@ +use crate::alloc::{alloc, Layout}; + +pub type Key = usize; + +#[inline] +pub unsafe fn create(_dtor: Option) -> Key { + alloc(Layout::new::<*mut u8>()) as _ +} + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { + let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key); + *key = value; +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key); + *key +} + +#[inline] +pub unsafe fn destroy(_key: Key) {} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 851832a377cf8..01f83ecb41452 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -59,12 +59,14 @@ cfg_if::cfg_if! { /// A trait for viewing representations from std types #[doc(hidden)] +#[allow(dead_code)] // not used on all platforms pub trait AsInner { fn as_inner(&self) -> &Inner; } /// A trait for viewing representations from std types #[doc(hidden)] +#[allow(dead_code)] // not used on all platforms pub trait AsInnerMut { fn as_inner_mut(&mut self) -> &mut Inner; } diff --git a/library/std/src/sys_common/once/mod.rs b/library/std/src/sys_common/once/mod.rs index 359697d831317..ec57568c54c4f 100644 --- a/library/std/src/sys_common/once/mod.rs +++ b/library/std/src/sys_common/once/mod.rs @@ -25,6 +25,7 @@ cfg_if::cfg_if! { target_family = "unix", all(target_vendor = "fortanix", target_env = "sgx"), target_os = "solid_asp3", + target_os = "xous", ))] { mod queue; pub use queue::{Once, OnceState}; diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 338567777f753..2e13f433dcffb 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -186,12 +186,12 @@ macro_rules! thread_local { // empty (base case for the recursion) () => {}; - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => ( + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => ( $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); $crate::thread_local!($($rest)*); ); - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => ( + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => ( $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); ); diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 9ce29a33df6e6..c9b9c54e3d49c 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -1,12 +1,16 @@ //! These tests just check that the macros are available in std. #![cfg_attr( - any( - all(target_arch = "arm", any(target_os = "linux", target_os = "android")), - all(target_arch = "powerpc", target_os = "linux"), - all(target_arch = "powerpc64", target_os = "linux"), - ), - feature(stdsimd) + all(target_arch = "arm", any(target_os = "linux", target_os = "android")), + feature(stdarch_arm_feature_detection) +)] +#![cfg_attr( + all(target_arch = "powerpc", target_os = "linux"), + feature(stdarch_powerpc_feature_detection) +)] +#![cfg_attr( + all(target_arch = "powerpc64", target_os = "linux"), + feature(stdarch_powerpc_feature_detection) )] #[test] diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 754b264c6ad93..4ce81f2846ea9 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -1,3 +1,4 @@ +use std::cell::{Cell, RefCell}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -14,3 +15,24 @@ fn sleep() { thread::sleep(Duration::from_millis(100)); assert_eq!(*finished.lock().unwrap(), false); } + +#[test] +fn thread_local_containing_const_statements() { + // This exercises the `const $init:block` cases of the thread_local macro. + // Despite overlapping with expression syntax, the `const { ... }` is not + // parsed as `$init:expr`. + thread_local! { + static CELL: Cell = const { + let value = 1; + Cell::new(value) + }; + + static REFCELL: RefCell = const { + let value = 1; + RefCell::new(value) + }; + } + + assert_eq!(CELL.get(), 1); + assert_eq!(REFCELL.take(), 1); +} diff --git a/library/stdarch b/library/stdarch index f4528dd6e85d9..5ef6eb42bdcfe 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit f4528dd6e85d97bb802240d7cd048b6e1bf72540 +Subproject commit 5ef6eb42bdcfef6891517a6e4c77a89c18722f18 diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 92c535501bf9c..4c42e3bae563e 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -9,3 +9,4 @@ std = { path = "../std" } core = { path = "../core" } panic_unwind = { path = "../panic_unwind" } panic_abort = { path = "../panic_abort" } +libc = { version = "0.2.150", default-features = false } diff --git a/library/test/src/console.rs b/library/test/src/console.rs index bbeb944e8b11b..09aa3bfb6aac3 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -323,7 +323,8 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu // Prevent the usage of `Instant` in some cases: // - It's currently not supported for wasm targets. // - We disable it for miri because it's not available when isolation is enabled. - let is_instant_supported = !cfg!(target_family = "wasm") && !cfg!(miri); + let is_instant_supported = + !cfg!(target_family = "wasm") && !cfg!(target_os = "zkvm") && !cfg!(miri); let start_time = is_instant_supported.then(Instant::now); run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; diff --git a/library/test/src/helpers/exit_code.rs b/library/test/src/helpers/exit_code.rs deleted file mode 100644 index f762f88819da5..0000000000000 --- a/library/test/src/helpers/exit_code.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Helper module to detect subprocess exit code. - -use std::process::ExitStatus; - -#[cfg(not(unix))] -pub fn get_exit_code(status: ExitStatus) -> Result { - status.code().ok_or_else(|| "received no exit code from child process".into()) -} - -#[cfg(unix)] -pub fn get_exit_code(status: ExitStatus) -> Result { - use std::os::unix::process::ExitStatusExt; - match status.code() { - Some(code) => Ok(code), - None => match status.signal() { - Some(signal) => Err(format!("child process exited with signal {signal}")), - None => Err("child process exited with unknown signal".into()), - }, - } -} diff --git a/library/test/src/helpers/mod.rs b/library/test/src/helpers/mod.rs index 6f366a911e8cd..3c79b90b16754 100644 --- a/library/test/src/helpers/mod.rs +++ b/library/test/src/helpers/mod.rs @@ -2,6 +2,5 @@ //! but used in `libtest`. pub mod concurrency; -pub mod exit_code; pub mod metrics; pub mod shuffle; diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 2e93796d98152..da110f9924861 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -85,7 +85,6 @@ mod tests; use core::any::Any; use event::{CompletedTest, TestEvent}; use helpers::concurrency::get_concurrency; -use helpers::exit_code::get_exit_code; use helpers::shuffle::{get_shuffle_seed, shuffle_tests}; use options::RunStrategy; use test_result::*; @@ -540,7 +539,7 @@ pub fn run_test( // Emscripten can catch panics but other wasm targets cannot let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No - && cfg!(target_family = "wasm") + && (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm")) && !cfg!(target_os = "emscripten"); if force_ignore || desc.ignore || ignore_because_no_process_support { @@ -712,17 +711,7 @@ fn spawn_test_subprocess( formatters::write_stderr_delimiter(&mut test_output, &desc.name); test_output.extend_from_slice(&stderr); - let result = match (|| -> Result { - let exit_code = get_exit_code(status)?; - Ok(get_result_from_exit_code(&desc, exit_code, &time_opts, &exec_time)) - })() { - Ok(r) => r, - Err(e) => { - write!(&mut test_output, "Unexpected error: {e}").unwrap(); - TrFailed - } - }; - + let result = get_result_from_exit_code(&desc, status, &time_opts, &exec_time); (result, test_output, exec_time) })(); @@ -751,7 +740,7 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) - if let TrOk = test_result { process::exit(test_result::TR_OK); } else { - process::exit(test_result::TR_FAILED); + process::abort(); } }); let record_result2 = record_result.clone(); diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index 1da238e3e8c0f..bb32c70d66311 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -1,4 +1,8 @@ use std::any::Any; +use std::process::ExitStatus; + +#[cfg(unix)] +use std::os::unix::process::ExitStatusExt; use super::bench::BenchSamples; use super::options::ShouldPanic; @@ -7,11 +11,15 @@ use super::types::TestDesc; pub use self::TestResult::*; -// Return codes for secondary process. +// Return code for secondary process. // Start somewhere other than 0 so we know the return code means what we think // it means. pub const TR_OK: i32 = 50; -pub const TR_FAILED: i32 = 51; + +// On Windows we use __fastfail to abort, which is documented to use this +// exception code. +#[cfg(windows)] +const STATUS_ABORTED: i32 = 0xC0000409u32 as i32; #[derive(Debug, Clone, PartialEq)] pub enum TestResult { @@ -81,14 +89,28 @@ pub fn calc_result<'a>( /// Creates a `TestResult` depending on the exit code of test subprocess. pub fn get_result_from_exit_code( desc: &TestDesc, - code: i32, + status: ExitStatus, time_opts: &Option, exec_time: &Option, ) -> TestResult { - let result = match code { - TR_OK => TestResult::TrOk, - TR_FAILED => TestResult::TrFailed, - _ => TestResult::TrFailedMsg(format!("got unexpected return code {code}")), + let result = match status.code() { + Some(TR_OK) => TestResult::TrOk, + #[cfg(windows)] + Some(STATUS_ABORTED) => TestResult::TrFailed, + #[cfg(unix)] + None => match status.signal() { + Some(libc::SIGABRT) => TestResult::TrFailed, + Some(signal) => { + TestResult::TrFailedMsg(format!("child process exited with signal {signal}")) + } + None => unreachable!("status.code() returned None but status.signal() was None"), + }, + #[cfg(not(unix))] + None => TestResult::TrFailedMsg(format!("unknown return code")), + #[cfg(any(windows, unix))] + Some(code) => TestResult::TrFailedMsg(format!("got unexpected return code {code}")), + #[cfg(not(any(windows, unix)))] + Some(_) => TestResult::TrFailed, }; // If test is already failed (or allowed to fail), do not change the result. diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 28d96cb1cfe56..0d604c0d3e5e0 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -924,17 +924,29 @@ def build_bootstrap_cmd(self, env): # default toolchain is not nightly. # # But that setting has the collateral effect of rust-analyzer also - # passing RUSTC_BOOTSTRAP=1 to all x.py invocations too (the various overrideCommand). - # For compiling bootstrap that can cause spurious rebuilding of bootstrap when - # rust-analyzer x.py invocations are interleaved with handwritten ones on the - # command line. + # passing RUSTC_BOOTSTRAP=1 to all x.py invocations too (the various + # overrideCommand). # - # Set RUSTC_BOOTSTRAP=1 consistently. + # Set a consistent RUSTC_BOOTSTRAP=1 here to prevent spurious rebuilds + # of bootstrap when rust-analyzer x.py invocations are interleaved with + # handwritten ones on the command line. env["RUSTC_BOOTSTRAP"] = "1" - default_rustflags = "" if env.get("RUSTFLAGS_BOOTSTRAP", "") else "-Zallow-features=" - - env.setdefault("RUSTFLAGS", default_rustflags) + # If any of RUSTFLAGS or RUSTFLAGS_BOOTSTRAP are present and nonempty, + # we allow arbitrary compiler flags in there, including unstable ones + # such as `-Zthreads=8`. + # + # But if there aren't custom flags being passed to bootstrap, then we + # cancel the RUSTC_BOOTSTRAP=1 from above by passing `-Zallow-features=` + # to ensure unstable language or library features do not accidentally + # get introduced into bootstrap over time. Distros rely on being able to + # compile bootstrap with a variety of their toolchains, not necessarily + # the same as Rust's CI uses. + if env.get("RUSTFLAGS", "") or env.get("RUSTFLAGS_BOOTSTRAP", ""): + # Preserve existing RUSTFLAGS. + env.setdefault("RUSTFLAGS", "") + else: + env["RUSTFLAGS"] = "-Zallow-features=" target_features = [] if self.get_toml("crt-static", build_section) == "true": @@ -1022,7 +1034,16 @@ def check_vendored_status(self): eprint('ERROR: vendoring required, but vendor directory does not exist.') eprint(' Run `cargo vendor {}` to initialize the ' 'vendor directory.'.format(sync_dirs)) - eprint('Alternatively, use the pre-vendored `rustc-src` dist component.') + eprint(' Alternatively, use the pre-vendored `rustc-src` dist component.') + eprint(' To get a stable/beta/nightly version, download it from: ') + eprint(' ' + 'https://forge.rust-lang.org/infra/other-installation-methods.html#source-code') + eprint(' To get a specific commit version, download it using the below URL,') + eprint(' replacing with a specific commit checksum: ') + eprint(' ' + 'https://ci-artifacts.rust-lang.org/rustc-builds//rustc-nightly-src.tar.xz') + eprint(' Once you have the source downloaded, place the vendor directory') + eprint(' from the archive in the root of the rust project.') raise Exception("{} not found".format(vendor_dir)) if not os.path.exists(cargo_dir): diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 190f0fe3cddcf..ddbe18ab8388d 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -803,7 +803,14 @@ impl Rustc { } impl Step for Rustc { - type Output = (); + // We return the stage of the "actual" compiler (not the uplifted one). + // + // By "actual" we refer to the uplifting logic where we may not compile the requested stage; + // instead, we uplift it from the previous stages. Which can lead to bootstrap failures in + // specific situations where we request stage X from other steps. However we may end up + // uplifting it from stage Y, causing the other stage to fail when attempting to link with + // stage X which was never actually built. + type Output = u32; const ONLY_HOSTS: bool = true; const DEFAULT: bool = false; @@ -834,7 +841,7 @@ impl Step for Rustc { /// This will build the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. - fn run(self, builder: &Builder<'_>) { + fn run(self, builder: &Builder<'_>) -> u32 { let compiler = self.compiler; let target = self.target; @@ -848,7 +855,7 @@ impl Step for Rustc { compiler, builder.config.ci_rustc_dev_contents(), ); - return; + return compiler.stage; } builder.ensure(Std::new(compiler, target)); @@ -857,7 +864,8 @@ impl Step for Rustc { builder.info("WARNING: Using a potentially old librustc. This may not behave well."); builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); builder.ensure(RustcLink::from_rustc(self, compiler)); - return; + + return compiler.stage; } let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); @@ -880,7 +888,7 @@ impl Step for Rustc { }; builder.info(&msg); builder.ensure(RustcLink::from_rustc(self, compiler_to_use)); - return; + return compiler_to_use.stage; } // Ensure that build scripts and proc macros have a std / libproc_macro to link against. @@ -984,6 +992,8 @@ impl Step for Rustc { self, builder.compiler(compiler.stage, builder.config.build), )); + + compiler.stage } } @@ -1103,16 +1113,11 @@ pub fn rustc_cargo_env( /// Pass down configuration from the LLVM build into the build of /// rustc_llvm and rustc_codegen_llvm. fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { - let target_config = builder.config.target_config.get(&target); - if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); cargo.env("LLVM_CONFIG", &llvm_config); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by @@ -1642,21 +1647,6 @@ impl Step for Assemble { return target_compiler; } - // Get the compiler that we'll use to bootstrap ourselves. - // - // Note that this is where the recursive nature of the bootstrap - // happens, as this will request the previous stage's compiler on - // downwards to stage 0. - // - // Also note that we're building a compiler for the host platform. We - // only assume that we can run `build` artifacts, which means that to - // produce some other architecture compiler we need to start from - // `build` to get there. - // - // FIXME: It may be faster if we build just a stage 1 compiler and then - // use that to bootstrap this compiler forward. - let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); - // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. if builder.download_rustc() { let sysroot = @@ -1671,19 +1661,30 @@ impl Step for Assemble { return target_compiler; } + // Get the compiler that we'll use to bootstrap ourselves. + // + // Note that this is where the recursive nature of the bootstrap + // happens, as this will request the previous stage's compiler on + // downwards to stage 0. + // + // Also note that we're building a compiler for the host platform. We + // only assume that we can run `build` artifacts, which means that to + // produce some other architecture compiler we need to start from + // `build` to get there. + // + // FIXME: It may be faster if we build just a stage 1 compiler and then + // use that to bootstrap this compiler forward. + let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + // Build the libraries for this compiler to link to (i.e., the libraries // it uses at runtime). NOTE: Crates the target compiler compiles don't // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - builder.ensure(Rustc::new(build_compiler, target_compiler.host)); - - // FIXME: For now patch over problems noted in #90244 by early returning here, even though - // we've not properly assembled the target sysroot. A full fix is pending further investigation, - // for now full bootstrap usage is rare enough that this is OK. - if target_compiler.stage >= 3 && !builder.config.full_bootstrap { - return target_compiler; - } + let actual_stage = builder.ensure(Rustc::new(build_compiler, target_compiler.host)); + // Current build_compiler.stage might be uplifted instead of being built; so update it + // to not fail while linking the artifacts. + build_compiler.stage = actual_stage; for &backend in builder.config.rust_codegen_backends.iter() { if backend == "llvm" { diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 9c897ae1bb784..5b434eddb7158 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -14,7 +14,6 @@ use std::str::FromStr; use std::{fmt, fs, io}; #[cfg(test)] -#[path = "../../tests/setup.rs"] mod tests; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] @@ -37,6 +36,7 @@ static SETTINGS_HASHES: &[&str] = &[ "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", ]; static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); diff --git a/src/bootstrap/src/tests/setup.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs similarity index 100% rename from src/bootstrap/src/tests/setup.rs rename to src/bootstrap/src/core/build_steps/setup/tests.rs diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 3770d0687b242..dac8393de6b4c 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -32,7 +32,6 @@ use clap::ValueEnum; use once_cell::sync::Lazy; #[cfg(test)] -#[path = "../tests/builder.rs"] mod tests; pub struct Builder<'a> { diff --git a/src/bootstrap/src/tests/builder.rs b/src/bootstrap/src/core/builder/tests.rs similarity index 100% rename from src/bootstrap/src/tests/builder.rs rename to src/bootstrap/src/core/builder/tests.rs diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index fcdd742e69c22..c0dd1e1208484 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -3,10 +3,6 @@ //! This module implements parsing `config.toml` configuration files to tweak //! how the build runs. -#[cfg(test)] -#[path = "../../tests/config.rs"] -mod tests; - use std::cell::{Cell, RefCell}; use std::cmp; use std::collections::{HashMap, HashSet}; @@ -1203,7 +1199,7 @@ impl Config { Self::parse_inner(args, get_toml) } - fn parse_inner(args: &[String], get_toml: impl Fn(&Path) -> TomlConfig) -> Config { + pub(crate) fn parse_inner(args: &[String], get_toml: impl Fn(&Path) -> TomlConfig) -> Config { let mut flags = Flags::parse(&args); let mut config = Config::default_opts(); diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 9c6861826d605..99412848abbb7 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -1,4 +1,6 @@ pub(crate) mod config; pub(crate) mod flags; +#[cfg(test)] +mod tests; pub use config::*; diff --git a/src/bootstrap/src/tests/config.rs b/src/bootstrap/src/core/config/tests.rs similarity index 95% rename from src/bootstrap/src/tests/config.rs rename to src/bootstrap/src/core/config/tests.rs index c65067f8e8f76..0ae466eca7d7c 100644 --- a/src/bootstrap/src/tests/config.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,4 +1,4 @@ -use super::{Config, Flags}; +use super::{flags::Flags, Config}; use crate::core::config::{LldMode, TomlConfig}; use clap::CommandFactory; @@ -174,12 +174,14 @@ fn override_toml_duplicate() { #[test] fn profile_user_dist() { fn get_toml(file: &Path) -> TomlConfig { - let contents = if file.ends_with("config.toml") { - "profile = \"user\"".to_owned() - } else { - assert!(file.ends_with("config.dist.toml")); - std::fs::read_to_string(file).unwrap() - }; + let contents = + if file.ends_with("config.toml") || env::var_os("RUST_BOOTSTRAP_CONFIG").is_some() { + "profile = \"user\"".to_owned() + } else { + assert!(file.ends_with("config.dist.toml")); + std::fs::read_to_string(file).unwrap() + }; + toml::from_str(&contents) .and_then(|table: toml::Value| TomlConfig::deserialize(table)) .unwrap() diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 30824f5852283..1336abf6c7aba 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -90,6 +90,10 @@ const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx"])), // (Some(Mode::Std), "target_os", Some(&[])), + // #[cfg(bootstrap)] zkvm + (Some(Mode::Std), "target_os", Some(&["zkvm"])), + // #[cfg(bootstrap)] risc0 + (Some(Mode::Std), "target_vendor", Some(&["risc0"])), (Some(Mode::Std), "target_arch", Some(&["spirv", "nvptx", "xtensa"])), /* Extra names used by dependencies */ // FIXME: Used by serde_json, but we should not be triggering on external dependencies. @@ -721,6 +725,11 @@ impl Build { if self.config.profiler_enabled(target) { features.push_str(" profiler"); } + // Generate memcpy, etc. FIXME: Remove this once compiler-builtins + // automatically detects this target. + if target.contains("zkvm") { + features.push_str(" compiler-builtins-mem"); + } features } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 327b4674acfdb..0d5e2600b73a9 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -2,6 +2,9 @@ //! with the goal of keeping developers synchronized with important modifications in //! the bootstrap. +#[cfg(test)] +mod tests; + #[derive(Clone, Debug)] pub struct ChangeInfo { /// Represents the ID of PR caused major change on bootstrap. diff --git a/src/bootstrap/src/utils/change_tracker/tests.rs b/src/bootstrap/src/utils/change_tracker/tests.rs new file mode 100644 index 0000000000000..d2bfc07d1727b --- /dev/null +++ b/src/bootstrap/src/utils/change_tracker/tests.rs @@ -0,0 +1,10 @@ +use crate::{find_recent_config_change_ids, CONFIG_CHANGE_HISTORY}; + +#[test] +fn test_find_recent_config_change_ids() { + // If change-id is greater than the most recent one, result should be empty. + assert!(find_recent_config_change_ids(usize::MAX).is_empty()); + + // There is no change-id equal to or less than 0, result should include the entire change history. + assert_eq!(find_recent_config_change_ids(0).len(), CONFIG_CHANGE_HISTORY.len()); +} diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 0c917c3d57933..d1f713af91709 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -21,7 +21,6 @@ use crate::LldMode; pub use crate::utils::dylib::{dylib_path, dylib_path_var}; #[cfg(test)] -#[path = "../tests/helpers.rs"] mod tests; /// A helper macro to `unwrap` a result except also print out details like: diff --git a/src/bootstrap/src/tests/helpers.rs b/src/bootstrap/src/utils/helpers/tests.rs similarity index 62% rename from src/bootstrap/src/tests/helpers.rs rename to src/bootstrap/src/utils/helpers/tests.rs index 2d626fad417d7..9cfaa3eb67b5c 100644 --- a/src/bootstrap/src/tests/helpers.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -1,5 +1,14 @@ -use crate::utils::helpers::{check_cfg_arg, extract_beta_rev, hex_encode, make}; -use std::path::PathBuf; +use crate::{ + utils::helpers::{ + check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, symlink_dir, + }, + Config, +}; +use std::{ + fs::{self, remove_file, File}, + io::Write, + path::PathBuf, +}; #[test] fn test_make() { @@ -70,3 +79,38 @@ fn test_check_cfg_arg() { "--check-cfg=cfg(target_os,values(\"nixos\",\"nix2\"))" ); } + +#[test] +fn test_program_out_of_date() { + let config = Config::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]); + let tempfile = config.tempdir().join(".tmp-stamp-file"); + File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap(); + assert!(tempfile.exists()); + + // up-to-date + assert!(!program_out_of_date(&tempfile, "dummy value")); + // out-of-date + assert!(program_out_of_date(&tempfile, "")); + + remove_file(tempfile).unwrap(); +} + +#[test] +fn test_symlink_dir() { + let config = Config::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]); + let tempdir = config.tempdir().join(".tmp-dir"); + let link_path = config.tempdir().join(".tmp-link"); + + fs::create_dir_all(&tempdir).unwrap(); + symlink_dir(&config, &tempdir, &link_path).unwrap(); + + let link_source = fs::read_link(&link_path).unwrap(); + assert_eq!(link_source, tempdir); + + fs::remove_dir(tempdir).unwrap(); + + #[cfg(windows)] + fs::remove_dir(link_path).unwrap(); + #[cfg(not(windows))] + fs::remove_file(link_path).unwrap(); +} diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile index ba65ba9bed460..bec1c89733775 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile @@ -44,6 +44,7 @@ ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \ ENV TARGETS=x86_64-fuchsia ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu +ENV TARGETS=$TARGETS,wasm32-unknown-unknown COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -51,6 +52,9 @@ RUN sh /scripts/sccache.sh ENV RUST_INSTALL_DIR /checkout/obj/install RUN mkdir -p $RUST_INSTALL_DIR/etc +# Fuchsia only supports LLVM. +ENV CODEGEN_BACKENDS llvm + ENV RUST_CONFIGURE_ARGS \ --prefix=$RUST_INSTALL_DIR \ --sysconfdir=etc \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh index 4a246f591d717..d6de992913bf5 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh @@ -5,7 +5,7 @@ set -euf -o pipefail -INTEGRATION_SHA=66793c4894bf6204579bbee3b79956335f31c768 +INTEGRATION_SHA=56310bca298872ffb5ea02e665956d9b6dc41171 PICK_REFS=() checkout=fuchsia diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 55eed95492d3e..0db61204f77f2 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -74,25 +74,6 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then cksum=$(sha512sum $hash_key | \ awk '{print $1}') - - url="https://$CACHE_DOMAIN/docker/$cksum" - - echo "Attempting to download $url" - rm -f /tmp/rustci_docker_cache - set +e - retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \ - -o /tmp/rustci_docker_cache "$url" - - docker_archive_hash=$(sha512sum /tmp/rustci_docker_cache | awk '{print $1}') - echo "Downloaded archive hash: ${docker_archive_hash}" - - echo "Loading images into docker" - # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM, - # KILL after 12 minutes - loaded_images=$(/usr/bin/timeout -k 720 600 docker load -i /tmp/rustci_docker_cache \ - | sed 's/.* sha/sha/') - set -e - printf "Downloaded containers:\n$loaded_images\n" fi dockerfile="$docker_dir/$image/Dockerfile" @@ -103,46 +84,65 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then context="$script_dir" fi echo "::group::Building docker image for $image" - - # As of August 2023, Github Actions have updated Docker to 23.X, - # which uses the BuildKit by default. It currently throws aways all - # intermediate layers, which breaks our usage of S3 layer caching. - # Therefore we opt-in to the old build backend for now. - export DOCKER_BUILDKIT=0 - retry docker \ - build \ - --rm \ - -t rust-ci \ - -f "$dockerfile" \ - "$context" - echo "::endgroup::" - - if [ "$CI" != "" ]; then - s3url="s3://$SCCACHE_BUCKET/docker/$cksum" - upload="aws s3 cp - $s3url" - digest=$(docker inspect rust-ci --format '{{.Id}}') - echo "Built container $digest" - if ! grep -q "$digest" <(echo "$loaded_images"); then - echo "Uploading finished image $digest to $url" - set +e - # Print image history for easier debugging of layer SHAs - docker history rust-ci - docker history -q rust-ci | \ - grep -v missing | \ - xargs docker save | \ - gzip | \ - $upload - set -e - else - echo "Looks like docker image is the same as before, not uploading" - fi - # Record the container image for reuse, e.g. by rustup.rs builds - info="$dist/image-$image.txt" - mkdir -p "$dist" - echo "$url" >"$info" - echo "$digest" >>"$info" - cat "$info" + echo "Image input" + cat $hash_key + echo "Image input checksum ${cksum}" + + # Print docker version + docker --version + + # On non-CI or PR jobs, we don't have permissions to write to the registry cache, so we should + # not use `docker login` nor caching. + if [[ "$CI" == "" ]] || [[ "$PR_CI_JOB" == "1" ]]; + then + retry docker build --rm -t rust-ci -f "$dockerfile" "$context" + else + REGISTRY=ghcr.io + # Most probably rust-lang-ci, but in general the owner of the repository where CI runs + REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER} + # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup + IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum} + # Tag used to cache the Docker build + # It seems that it cannot be the same as $IMAGE_TAG, otherwise it overwrites the cache + CACHE_IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci-cache:${cksum} + + # Log into the Docker registry, so that we can read/write cache and the final image + echo ${DOCKER_TOKEN} | docker login ${REGISTRY} \ + --username ${REGISTRY_USERNAME} \ + --password-stdin + + # Enable a new Docker driver so that --cache-from/to works with a registry backend + docker buildx create --use --driver docker-container + + # Build the image using registry caching backend + retry docker \ + buildx \ + build \ + --rm \ + -t rust-ci \ + -f "$dockerfile" \ + --cache-from type=registry,ref=${CACHE_IMAGE_TAG} \ + --cache-to type=registry,ref=${CACHE_IMAGE_TAG},compression=zstd \ + --output=type=docker \ + "$context" + + # Print images for debugging purposes + docker images + + # Tag the built image and push it to the registry + docker tag rust-ci "${IMAGE_TAG}" + docker push "${IMAGE_TAG}" + + # Record the container registry tag/url for reuse, e.g. by rustup.rs builds + # It should be possible to run `docker pull <$IMAGE_TAG>` to download the image + info="$dist/image-$image.txt" + mkdir -p "$dist" + echo "${IMAGE_TAG}" > "$info" + cat "$info" + + echo "To download the image, run docker pull ${IMAGE_TAG}" fi + echo "::endgroup::" elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then if isCI; then echo Cannot run disabled images on CI! diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 68a3afc910f22..43e48c01176f3 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -34,6 +34,7 @@ x--expand-yaml-anchors--remove: 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 }} + DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - &public-variables SCCACHE_BUCKET: rust-lang-ci-sccache2 @@ -92,7 +93,7 @@ x--expand-yaml-anchors--remove: <<: *base-job - &job-macos-m1 - os: macos-13-xlarge + os: macos-14 <<: *base-job - &job-windows-8c @@ -301,6 +302,7 @@ on: permissions: contents: read + packages: write defaults: run: @@ -476,7 +478,7 @@ jobs: # nightly features to compile, and this job would fail if # executed on beta and stable. CI_ONLY_WHEN_CHANNEL: nightly - <<: *job-linux-16c + <<: *job-linux-8c - name: x86_64-gnu-debug <<: *job-linux-8c @@ -509,7 +511,7 @@ jobs: - name: dist-x86_64-apple env: SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin - RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin + RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 SELECT_XCODE: /Applications/Xcode_13.4.1.app @@ -523,7 +525,7 @@ jobs: - name: dist-apple-various env: SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim - RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 SELECT_XCODE: /Applications/Xcode_13.4.1.app @@ -535,7 +537,7 @@ jobs: - name: x86_64-apple-1 env: &env-x86_64-apple-tests SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 @@ -553,17 +555,14 @@ jobs: # This target only needs to support 11.0 and up as nothing else supports the hardware - name: dist-aarch64-apple env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --stage 2 + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin RUST_CONFIGURE_ARGS: >- - --build=x86_64-apple-darwin - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler - --disable-docs --set rust.jemalloc --set llvm.ninja=false + --set rust.lto=thin RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_13.4.1.app USE_XCODE_CLANG: 1 @@ -573,15 +572,25 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - # Corresponds to 16K page size - # - # Shouldn't be needed if jemalloc-sys is updated to - # handle this platform like iOS or if we build on - # aarch64-apple-darwin itself. - # - # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237 - JEMALLOC_SYS_WITH_LG_PAGE: 14 - <<: *job-macos-xl + <<: *job-macos-m1 + + # This target only needs to support 11.0 and up as nothing else supports the hardware + - 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_13.4.1.app + USE_XCODE_CLANG: 1 + 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 # diff --git a/src/ci/run.sh b/src/ci/run.sh index 420545172e6d5..1cdcffc1a7544 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -119,7 +119,8 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir" fi - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=${CODEGEN_BACKENDS:-llvm}" + CODEGEN_BACKENDS="${CODEGEN_BACKENDS:-llvm}" + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=$CODEGEN_BACKENDS" else # We almost always want debug assertions enabled, but sometimes this takes too # long for too little benefit, so we just turn them off. @@ -144,11 +145,12 @@ else # tests as it will fail them. if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then # Test the Cranelift and GCC backends in CI. Bootstrap knows which targets to run tests on. - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift,gcc" + CODEGEN_BACKENDS="${CODEGEN_BACKENDS:-llvm,cranelift,gcc}" else # Test the Cranelift backend in CI. Bootstrap knows which targets to run tests on. - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift" + CODEGEN_BACKENDS="${CODEGEN_BACKENDS:-llvm,cranelift}" fi + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=$CODEGEN_BACKENDS" # We enable this for non-dist builders, since those aren't trying to produce # fresh binaries. We currently don't entirely support distributing a fresh diff --git a/src/ci/scripts/install-ninja.sh b/src/ci/scripts/install-ninja.sh index b8261d8a6f284..5145a03e353de 100755 --- a/src/ci/scripts/install-ninja.sh +++ b/src/ci/scripts/install-ninja.sh @@ -13,4 +13,6 @@ if isWindows; then rm ninja.zip ciCommandSetEnv "RUST_CONFIGURE_ARGS" "${RUST_CONFIGURE_ARGS} --enable-ninja" ciCommandAddPath "$(pwd)/ninja" +elif isMacOS; then + brew install ninja fi diff --git a/src/doc/edition-guide b/src/doc/edition-guide index bbffb074e16be..baafacc6d8701 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit bbffb074e16bef89772818b400b6c76a65eac126 +Subproject commit baafacc6d8701269dab1e1e333f3547fb54b5a59 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 3f9df2b9885c6..2e95fc2fd31d6 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 3f9df2b9885c6741365da2e12ed6662cd0e827d6 +Subproject commit 2e95fc2fd31d669947e993aa07ef10dc9828bee7 diff --git a/src/doc/reference b/src/doc/reference index 8c77e8be9da1a..a0b119535e774 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 8c77e8be9da1a9c70545556218d563c8d061f1fd +Subproject commit a0b119535e7740f68494c4f0582f7ad008b00ccd diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index ddf5cb0e6ee54..179256a445d61 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit ddf5cb0e6ee54ba2dd84c8ca3e1314120014e20d +Subproject commit 179256a445d6144f5f371fdefb993f48f33978b0 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 4af29d1a7f64f..ec287e3327776 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 4af29d1a7f64f88a36539662c6a84fe1fbe6cde1 +Subproject commit ec287e332777627185be4798ad22599ffe7b84aa diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 1c8e1d1e316b7..1998b008dc811 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -47,6 +47,7 @@ - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md) - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv32*-unknown-none-elf](platform-support/riscv32imac-unknown-none-elf.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 2ddf5737fbd91..f648a60b6c48d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -72,6 +72,12 @@ ensure that each tier 2 target can be used as build target after each change. Au not always run so it's not guaranteed to produce a working build, but tier 2 targets often work to quite a good degree and patches are always welcome! +Tier 2 target-specific code is not closely scrutinized by Rust team(s) when +modifications are made. Bugs are possible in all code, but the level of quality +control for these targets is likely to be lower. See [library team +policy](https://std-dev-guide.rust-lang.org/policy/target-code.html) for +details on the review practices for standard library code. + Tier 2 targets with host tools additionally support running tools like `rustc` and `cargo` natively on the target, and automated builds ensure that the host tools build as well. This allows the target to be used as a development @@ -121,6 +127,12 @@ The `std` column in the table below has the following meanings: [`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html +Tier 2 target-specific code is not closely scrutinized by Rust team(s) when +modifications are made. Bugs are possible in all code, but the level of quality +control for these targets is likely to be lower. See [library team +policy](https://std-dev-guide.rust-lang.org/policy/target-code.html) for +details on the review practices for standard library code. + **NOTE:** The `rust-docs` component is not usually built for tier 2 targets, so Rustup may install the documentation for a similar tier 1 target instead. @@ -211,6 +223,12 @@ The `std` column in the table below has the following meanings: [`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html +Tier 3 target-specific code is not closely scrutinized by Rust team(s) when +modifications are made. Bugs are possible in all code, but the level of quality +control for these targets is likely to be lower. See [library team +policy](https://std-dev-guide.rust-lang.org/policy/target-code.html) for +details on the review practices for standard library code. + The `host` column indicates whether the codebase includes support for building host tools. @@ -320,6 +338,7 @@ target | std | host | notes [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) +[`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? | | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA) [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index a54abcb606ea7..e72bfb8bae767 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -50,6 +50,7 @@ cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" [target.csky-unknown-linux-gnuabiv2hf] # ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" +``` ### Build diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md index 06423f0f8fa53..3ac1d2c24603c 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md @@ -128,7 +128,8 @@ q6_arch=v65 g0_lib_path=${sdk_libs}/${q6_arch}/G0 pic_lib_path=${sdk_libs}/${q6_arch}/G0/pic -cargo build --target=hexagon-unknown-none-elf -Zbuild-std +build_cfg=release +cargo build --target=hexagon-unknown-none-elf -Zbuild-std --release # Builds an executable against "hexagon standalone OS" suitable for emulation: ${cc} --target=hexagon-unknown-none-elf -o testit \ @@ -142,12 +143,12 @@ ${cc} --target=hexagon-unknown-none-elf -o testit \ -L${sdk_libs}/${q6_arch}/ \ -L${sdk_libs}/ \ testit.c \ - target/hexagon-unknown-none-elf/debug/libmin_ex_lib_lin.rlib \ - target/hexagon-unknown-none-elf/debug/deps/libcore-*.rlib \ - target/hexagon-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib \ + target/hexagon-unknown-none-elf/${build_cfg}/libdemo1_hexagon.rlib \ + target/hexagon-unknown-none-elf/${build_cfg}/deps/libcore-*.rlib \ + target/hexagon-unknown-none-elf/${build_cfg}/deps/libcompiler_builtins-*.rlib \ -Wl,--start-group \ -Wl,--defsym,_SDA_BASE_=0,--defsym,__sbss_start=0,--defsym,__sbss_end=0 \ - -lstandalone \ + ${g0_lib_path}/libstandalone.a \ ${g0_lib_path}/libc.a \ -lgcc \ -lc_eh \ @@ -248,9 +249,9 @@ ${cc} --target=hexagon-unknown-none-elf -o testit.so \ -Wl,--wrap=memalign \ -m${q6_arch} \ testit.c \ - target/hexagon-unknown-none-elf/debug/libmin_ex_lib_lin.rlib \ - target/hexagon-unknown-none-elf/debug/deps/libcore-*.rlib \ - target/hexagon-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib \ + target/hexagon-unknown-none-elf/${build_cfg}/libdemo2_hexagon.rlib \ + target/hexagon-unknown-none-elf/${build_cfg}/deps/libcore-*.rlib \ + target/hexagon-unknown-none-elf/${build_cfg}/deps/libcompiler_builtins-*.rlib \ -Wl,-soname=testit \ ${pic_lib_path}/libc.so diff --git a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md new file mode 100644 index 0000000000000..1fdd594012c22 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md @@ -0,0 +1,86 @@ +# `riscv32im-risc0-zkvm-elf` + +**Tier: 3** + +RISC Zero's Zero Knowledge Virtual Machine (zkVM) implementing the RV32IM instruction set. + +## Target maintainers + +- Frank Laub, `frank@risczero.com`, https://github.com/flaub +- Jeremy Bruestle, `jeremy@risczero.com`, https://github.com/jbruestle +- Erik Kaneda, `erik@risczero.com`, https://github.com/SchmErik + +## Background + +This target is an execution environment to produce a proof of execution of +a RISC-V ELF binary and any output that the developer of the binary wishes to +display publicly. In order to do this, the target will execute the ELF to +generate a receipt containing the output of the computation along with a +cryptographic seal. This receipt can be verified to ensure the integrity of the +computation and its result. This target is implemented as software only; it has +no hardware implementation. + +We have a cargo extension called [cargo-risczero] that allow users to generate +project templates, install tools for improved user experience, build the binary +using a docker environment and test programs. + +## Requirements + +The target only supports cross compilation and no host tools. The target +supports `alloc` with a default allocator and has experimental support for +`std`. The target expects the binaries to be in ELF. + +The target's execution environment is single threaded, non-preemptive, and does +not support any privileged instructions, nor unaligned accesses. At the time of +writing the VM has 192 MB of memory and text/data, heap, and stack need to be +with in the address range `0x400` - `0x0C000000`. The binaries themselves expect +no operating system and can be thought of as running on bare-metal. The target +does not use `#[target_feature(...)]` or `-C target-feature=` values. + +Calling `extern "C"` on the target uses the C calling convention outlined in the +[RISC-V specification]. + +## Building for the zkVM + +Programs for the zkVM could be built by adding it to the `target` list in +`config.toml`. However, we recommend building programs in our starter template +generated by the [cargo-risczero] utility and the [risc0-build] crate. This +crate calls `rustc` with `-C "link-arg=-Ttext=` so that it maps the text in the +appropriate location as well as generating variables that represent the ELF and +a unique ID associated with the ELF. The starter template provides developers +with system calls that are useful to zero knowledge computing such as writing to +the public output, hashing using sha256, and multiply big integers. + +## 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). We do not recommend using `build-std` as we have +run into issues building core in the past on our starter template. An alternate +solution is to download the risc0 tool chain by running `cargo risczero install`. + +## Testing + +Note: the target is implemented as a software emulator called the zkVM and there +is no hardware implementation of the target. + +The most practical way to test the target program is to use our starter template +that can be generated by using the `cargo risczero new` command. The template +generates a sample "host" and "guest" code. The guest code compiled to the +target (which is RV32IM) whereas the "host" code is compiled to run on the +programmer's machine running either a Linux distribution or macOS. The host +program is responsible for running the guest binary on the zkVM and retrieving +its public output. + +The target currently does not support running the Rust test suite. + +## Cross-compilation toolchains and C code + +Compatible C code can be built for this target on any compiler that has a RV32IM +target. On clang and ld.lld linker, it can be generated using the +`-march=rv32im`, `-mabi=ilp32` with llvm features flag `features=+m` and llvm +target `riscv32-unknown-none`. + +[RISC-V specification]: https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf +[cargo-risczero]: https://docs.rs/cargo-risczero/latest/cargo_risczero/ +[risc0-build]: https://crates.io/crates/risc0-build diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md index 19e62c4867c99..b9a89c20cee40 100644 --- a/src/doc/style-guide/src/editions.md +++ b/src/doc/style-guide/src/editions.md @@ -36,6 +36,10 @@ For a full history of changes in the Rust 2024 style edition, see the git history of the style guide. Notable changes in the Rust 2024 style edition include: +- [#114764](https://github.com/rust-lang/rust/pull/114764) As the last member + of a delimited expression, delimited expressions are generally combinable, + regardless of the number of members. Previously only applied with exactly + one member (except for closures with explicit blocks). - Miscellaneous `rustfmt` bugfixes. - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order). - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase". diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 12037b5992ec0..171a24cd89d73 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -818,11 +818,11 @@ E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. ## Combinable expressions -Where a function call has a single argument, and that argument is formatted -across multiple-lines, format the outer call as if it were a single-line call, +When the last argument in a function call is formatted across +multiple-lines, format the outer call as if it were a single-line call, if the result fits. Apply the same combining behaviour to any similar expressions which have multi-line, block-indented lists of sub-expressions -delimited by parentheses (e.g., macros or tuple struct literals). E.g., +delimited by parentheses, brackets, or braces. E.g., ```rust foo(bar( @@ -848,20 +848,61 @@ let arr = [combinable( an_expr, another_expr, )]; + +let x = Thing(an_expr, another_expr, match cond { + A => 1, + B => 2, +}); + +let x = format!("Stuff: {}", [ + an_expr, + another_expr, +]); + +let x = func(an_expr, another_expr, SomeStruct { + field: this_is_long, + another_field: 123, +}); ``` Apply this behavior recursively. -For a function with multiple arguments, if the last argument is a multi-line -closure with an explicit block, there are no other closure arguments, and all -the arguments and the first line of the closure fit on the first line, use the -same combining behavior: +If the last argument is a multi-line closure with an explicit block, +only apply the combining behavior if there are no other closure arguments. ```rust +// Combinable foo(first_arg, x, |param| { action(); foo(param) }) +// Not combinable, because the closure is not the last argument +foo( + first_arg, + |param| { + action(); + foo(param) + }, + whatever, +) +// Not combinable, because the first line of the closure does not fit +foo( + first_arg, + x, + move |very_long_param_causing_line_to_overflow| -> Bar { + action(); + foo(param) + }, +) +// Not combinable, because there is more than one closure argument +foo( + first_arg, + |x| x.bar(), + |param| { + action(); + foo(param) + }, +) ``` ## Ranges diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md index 13349ff6b8f41..424f1128e3b5c 100644 --- a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md +++ b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md @@ -20,5 +20,5 @@ This flag accepts a comma-separated list of values and may be specified multiple ```sh # This would produce an absolute path to main.rs in build outputs of # "./main.rs". -rustc --remap-path-prefix=$(PWD)=/remapped -Zremap-path-prefix=object main.rs +rustc --remap-path-prefix=$(PWD)=/remapped -Zremap-path-scope=object main.rs ``` diff --git a/src/doc/unstable-book/src/language-features/trait-upcasting.md b/src/doc/unstable-book/src/language-features/trait-upcasting.md new file mode 100644 index 0000000000000..3697ae38f9d81 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/trait-upcasting.md @@ -0,0 +1,27 @@ +# `trait_upcasting` + +The tracking issue for this feature is: [#65991] + +[#65991]: https://github.com/rust-lang/rust/issues/65991 + +------------------------ + +The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a +trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo` +so long as `Bar: Foo`. + +```rust,edition2018 +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo {} + +trait Bar: Foo {} + +impl Foo for i32 {} + +impl Bar for T {} + +let bar: &dyn Bar = &123; +let foo: &dyn Foo = bar; +``` diff --git a/src/doc/unstable-book/src/library-features/async-fn-traits.md b/src/doc/unstable-book/src/library-features/async-fn-traits.md new file mode 100644 index 0000000000000..e1c3f067e5b2b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/async-fn-traits.md @@ -0,0 +1,13 @@ +# `async_fn_traits` + +See Also: [`fn_traits`](../library-features/fn-traits.md) + +---- + +The `async_fn_traits` feature allows for implementation of the [`AsyncFn*`] traits +for creating custom closure-like types that return futures. + +[`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html + +The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future +that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does). diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 624d8cc5cc55a..5e0c21a13a9fe 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -41,40 +41,7 @@ - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - - {__0} - - + {__0} @@ -99,9 +66,9 @@ - Pin({(void*)pointer}: {pointer}) + Pin({(void*)__pointer}: {__pointer}) - pointer + __pointer diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index 32a04cfd5d162..d329fe997cd79 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -1,4 +1,5 @@ { + "git.detectSubmodulesLimit": 20, "rust-analyzer.check.invocationLocation": "root", "rust-analyzer.check.invocationStrategy": "once", "rust-analyzer.check.overrideCommand": [ diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 124a2d9cba957..3bac71dbc24e2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -15,6 +15,7 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; +use rustc_errors::{codes::*, struct_span_code_err, FatalError}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; @@ -147,6 +148,17 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< ) } +fn is_glob_import(tcx: TyCtxt<'_>, import_id: LocalDefId) -> bool { + if let Some(node) = tcx.opt_hir_node_by_def_id(import_id) + && let hir::Node::Item(item) = node + && let hir::ItemKind::Use(_, use_kind) = item.kind + { + use_kind == hir::UseKind::Glob + } else { + false + } +} + fn generate_item_with_correct_attrs( cx: &mut DocContext<'_>, kind: ItemKind, @@ -157,10 +169,17 @@ fn generate_item_with_correct_attrs( ) -> Item { let target_attrs = inline::load_attrs(cx, def_id); let attrs = if let Some(import_id) = import_id { + // glob reexports are treated the same as `#[doc(inline)]` items. + // + // For glob re-exports the item may or may not exist to be re-exported (potentially the cfgs + // on the path up until the glob can be removed, and only cfgs on the globbed item itself + // matter), for non-inlined re-exports see #85043. let is_inline = inline::load_attrs(cx, import_id.to_def_id()) .lists(sym::doc) .get_word_attr(sym::inline) - .is_some(); + .is_some() + || (is_glob_import(cx.tcx, import_id) + && (cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id))); let mut attrs = get_all_import_attributes(cx, import_id, def_id, is_inline); add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); attrs @@ -1049,7 +1068,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib func.decl .inputs .values - .insert(a as _, Argument { name, type_: *ty, is_const: true }); + .insert(a.get() as _, Argument { name, type_: *ty, is_const: true }); } else { panic!("unexpected non const in position {pos}"); } @@ -1835,7 +1854,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), TyKind::Array(ty, ref length) => { let length = match length { - hir::ArrayLen::Infer(_, _) => "_".to_string(), + hir::ArrayLen::Infer(..) => "_".to_string(), hir::ArrayLen::Body(anon_const) => { // NOTE(min_const_generics): We can't use `const_eval_poly` for constants // as we currently do not supply the parent generics to anonymous constants @@ -2267,11 +2286,12 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Closure(..) => panic!("Closure"), + ty::CoroutineClosure(..) => panic!("CoroutineClosure"), ty::Coroutine(..) => panic!("Coroutine"), ty::Placeholder(..) => panic!("Placeholder"), ty::CoroutineWitness(..) => panic!("CoroutineWitness"), ty::Infer(..) => panic!("Infer"), - ty::Error(_) => rustc_errors::FatalError.raise(), + ty::Error(_) => FatalError.raise(), } } @@ -2995,7 +3015,7 @@ fn clean_use_statement_inner<'tcx>( visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module(); if pub_underscore && let Some(ref inline) = inline_attr { - rustc_errors::struct_span_code_err!( + struct_span_code_err!( cx.tcx.dcx(), inline.span(), E0780, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fa72758c21659..9eb62c258923f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::emitter::{DynEmitter, HumanEmitter}; use rustc_errors::json::JsonEmitter; -use rustc_errors::TerminalUrl; +use rustc_errors::{codes::*, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; @@ -377,7 +377,7 @@ pub(crate) fn run_global_ctxt( {}/rustdoc/how-to-write-documentation.html", crate::DOC_RUST_LANG_ORG_CHANNEL ); - tcx.struct_lint_node( + tcx.node_lint( crate::lint::MISSING_CRATE_LEVEL_DOCS, DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(), "no documentation found for this crate's top-level module", @@ -449,6 +449,7 @@ pub(crate) fn run_global_ctxt( tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); + // We must include lint errors here. if tcx.dcx().has_errors_or_lint_errors().is_some() { rustc_errors::FatalError.raise(); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 82746a7ab0343..f2e083de0ec74 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -150,6 +150,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { collector }); + // We must include lint errors here. if compiler.sess.dcx().has_errors_or_lint_errors().is_some() { FatalError.raise(); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 642265f5f6bef..ee5891c12fc5a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -530,7 +530,6 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for event in &mut self.inner { match &event.0 { Event::End(Tag::Heading(..)) => break, - Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); self.buf.push_back(event); @@ -549,12 +548,10 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator let level = std::cmp::min(level as u32 + (self.heading_offset as u32), MAX_HEADER_LEVEL); - self.buf.push_back((Event::Html(format!("").into()), 0..0)); + self.buf.push_back((Event::Html(format!("").into()), 0..0)); - let start_tags = format!( - "\ - ", - ); + let start_tags = + format!("§"); return Some((Event::Html(start_tags.into()), 0..0)); } event @@ -830,7 +827,7 @@ impl<'tcx> ExtraInfo<'tcx> { fn error_invalid_codeblock_attr(&self, msg: impl Into) { if let Some(def_id) = self.def_id.as_local() { - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, self.tcx.local_def_id_to_hir_id(def_id), self.sp, @@ -846,7 +843,7 @@ impl<'tcx> ExtraInfo<'tcx> { f: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { if let Some(def_id) = self.def_id.as_local() { - self.tcx.struct_span_lint_hir( + self.tcx.node_span_lint( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, self.tcx.local_def_id_to_hir_id(def_id), self.sp, diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 5eba1d0609f38..4dd176b3a692a 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -311,26 +311,38 @@ fn test_header() { assert_eq!(output, expect, "original: {}", input); } - t("# Foo bar", "