diff options
1462 files changed, 30135 insertions, 14625 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1c87b0a76e..90269f56c52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,8 +36,21 @@ concurrency: group: "${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }}" cancel-in-progress: true jobs: + calculate_matrix: + name: Calculate job matrix + runs-on: ubuntu-latest + outputs: + jobs: "${{ steps.jobs.outputs.jobs }}" + steps: + - name: Checkout the source code + uses: actions/checkout@v4 + - name: Calculate the CI job matrix + run: python3 src/ci/scripts/calculate-job-matrix.py >> $GITHUB_OUTPUT + id: jobs pr: name: "PR - ${{ matrix.name }}" + needs: + - calculate_matrix env: PR_CI_JOB: 1 CI_JOB_NAME: "${{ matrix.name }}" @@ -51,20 +64,7 @@ jobs: continue-on-error: "${{ matrix.name == 'mingw-check-tidy' }}" strategy: matrix: - include: - - name: mingw-check - os: ubuntu-20.04-4core-16gb - env: {} - - name: mingw-check-tidy - os: ubuntu-20.04-4core-16gb - env: {} - - name: x86_64-gnu-llvm-17 - env: - ENABLE_GCC_CODEGEN: "1" - os: ubuntu-20.04-16core-64gb - - name: x86_64-gnu-tools - os: ubuntu-20.04-16core-64gb - env: {} + include: "${{ fromJSON(needs.calculate_matrix.outputs.jobs) }}" defaults: run: shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" @@ -156,7 +156,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -566,7 +566,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -705,7 +705,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" diff --git a/.mailmap b/.mailmap index 93f5ca8157c..0bd16a797ca 100644 --- a/.mailmap +++ b/.mailmap @@ -307,6 +307,8 @@ Joseph T. Lyons <JosephTLyons@gmail.com> <JosephTLyons@users.noreply.github.com> Josh Cotton <jcotton42@outlook.com> Josh Driver <keeperofdakeys@gmail.com> Josh Holmer <jholmer.in@gmail.com> +Josh Stone <cuviper@gmail.com> <jistone@redhat.com> +Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org> Julian Knodt <julianknodt@gmail.com> jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com> Junyoung Cho <june0.cho@samsung.com> @@ -474,7 +476,8 @@ Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de> phosphorus <steepout@qq.com> Pierre Krieger <pierre.krieger1708@gmail.com> pierwill <pierwill@users.noreply.github.com> <19642016+pierwill@users.noreply.github.com> -Pietro Albini <pietro@pietroalbini.org> <pietro@pietroalbini.io> <pietro.albini@ferrous-systems.com> +Pietro Albini <pietro@pietroalbini.org> <pietro@pietroalbini.io> +Pietro Albini <pietro@pietroalbini.org> <pietro.albini@ferrous-systems.com> Pradyumna Rahul <prkinformed@gmail.com> Przemysław Wesołek <jest@go.art.pl> Przemek Wesołek <jest@go.art.pl> r00ster <r00ster91@protonmail.com> @@ -543,6 +546,7 @@ Takashi Idobe <idobetakashi@gmail.com> Takayuki Maeda <takoyaki0316@gmail.com> Tamir Duberstein <tamird@gmail.com> Tamir Duberstein <tamird@squareup.com> Tatsuyuki Ishi <ishitatsuyuki@gmail.com> +Tau Gärtli <git@tau.garden> <ruben.schmidmeister@icloud.com> Tero Hänninen <lgvz@users.noreply.github.com> Tero Hänninen <tejohann@kapsi.fi> The8472 <git@infinite-source.de> Theo Belaire <theo.belaire@gmail.com> Theo Belaire <tyr.god.of.war.42@gmail.com> diff --git a/Cargo.lock b/Cargo.lock index c8b3095ae80..71967b03b09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" @@ -469,9 +469,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" [[package]] name = "cfg-if" @@ -491,9 +491,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -514,9 +514,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -541,7 +541,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.0", + "strsim 0.11.1", "terminal_size", ] @@ -556,14 +556,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -590,12 +590,12 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.55", + "syn 2.0.58", "tempfile", "termize", "tokio", "toml 0.7.8", - "ui_test 0.22.2", + "ui_test 0.22.3", "walkdir", ] @@ -634,7 +634,7 @@ dependencies = [ "itertools 0.12.1", "quine-mc_cluskey", "regex", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", "rustc-semver", "semver", "serde", @@ -739,9 +739,9 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "compiler_builtins" -version = "0.1.108" +version = "0.1.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68bc55329711cd719c2687bb147bc06211b0521f97ef398280108ccb23227e9" +checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e" dependencies = [ "cc", "rustc-std-workspace-core", @@ -766,7 +766,7 @@ dependencies = [ "miropt-test-tools", "once_cell", "regex", - "rustfix", + "rustfix 0.8.1", "serde", "serde_json", "tracing", @@ -948,7 +948,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -959,7 +959,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -974,7 +974,7 @@ version = "0.1.79" dependencies = [ "itertools 0.12.1", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1015,7 +1015,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1025,7 +1025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1048,7 +1048,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1137,7 +1137,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1266,9 +1266,9 @@ dependencies = [ [[package]] name = "expect-test" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3" +checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0" dependencies = [ "dissimilar", "once_cell", @@ -1483,7 +1483,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1555,9 +1555,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "a06fddc2749e0528d2813f95e050e87e52c8cbbae56223b9babf73b3e53b0cc6" dependencies = [ "cfg-if", "libc", @@ -1608,9 +1608,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1627,9 +1627,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.0" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ "log", "pest", @@ -1921,7 +1921,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2076,9 +2076,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jemalloc-sys" @@ -2215,13 +2215,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -2377,7 +2376,7 @@ dependencies = [ "memchr", "once_cell", "opener", - "pulldown-cmark 0.10.0", + "pulldown-cmark 0.10.2", "regex", "serde", "serde_json", @@ -2422,9 +2421,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -2708,7 +2707,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2719,9 +2718,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -2872,9 +2871,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" dependencies = [ "memchr", "thiserror", @@ -2883,9 +2882,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" dependencies = [ "pest", "pest_generator", @@ -2893,22 +2892,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "pest_meta" -version = "2.7.8" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" dependencies = [ "once_cell", "pest", @@ -2955,9 +2954,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3070,9 +3069,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce76ce678ffc8e5675b22aa1405de0b7037e2fdf8913fea40d1926c6fe1e6e7" +checksum = "5f0530d13d87d1f549b66a3e8d0c688952abe5994e204ed62615baaf25dc029c" dependencies = [ "bitflags 2.5.0", "memchr", @@ -3109,9 +3108,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0" +checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -3207,9 +3206,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -3271,9 +3270,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "remote-test-client" @@ -3671,6 +3670,7 @@ dependencies = [ "rustc_metadata", "rustc_middle", "rustc_query_system", + "rustc_sanitizers", "rustc_session", "rustc_span", "rustc_symbol_mangling", @@ -3939,7 +3939,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "unic-langid", ] @@ -4074,7 +4074,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "synstructure", ] @@ -4220,7 +4220,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "synstructure", ] @@ -4263,7 +4263,6 @@ dependencies = [ "either", "field-offset", "gsgdt", - "measureme", "polonius-engine", "rustc-rayon", "rustc-rayon-core", @@ -4560,6 +4559,21 @@ dependencies = [ ] [[package]] +name = "rustc_sanitizers" +version = "0.0.0" +dependencies = [ + "bitflags 2.5.0", + "rustc_data_structures", + "rustc_hir", + "rustc_middle", + "rustc_span", + "rustc_target", + "rustc_trait_selection", + "tracing", + "twox-hash", +] + +[[package]] name = "rustc_serialize" version = "0.0.0" dependencies = [ @@ -4634,7 +4648,6 @@ dependencies = [ name = "rustc_symbol_mangling" version = "0.0.0" dependencies = [ - "bitflags 2.5.0", "punycode", "rustc-demangle", "rustc_data_structures", @@ -4644,9 +4657,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "rustc_trait_selection", "tracing", - "twox-hash", ] [[package]] @@ -4845,13 +4856,25 @@ dependencies = [ ] [[package]] +name = "rustfix" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81864b097046da5df3758fdc6e4822bbb70afa06317e8ca45ea1b51cb8c5e5a4" +dependencies = [ + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] name = "rustfmt-config_proc_macro" version = "0.3.0" dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -4908,9 +4931,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "ruzstd" @@ -4972,9 +4995,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4985,9 +5008,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -5034,14 +5057,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "indexmap", "itoa", @@ -5296,9 +5319,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" @@ -5341,9 +5364,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -5364,7 +5387,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -5530,7 +5553,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -5568,7 +5591,6 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "cargo-platform", "cargo_metadata 0.15.4", "ignore", "lazy_static", @@ -5641,9 +5663,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -5753,7 +5775,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -5886,7 +5908,7 @@ dependencies = [ "prettydiff", "regex", "rustc_version", - "rustfix", + "rustfix 0.6.1", "serde", "serde_json", "tempfile", @@ -5894,9 +5916,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1ded30ff8c9d83e8d85d7e8e8aabbaf2c282a2b0ea09ef3f1accd4906134c7" +checksum = "aa577a42db0e211a73c069d7dbcae54bc7473a7c5535a564842cbd8a13c0441e" dependencies = [ "annotate-snippets 0.10.2", "anyhow", @@ -5913,7 +5935,7 @@ dependencies = [ "prettydiff", "regex", "rustc_version", - "rustfix", + "rustfix 0.6.1", "serde", "serde_json", "spanned", @@ -5959,7 +5981,7 @@ checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.55", + "syn 2.0.58", "unic-langid-impl", ] @@ -6191,7 +6213,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -6225,7 +6247,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6316,7 +6338,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.55", + "syn 2.0.58", "windows-metadata", ] @@ -6570,7 +6592,7 @@ checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "synstructure", ] @@ -6591,7 +6613,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -6611,7 +6633,7 @@ checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "synstructure", ] @@ -6634,7 +6656,7 @@ checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e12c968e205..bbf4ecfe61d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ adler.debug = 0 gimli.debug = 0 miniz_oxide.debug = 0 object.debug = 0 +rustc-demangle.debug = 0 # These are very thin wrappers around executing lld with the right binary name. # Basically nothing within them can go wrong without having been explicitly logged anyway. diff --git a/RELEASES.md b/RELEASES.md index f35dd27ec24..3bd638ff64c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,10 @@ +Version 1.77.2 (2024-04-09) +=========================== + +<a id="1.77.2"></a> + +- [CVE-2024-24576: fix escaping of Windows batch file arguments in `std::process::Command`](https://blog.rust-lang.org/2024/04/09/cve-2024-24576.html) + Version 1.77.1 (2024-03-28) =========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e29ef591bcb..5b708cf4e1a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -920,14 +920,8 @@ impl BinOpKind { matches!(self, BinOpKind::And | BinOpKind::Or) } - pub fn is_comparison(&self) -> bool { - use BinOpKind::*; - // Note for developers: please keep this match exhaustive; - // we want compilation to fail if another variant is added. - match *self { - Eq | Lt | Le | Ne | Gt | Ge => true, - And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false, - } + pub fn is_comparison(self) -> bool { + crate::util::parser::AssocOp::from_ast_binop(self).is_comparison() } /// Returns `true` if the binary operator takes its arguments by value. @@ -2152,6 +2146,9 @@ pub enum TyKind { MacCall(P<MacCall>), /// Placeholder for a `va_list`. CVarArgs, + /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`, + /// just as part of the type system. + Pat(P<Ty>, P<Pat>), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 7337b969242..da57def263d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -502,6 +502,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { } TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), + TyKind::Pat(ty, pat) => { + vis.visit_ty(ty); + vis.visit_pat(pat); + } TyKind::Path(qself, path) => { vis.visit_qself(qself); vis.visit_path(path); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 18986fb7504..9e9ae52962d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -446,6 +446,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { } try_visit!(visitor.visit_path(path, typ.id)); } + TyKind::Pat(ty, pat) => { + try_visit!(visitor.visit_ty(ty)); + try_visit!(visitor.visit_pat(pat)); + } TyKind::Array(ty, length) => { try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_anon_const(length)); diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index ff7a1552047..9ff2e32f06b 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -51,6 +51,14 @@ impl Mutability { } } + /// Returns `"const"` or `"mut"` depending on the mutability. + pub fn ptr_str(self) -> &'static str { + match self { + Mutability::Not => "const", + Mutability::Mut => "mut", + } + } + /// Returns `""` (empty string) or `"mutably "` depending on the mutability. pub fn mutably_str(self) -> &'static str { match self { diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 1c34fd0afbb..4c552289a81 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -381,4 +381,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { ArrayLen::Body(..) => intravisit::walk_array_len(self, len), } } + + fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { + self.visit_pat(p) + } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8cf347bfa96..5005c22d4cc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1463,7 +1463,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), + TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)), + TyKind::MacCall(_) => { + span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") + } TyKind::CVarArgs => { let guar = self.dcx().span_delayed_bug( t.span, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index ac3799e7a05..a3731e94276 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -273,6 +273,7 @@ ast_passes_visibility_not_permitted = .trait_impl = trait items always share the visibility of their trait .individual_impl_items = place qualifiers on individual impl items instead .individual_foreign_items = place qualifiers on individual foreign items instead + .remove_qualifier_sugg = remove the qualifier ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases .note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 093a985495c..cb4dcf3ae75 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -266,7 +266,11 @@ impl<'a> AstValidator<'a> { return; } - self.dcx().emit_err(errors::VisibilityNotPermitted { span: vis.span, note }); + self.dcx().emit_err(errors::VisibilityNotPermitted { + span: vis.span, + note, + remove_qualifier_sugg: vis.span, + }); } fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) { @@ -346,7 +350,7 @@ impl<'a> AstValidator<'a> { in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), const_context_label: parent_constness, remove_const_sugg: ( - self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), + self.session.source_map().span_extend_while_whitespace(span), match parent_constness { Some(_) => rustc_errors::Applicability::MachineApplicable, None => rustc_errors::Applicability::MaybeIncorrect, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 8ae9f7d3966..f397c949e04 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -31,6 +31,12 @@ pub struct VisibilityNotPermitted { pub span: Span, #[subdiagnostic] pub note: VisibilityNotPermittedNote, + #[suggestion( + ast_passes_remove_qualifier_sugg, + code = "", + applicability = "machine-applicable" + )] + pub remove_qualifier_sugg: Span, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5912dd3f931..d7cd3efe408 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -332,6 +332,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Never => { gate!(&self, never_type, ty.span, "the `!` type is experimental"); } + ast::TyKind::Pat(..) => { + gate!(&self, pattern_types, ty.span, "pattern types are unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3ea182c5867..51ccfe89fbd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1188,6 +1188,11 @@ impl<'a> State<'a> { ast::TyKind::CVarArgs => { self.word("..."); } + ast::TyKind::Pat(ty, pat) => { + self.print_type(ty); + self.word(" is "); + self.print_pat(pat); + } } self.end(); } diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 587536e1f9a..c14a617eb91 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -87,6 +87,12 @@ borrowck_move_unsized = borrowck_moved_a_fn_once_in_call = this value implements `FnOnce`, which causes it to be moved when called +borrowck_moved_a_fn_once_in_call_call = + `FnOnce` closures can only be called once + +borrowck_moved_a_fn_once_in_call_def = + `{$ty}` is made to be an `FnOnce` closure here + borrowck_moved_due_to_await = {$place_name} {$is_partial -> [true] partially moved diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 8b7d9ec2cd6..540b466560c 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -216,23 +216,14 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { type Node = RegionVid; -} -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { fn num_nodes(&self) -> usize { self.constraint_graph.first_constraints.len() } } -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { - fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter { +impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> { + fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { self.outgoing_regions(node) } } - -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_> - for RegionGraph<'s, 'tcx, D> -{ - type Item = RegionVid; - type Iter = Successors<'s, 'tcx, D>; -} diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 31307ef1410..64726eacca7 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -4,7 +4,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::{Body, Promoted}; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::TyCtxt; use std::rc::Rc; @@ -106,7 +105,7 @@ pub fn get_body_with_borrowck_facts( options: ConsumerOptions, ) -> BodyWithBorrowckFacts<'_> { let (input_body, promoted) = tcx.mir_promoted(def); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build(); let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap() diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index bc5bd787956..ec7d4582a60 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::graph::WithSuccessors; +use rustc_data_structures::graph; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, @@ -262,7 +262,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> { // We first handle the cases where the loan doesn't go out of scope, depending on the issuing // region's successors. - for successor in self.regioncx.region_graph().depth_first_search(issuing_region) { + for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) { // 1. Via applied member constraints // // The issuing region can flow into the choice regions, and they are either: diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 62e16d445c6..0a4f32c9585 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -203,13 +203,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if !seen_spans.contains(&move_span) { if !closure { - self.suggest_ref_or_clone( - mpi, - move_span, - &mut err, - &mut in_pattern, - move_spans, - ); + self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans); } let msg_opt = CapturedMessageOpt { @@ -283,7 +277,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(name) => format!("`{name}`"), None => "value".to_owned(), }; - if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) { + if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) + || if let UseSpans::FnSelfUse { kind, .. } = use_spans + && let CallKind::FnCall { fn_trait_id, self_ty } = kind + && let ty::Param(_) = self_ty.kind() + && ty == self_ty + && Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() + { + // this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`. + true + } else { + false + } + { // Suppress the next suggestion since we don't want to put more bounds onto // something that already has `Fn`-like bounds (or is a closure), so we can't // restrict anyways. @@ -339,18 +345,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_ref_or_clone( &self, mpi: MovePathIndex, - move_span: Span, err: &mut Diag<'tcx>, in_pattern: &mut bool, move_spans: UseSpans<'_>, ) { + let move_span = match move_spans { + UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span, + _ => move_spans.args_or_use(), + }; struct ExpressionFinder<'hir> { expr_span: Span, expr: Option<&'hir hir::Expr<'hir>>, pat: Option<&'hir hir::Pat<'hir>>, parent_pat: Option<&'hir hir::Pat<'hir>>, + hir: rustc_middle::hir::map::Map<'hir>, } impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.hir + } + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { if e.span == self.expr_span { self.expr = Some(e); @@ -385,8 +401,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = hir.body(body_id).value; let place = &self.move_data.move_paths[mpi].place; let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span); - let mut finder = - ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None }; + let mut finder = ExpressionFinder { + expr_span: move_span, + expr: None, + pat: None, + parent_pat: None, + hir, + }; finder.visit_expr(expr); if let Some(span) = span && let Some(expr) = finder.expr @@ -467,16 +488,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else if let UseSpans::ClosureUse { closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)), - args_span: _, - capture_kind_span: _, - path_span, + .. } = move_spans { - self.suggest_cloning(err, ty, expr, path_span); + self.suggest_cloning(err, ty, expr, None); } else if self.suggest_hoisting_call_outside_loop(err, expr) { // The place where the the type moves would be misleading to suggest clone. // #121466 - self.suggest_cloning(err, ty, expr, move_span); + self.suggest_cloning(err, ty, expr, None); } } if let Some(pat) = finder.pat { @@ -661,34 +680,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = moved_place.ty(self.body, self.infcx.tcx).ty; debug!("ty: {:?}, kind: {:?}", ty, ty.kind()); - let tcx = self.infcx.tcx; - let implements_default = |ty, param_env| { - let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { - return false; - }; - self.infcx - .type_implements_trait(default_trait, [ty], param_env) - .must_apply_modulo_regions() - }; - - let assign_value = match ty.kind() { - ty::Bool => "false", - ty::Float(_) => "0.0", - ty::Int(_) | ty::Uint(_) => "0", - ty::Never | ty::Error(_) => "", - ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]", - ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()", - _ => "todo!()", + let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty) + else { + return; }; - if !assign_value.is_empty() { - err.span_suggestion_verbose( - sugg_span.shrink_to_hi(), - "consider assigning a value", - format!(" = {assign_value}"), - Applicability::MaybeIncorrect, - ); - } + err.span_suggestion_verbose( + sugg_span.shrink_to_hi(), + "consider assigning a value", + format!(" = {assign_value}"), + Applicability::MaybeIncorrect, + ); } fn suggest_borrow_fn_like( @@ -916,7 +918,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { sm.span_to_diagnostic_string(span) } }; - let mut spans: MultiSpan = spans.clone().into(); + let mut spans: MultiSpan = spans.into(); // Point at all the `continue`s and explicit `break`s in the relevant loops. for (desc, elements) in [ ("`break` exits", &finder.found_breaks), @@ -987,8 +989,272 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { can_suggest_clone } - fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) { + /// We have `S { foo: val, ..base }`, and we suggest instead writing + /// `S { foo: val, bar: base.bar.clone(), .. }` when valid. + fn suggest_cloning_on_functional_record_update( + &self, + err: &mut Diag<'_>, + ty: Ty<'tcx>, + expr: &'cx hir::Expr<'cx>, + ) { + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return }; + let hir::QPath::Resolved(_, path) = struct_qpath else { return }; + let hir::def::Res::Def(_, def_id) = path.res else { return }; + let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return }; + let ty::Adt(def, args) = expr_ty.kind() else { return }; + let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = base.kind else { return }; + let (hir::def::Res::Local(_) + | hir::def::Res::Def( + DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } | DefKind::AssocConst, + _, + )) = path.res + else { + return; + }; + let Ok(base_str) = self.infcx.tcx.sess.source_map().span_to_snippet(base.span) else { + return; + }; + + // 1. look for the fields of type `ty`. + // 2. check if they are clone and add them to suggestion + // 3. check if there are any values left to `..` and remove it if not + // 4. emit suggestion to clone the field directly as `bar: base.bar.clone()` + + let mut final_field_count = fields.len(); + let Some(variant) = def.variants().iter().find(|variant| variant.def_id == def_id) else { + // When we have an enum, look for the variant that corresponds to the variant the user + // wrote. + return; + }; + let mut sugg = vec![]; + for field in &variant.fields { + // In practice unless there are more than one field with the same type, we'll be + // suggesting a single field at a type, because we don't aggregate multiple borrow + // checker errors involving the functional record update sytnax into a single one. + let field_ty = field.ty(self.infcx.tcx, args); + let ident = field.ident(self.infcx.tcx); + if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) { + // Suggest adding field and cloning it. + sugg.push(format!("{ident}: {base_str}.{ident}.clone()")); + final_field_count += 1; + } + } + let (span, sugg) = match fields { + [.., last] => ( + if final_field_count == variant.fields.len() { + // We'll remove the `..base` as there aren't any fields left. + last.span.shrink_to_hi().with_hi(base.span.hi()) + } else { + last.span.shrink_to_hi() + }, + format!(", {}", sugg.join(", ")), + ), + // Account for no fields in suggestion span. + [] => ( + expr.span.with_lo(struct_qpath.span().hi()), + if final_field_count == variant.fields.len() { + // We'll remove the `..base` as there aren't any fields left. + format!(" {{ {} }}", sugg.join(", ")) + } else { + format!(" {{ {}, ..{base_str} }}", sugg.join(", ")) + }, + ), + }; + let prefix = if !self.implements_clone(ty) { + let msg = format!("`{ty}` doesn't implement `Copy` or `Clone`"); + if let ty::Adt(def, _) = ty.kind() { + err.span_note(self.infcx.tcx.def_span(def.did()), msg); + } else { + err.note(msg); + } + format!("if `{ty}` implemented `Clone`, you could ") + } else { + String::new() + }; + let msg = format!( + "{prefix}clone the value from the field instead of using the functional record update \ + syntax", + ); + err.span_suggestion_verbose(span, msg, sugg, Applicability::MachineApplicable); + } + + pub(crate) fn suggest_cloning( + &self, + err: &mut Diag<'_>, + ty: Ty<'tcx>, + mut expr: &'cx hir::Expr<'cx>, + mut other_expr: Option<&'cx hir::Expr<'cx>>, + ) { + if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind { + // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single + // `Location` that covers both the `S { ... }` literal, all of its fields and the + // `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr` + // will already be correct. Instead, we see if we can suggest writing. + self.suggest_cloning_on_functional_record_update(err, ty, expr); + return; + } + + if let Some(some_other_expr) = other_expr + && let Some(parent_binop) = + self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| { + if let (hir_id, hir::Node::Expr(e)) = n + && let hir::ExprKind::AssignOp(_binop, target, _arg) = e.kind + && target.hir_id == expr.hir_id + { + Some(hir_id) + } else { + None + } + }) + && let Some(other_parent_binop) = + self.infcx.tcx.hir().parent_iter(some_other_expr.hir_id).find_map(|n| { + if let (hir_id, hir::Node::Expr(expr)) = n + && let hir::ExprKind::AssignOp(..) = expr.kind + { + Some(hir_id) + } else { + None + } + }) + && parent_binop == other_parent_binop + { + // Explicitly look for `expr += other_expr;` and avoid suggesting + // `expr.clone() += other_expr;`, instead suggesting `expr += other_expr.clone();`. + other_expr = Some(expr); + expr = some_other_expr; + } + 'outer: { + if let ty::Ref(..) = ty.kind() { + // We check for either `let binding = foo(expr, other_expr);` or + // `foo(expr, other_expr);` and if so we don't suggest an incorrect + // `foo(expr, other_expr).clone()` + if let Some(other_expr) = other_expr + && let Some(parent_let) = + self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| { + if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n { + Some(hir_id) + } else { + None + } + }) + && let Some(other_parent_let) = + self.infcx.tcx.hir().parent_iter(other_expr.hir_id).find_map(|n| { + if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n { + Some(hir_id) + } else { + None + } + }) + && parent_let == other_parent_let + { + // Explicitly check that we don't have `foo(&*expr, other_expr)`, as cloning the + // result of `foo(...)` won't help. + break 'outer; + } + + // We're suggesting `.clone()` on an borrowed value. See if the expression we have + // is an argument to a function or method call, and try to suggest cloning the + // *result* of the call, instead of the argument. This is closest to what people + // would actually be looking for in most cases, with maybe the exception of things + // like `fn(T) -> T`, but even then it is reasonable. + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let mut prev = expr; + while let hir::Node::Expr(parent) = self.infcx.tcx.parent_hir_node(prev.hir_id) { + if let hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) = parent.kind + && let Some(call_ty) = typeck_results.node_type_opt(parent.hir_id) + && let call_ty = call_ty.peel_refs() + && (!call_ty + .walk() + .any(|t| matches!(t.unpack(), ty::GenericArgKind::Lifetime(_))) + || if let ty::Alias(ty::Projection, _) = call_ty.kind() { + // FIXME: this isn't quite right with lifetimes on assoc types, + // but ignore for now. We will only suggest cloning if + // `<Ty as Trait>::Assoc: Clone`, which should keep false positives + // down to a managable ammount. + true + } else { + false + }) + && self.implements_clone(call_ty) + && self.suggest_cloning_inner(err, call_ty, parent) + { + return; + } + prev = parent; + } + } + } + let ty = ty.peel_refs(); + if self.implements_clone(ty) { + self.suggest_cloning_inner(err, ty, expr); + } else if let ty::Adt(def, args) = ty.kind() + && def.did().as_local().is_some() + && def.variants().iter().all(|variant| { + variant + .fields + .iter() + .all(|field| self.implements_clone(field.ty(self.infcx.tcx, args))) + }) + { + err.span_note( + self.infcx.tcx.def_span(def.did()), + format!("if `{ty}` implemented `Clone`, you could clone the value"), + ); + } + } + + fn implements_clone(&self, ty: Ty<'tcx>) -> bool { + let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false }; + self.infcx + .type_implements_trait(clone_trait_def, [ty], self.param_env) + .must_apply_modulo_regions() + } + + /// Given an expression, check if it is a method call `foo.clone()`, where `foo` and + /// `foo.clone()` both have the same type, returning the span for `.clone()` if so. + pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> { + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind + && let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) + && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) + && rcvr_ty == expr_ty + && segment.ident.name == sym::clone + && args.is_empty() + { + Some(span) + } else { + None + } + } + + fn in_move_closure(&self, expr: &hir::Expr<'_>) -> bool { + for (_, node) in self.infcx.tcx.hir().parent_iter(expr.hir_id) { + if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = node + && let hir::CaptureBy::Value { .. } = closure.capture_clause + { + // `move || x.clone()` will not work. FIXME: suggest `let y = x.clone(); move || y` + return true; + } + } + false + } + + fn suggest_cloning_inner( + &self, + err: &mut Diag<'_>, + ty: Ty<'tcx>, + expr: &hir::Expr<'_>, + ) -> bool { let tcx = self.infcx.tcx; + if let Some(_) = self.clone_on_reference(expr) { + // Avoid redundant clone suggestion already suggested in `explain_captures`. + // See `tests/ui/moves/needs-clone-through-deref.rs` + return false; + } + if self.in_move_closure(expr) { + return false; + } // Try to find predicates on *generic params* that would allow copying `ty` let suggestion = if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { @@ -996,27 +1262,39 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { ".clone()".to_owned() }; - if let Some(clone_trait_def) = tcx.lang_items().clone_trait() - && self - .infcx - .type_implements_trait(clone_trait_def, [ty], self.param_env) - .must_apply_modulo_regions() + let mut sugg = Vec::with_capacity(2); + let mut inner_expr = expr; + // Remove uses of `&` and `*` when suggesting `.clone()`. + while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) = + &inner_expr.kind { - let msg = if let ty::Adt(def, _) = ty.kind() - && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)] - .contains(&Some(def.did())) - { - "clone the value to increment its reference count" - } else { - "consider cloning the value if the performance cost is acceptable" - }; - err.span_suggestion_verbose( - span.shrink_to_hi(), - msg, - suggestion, - Applicability::MachineApplicable, - ); + if let hir::ExprKind::AddrOf(_, hir::Mutability::Mut, _) = inner_expr.kind { + // We assume that `&mut` refs are desired for their side-effects, so cloning the + // value wouldn't do what the user wanted. + return false; + } + inner_expr = inner; } + if inner_expr.span.lo() != expr.span.lo() { + sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new())); + } + let span = if inner_expr.span.hi() != expr.span.hi() { + // Account for `(*x)` to suggest `x.clone()`. + expr.span.with_lo(inner_expr.span.hi()) + } else { + expr.span.shrink_to_hi() + }; + sugg.push((span, suggestion)); + let msg = if let ty::Adt(def, _) = ty.kind() + && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)] + .contains(&Some(def.did())) + { + "clone the value to increment its reference count" + } else { + "consider cloning the value if the performance cost is acceptable" + }; + err.multipart_suggestion_verbose(msg, sugg, Applicability::MachineApplicable); + true } fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) { @@ -1121,6 +1399,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ); self.suggest_copy_for_type_in_cloned_ref(&mut err, place); + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + if let Some(expr) = self.find_expr(borrow_span) + && let Some(ty) = typeck_results.node_type_opt(expr.hir_id) + { + self.suggest_cloning(&mut err, ty, expr, self.find_expr(span)); + } self.buffer_error(err); } @@ -1469,27 +1753,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let hir = tcx.hir(); let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; struct FindUselessClone<'hir> { + tcx: TyCtxt<'hir>, + def_id: DefId, pub clones: Vec<&'hir hir::Expr<'hir>>, } impl<'hir> FindUselessClone<'hir> { - pub fn new() -> Self { - Self { clones: vec![] } + pub fn new(tcx: TyCtxt<'hir>, def_id: DefId) -> Self { + Self { tcx, def_id, clones: vec![] } } } impl<'v> Visitor<'v> for FindUselessClone<'v> { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - // FIXME: use `lookup_method_for_diagnostic`? if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind && segment.ident.name == sym::clone && args.len() == 0 + && let Some(def_id) = self.def_id.as_local() + && let Some(method) = self.tcx.lookup_method_for_diagnostic((def_id, ex.hir_id)) + && Some(self.tcx.parent(method)) == self.tcx.lang_items().clone_trait() { self.clones.push(ex); } hir::intravisit::walk_expr(self, ex); } } - let mut expr_finder = FindUselessClone::new(); + let mut expr_finder = FindUselessClone::new(tcx, self.mir_def_id().into()); let body = hir.body(body_id).value; expr_finder.visit_expr(body); @@ -1538,22 +1826,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } for ty in types_to_constrain { - self.suggest_adding_bounds(err, ty, clone, body.span); - if let ty::Adt(..) = ty.kind() { - // The type doesn't implement Clone. - let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty])); - let obligation = Obligation::new( - self.infcx.tcx, - ObligationCause::dummy(), - self.param_env, - trait_ref, - ); - self.infcx.err_ctxt().suggest_derive( - &obligation, - err, - trait_ref.to_predicate(self.infcx.tcx), - ); - } + self.suggest_adding_bounds_or_derive(err, ty, clone, body.span); + } + } + + pub(crate) fn suggest_adding_bounds_or_derive( + &self, + err: &mut Diag<'_>, + ty: Ty<'tcx>, + trait_def_id: DefId, + span: Span, + ) { + self.suggest_adding_bounds(err, ty, trait_def_id, span); + if let ty::Adt(..) = ty.kind() { + // The type doesn't implement the trait. + let trait_ref = + ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, trait_def_id, [ty])); + let obligation = Obligation::new( + self.infcx.tcx, + ObligationCause::dummy(), + self.param_env, + trait_ref, + ); + self.infcx.err_ctxt().suggest_derive( + &obligation, + err, + trait_ref.to_predicate(self.infcx.tcx), + ); } } @@ -1654,6 +1953,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } + pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> { + let tcx = self.infcx.tcx; + let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?; + let mut expr_finder = FindExprBySpan::new(span); + expr_finder.visit_expr(tcx.hir().body(body_id).value); + expr_finder.result + } + fn suggest_slice_method_if_applicable( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0106e285604..dbea317e7bb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -5,6 +5,7 @@ use crate::session_diagnostics::{ CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, }; use rustc_errors::{Applicability, Diag}; +use rustc_errors::{DiagCtxt, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; @@ -29,6 +30,8 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; +use crate::fluent_generated as fluent; + use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -587,7 +590,7 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn args_subdiag( self, - dcx: &rustc_errors::DiagCtxt, + dcx: &DiagCtxt, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel, ) { @@ -601,7 +604,7 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn var_path_only_subdiag( self, - dcx: &rustc_errors::DiagCtxt, + dcx: &DiagCtxt, err: &mut Diag<'_>, action: crate::InitializationRequiringAction, ) { @@ -639,7 +642,7 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn var_subdiag( self, - dcx: &rustc_errors::DiagCtxt, + dcx: &DiagCtxt, err: &mut Diag<'_>, kind: Option<rustc_middle::mir::BorrowKind>, f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause, @@ -1034,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{n}`")) .unwrap_or_else(|| "value".to_owned()); match kind { - CallKind::FnCall { fn_trait_id, .. } + CallKind::FnCall { fn_trait_id, self_ty } if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => { err.subdiagnostic( @@ -1046,7 +1049,79 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_loop_message, }, ); - err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span }); + // Check if the move occurs on a value because of a call on a closure that comes + // from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`: + // ``` + // error[E0382]: use of moved value: `blk` + // --> $DIR/once-cant-call-twice-on-heap.rs:8:5 + // | + // LL | fn foo<F:FnOnce()>(blk: F) { + // | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait + // LL | blk(); + // | ----- `blk` moved due to this call + // LL | blk(); + // | ^^^ value used here after move + // | + // note: `FnOnce` closures can only be called once + // --> $DIR/once-cant-call-twice-on-heap.rs:6:10 + // | + // LL | fn foo<F:FnOnce()>(blk: F) { + // | ^^^^^^^^ `F` is made to be an `FnOnce` closure here + // LL | blk(); + // | ----- this value implements `FnOnce`, which causes it to be moved when called + // ``` + if let ty::Param(param_ty) = self_ty.kind() + && let generics = self.infcx.tcx.generics_of(self.mir_def_id()) + && let param = generics.type_param(param_ty, self.infcx.tcx) + && let Some(hir_generics) = self + .infcx + .tcx + .typeck_root_def_id(self.mir_def_id().to_def_id()) + .as_local() + .and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id)) + && let spans = hir_generics + .predicates + .iter() + .filter_map(|pred| match pred { + hir::WherePredicate::BoundPredicate(pred) => Some(pred), + _ => None, + }) + .filter(|pred| { + if let Some((id, _)) = pred.bounded_ty.as_generic_param() { + id == param.def_id + } else { + false + } + }) + .flat_map(|pred| pred.bounds) + .filter_map(|bound| { + if let Some(trait_ref) = bound.trait_ref() + && let Some(trait_def_id) = trait_ref.trait_def_id() + && trait_def_id == fn_trait_id + { + Some(bound.span()) + } else { + None + } + }) + .collect::<Vec<Span>>() + && !spans.is_empty() + { + let mut span: MultiSpan = spans.clone().into(); + for sp in spans { + span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def); + } + span.push_span_label( + fn_call_span, + fluent::borrowck_moved_a_fn_once_in_call, + ); + err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call); + } else { + err.subdiagnostic( + self.dcx(), + CaptureReasonNote::FnOnceMoveInCall { var_span }, + ); + } } CallKind::Operator { self_arg, trait_id, .. } => { let self_arg = self_arg.unwrap(); @@ -1212,13 +1287,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .iter_projections() .any(|(_, elem)| matches!(elem, ProjectionElem::Deref)) { + let (start, end) = if let Some(expr) = self.find_expr(move_span) + && let Some(_) = self.clone_on_reference(expr) + && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind + { + (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi())) + } else { + (move_span.shrink_to_lo(), move_span.shrink_to_hi()) + }; vec![ // We use the fully-qualified path because `.clone()` can // sometimes choose `<&T as Clone>` instead of `<T as Clone>` // when going through auto-deref, so this ensures that doesn't // happen, causing suggestions for `.clone().clone()`. - (move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")), - (move_span.shrink_to_hi(), ")".to_string()), + (start, format!("<{ty} as Clone>::clone(&")), + (end, ")".to_string()), ] } else { vec![(move_span.shrink_to_hi(), ".clone()".to_string())] diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 0d1b875cbed..bc02c5be93d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -435,7 +435,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) { match error { - GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { + GroupedMoveError::MovesFromPlace { + mut binds_to, move_from, span: other_span, .. + } => { self.add_borrow_suggestions(err, span); if binds_to.is_empty() { let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; @@ -444,6 +446,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { None => "value".to_string(), }; + if let Some(expr) = self.find_expr(span) { + self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span)); + } + err.subdiagnostic( self.dcx(), crate::session_diagnostics::TypeNoCopy::Label { @@ -468,19 +474,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } // No binding. Nothing to suggest. GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { - let span = use_spans.var_or_use(); + let use_span = use_spans.var_or_use(); let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(original_path.as_ref()) { Some(desc) => format!("`{desc}`"), None => "value".to_string(), }; + + if let Some(expr) = self.find_expr(use_span) { + self.suggest_cloning(err, place_ty, expr, self.find_expr(span)); + } + err.subdiagnostic( self.dcx(), crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty: place_ty, place: &place_desc, - span, + span: use_span, }, ); @@ -582,6 +593,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if binds_to.len() == 1 { let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); + + if let Some(expr) = self.find_expr(binding_span) { + self.suggest_cloning(err, bind_to.ty, expr, None); + } + err.subdiagnostic( self.dcx(), crate::session_diagnostics::TypeNoCopy::Label { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index bd068b29c12..602a84ce4dd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -21,7 +21,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use crate::diagnostics::BorrowedContentSource; use crate::util::FindAssignments; -use crate::MirBorrowckCtxt; +use crate::{session_diagnostics, MirBorrowckCtxt}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { let place = self.describe_any_place(access_place.as_ref()); - crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { + session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { place, var_span, } @@ -667,19 +667,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// User cannot make signature of a trait mutable without changing the /// trait. So we find if this error belongs to a trait and if so we move /// suggestion to the trait or disable it if it is out of scope of this crate - fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) { + /// + /// The returned values are: + /// - is the current item an assoc `fn` of an impl that corresponds to a trait def? if so, we + /// have to suggest changing both the impl `fn` arg and the trait `fn` arg + /// - is the trait from the local crate? If not, we can't suggest changing signatures + /// - `Span` of the argument in the trait definition + fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) { if self.body.local_kind(local) != LocalKind::Arg { - return (false, None); + return (false, false, None); } let my_def = self.body.source.def_id(); let my_hir = self.infcx.tcx.local_def_id_to_hir_id(my_def.as_local().unwrap()); let Some(td) = self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) else { - return (false, None); + return (false, false, None); }; ( true, + td.is_local(), td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) { Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => { let mut f_in_trait_opt = None; @@ -695,19 +702,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { break; } f_in_trait_opt.and_then(|f_in_trait| { - match self.infcx.tcx.hir_node(f_in_trait) { - Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. }, - _, - ), - .. - }) => { - let hir::Ty { span, .. } = *inputs.get(local.index() - 1)?; - Some(span) - } - _ => None, + if let Node::TraitItem(ti) = self.infcx.tcx.hir_node(f_in_trait) + && let hir::TraitItemKind::Fn(sig, _) = ti.kind + && let Some(ty) = sig.decl.inputs.get(local.index() - 1) + && let hir::TyKind::Ref(_, mut_ty) = ty.kind + && let hir::Mutability::Not = mut_ty.mutbl + && sig.decl.implicit_self.has_implicit_self() + { + Some(ty.span) + } else { + None } }) } @@ -1061,20 +1065,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let (pointer_sigil, pointer_desc) = if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; - let (is_trait_sig, local_trait) = self.is_error_in_trait(local); - if is_trait_sig && local_trait.is_none() { + let (is_trait_sig, is_local, local_trait) = self.is_error_in_trait(local); + + if is_trait_sig && !is_local { + // Do not suggest to change the signature when the trait comes from another crate. + err.span_label( + local_decl.source_info.span, + format!("this is an immutable {pointer_desc}"), + ); return; } - - let decl_span = match local_trait { - Some(span) => span, - None => local_decl.source_info.span, - }; + let decl_span = local_decl.source_info.span; let label = match *local_decl.local_info() { LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => { let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span); - Some((true, decl_span, suggestion)) + let additional = + local_trait.map(|span| (span, suggest_ampmut_self(self.infcx.tcx, span))); + Some((true, decl_span, suggestion, additional)) } LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { @@ -1113,7 +1121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // don't create labels for compiler-generated spans Some(_) => None, None => { - let label = if name != kw::SelfLower { + let (has_sugg, decl_span, sugg) = if name != kw::SelfLower { suggest_ampmut( self.infcx.tcx, local_decl.ty, @@ -1140,7 +1148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), } }; - Some(label) + Some((has_sugg, decl_span, sugg, None)) } } } @@ -1151,22 +1159,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { })) => { let pattern_span: Span = local_decl.source_info.span; suggest_ref_mut(self.infcx.tcx, pattern_span) - .map(|span| (true, span, "mut ".to_owned())) + .map(|span| (true, span, "mut ".to_owned(), None)) } _ => unreachable!(), }; match label { - Some((true, err_help_span, suggested_code)) => { - err.span_suggestion_verbose( - err_help_span, - format!("consider changing this to be a mutable {pointer_desc}"), - suggested_code, + Some((true, err_help_span, suggested_code, additional)) => { + let mut sugg = vec![(err_help_span, suggested_code)]; + if let Some(s) = additional { + sugg.push(s); + } + + err.multipart_suggestion_verbose( + format!( + "consider changing this to be a mutable {pointer_desc}{}", + if is_trait_sig { + " in the `impl` method and the `trait` definition" + } else { + "" + } + ), + sugg, Applicability::MachineApplicable, ); } - Some((false, err_label_span, message)) => { + Some((false, err_label_span, message, _)) => { let def_id = self.body.source.def_id(); let hir_id = if let Some(local_def_id) = def_id.as_local() && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index c92fccc959f..304d41d6941 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -26,6 +26,9 @@ use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_middle::ty::{Region, TyCtxt}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_trait_selection::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::{Obligation, ObligationCtxt}; use crate::borrowck_errors; use crate::session_diagnostics::{ @@ -810,6 +813,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); self.suggest_move_on_borrowing_closure(&mut diag); + self.suggest_deref_closure_value(&mut diag); diag } @@ -1041,6 +1045,147 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable + /// When encountering a lifetime error caused by the return type of a closure, check the + /// corresponding trait bound and see if dereferencing the closure return value would satisfy + /// them. If so, we produce a structured suggestion. + fn suggest_deref_closure_value(&self, diag: &mut Diag<'_>) { + let tcx = self.infcx.tcx; + let map = tcx.hir(); + + // Get the closure return value and type. + let body_id = map.body_owned_by(self.mir_def_id()); + let body = &map.body(body_id); + let value = &body.value.peel_blocks(); + let hir::Node::Expr(closure_expr) = tcx.hir_node_by_def_id(self.mir_def_id()) else { + return; + }; + let fn_call_id = tcx.parent_hir_id(self.mir_hir_id()); + let hir::Node::Expr(expr) = tcx.hir_node(fn_call_id) else { return }; + let def_id = map.enclosing_body_owner(fn_call_id); + let tables = tcx.typeck(def_id); + let Some(return_value_ty) = tables.node_type_opt(value.hir_id) else { return }; + let return_value_ty = self.infcx.resolve_vars_if_possible(return_value_ty); + + // We don't use `ty.peel_refs()` to get the number of `*`s needed to get the root type. + let mut ty = return_value_ty; + let mut count = 0; + while let ty::Ref(_, t, _) = ty.kind() { + ty = *t; + count += 1; + } + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) { + return; + } + + // Build a new closure where the return type is an owned value, instead of a ref. + let Some(ty::Closure(did, args)) = + tables.node_type_opt(closure_expr.hir_id).as_ref().map(|ty| ty.kind()) + else { + return; + }; + let sig = args.as_closure().sig(); + let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr( + tcx, + sig.map_bound(|s| { + let unsafety = hir::Unsafety::Normal; + use rustc_target::spec::abi; + tcx.mk_fn_sig( + [s.inputs()[0]], + s.output().peel_refs(), + s.c_variadic, + unsafety, + abi::Abi::Rust, + ) + }), + ); + let parent_args = GenericArgs::identity_for_item( + tcx, + tcx.typeck_root_def_id(self.mir_def_id().to_def_id()), + ); + let closure_kind = args.as_closure().kind(); + let closure_kind_ty = Ty::from_closure_kind(tcx, closure_kind); + let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: closure_expr.span, + }); + let closure_args = ty::ClosureArgs::new( + tcx, + ty::ClosureArgsParts { + parent_args, + closure_kind_ty, + closure_sig_as_fn_ptr_ty, + tupled_upvars_ty, + }, + ); + let closure_ty = Ty::new_closure(tcx, *did, closure_args.args); + let closure_ty = tcx.erase_regions(closure_ty); + + let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return }; + let Some(pos) = args + .iter() + .enumerate() + .find(|(_, arg)| arg.hir_id == closure_expr.hir_id) + .map(|(i, _)| i) + else { + return; + }; + // The found `Self` type of the method call. + let Some(possible_rcvr_ty) = tables.node_type_opt(rcvr.hir_id) else { return }; + + // The `MethodCall` expression is `Res::Err`, so we search for the method on the `rcvr_ty`. + let Some(method) = tcx.lookup_method_for_diagnostic((self.mir_def_id(), expr.hir_id)) + else { + return; + }; + + // Get the type for the parameter corresponding to the argument the closure with the + // lifetime error we had. + let Some(input) = tcx + .fn_sig(method) + .instantiate_identity() + .inputs() + .skip_binder() + // Methods have a `self` arg, so `pos` is actually `+ 1` to match the method call arg. + .get(pos + 1) + else { + return; + }; + + trace!(?input); + + let ty::Param(closure_param) = input.kind() else { return }; + + // Get the arguments for the found method, only specifying that `Self` is the receiver type. + let args = GenericArgs::for_item(tcx, method, |param, _| { + if param.index == 0 { + possible_rcvr_ty.into() + } else if param.index == closure_param.index { + closure_ty.into() + } else { + self.infcx.var_for_def(expr.span, param) + } + }); + + let preds = tcx.predicates_of(method).instantiate(tcx, args); + + let ocx = ObligationCtxt::new(&self.infcx); + ocx.register_obligations(preds.iter().map(|(pred, span)| { + trace!(?pred); + Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred) + })); + + if ocx.select_all_or_error().is_empty() { + diag.span_suggestion_verbose( + value.span.shrink_to_lo(), + "dereference the return value", + "*".repeat(count), + Applicability::MachineApplicable, + ); + } + } + + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) { let map = self.infcx.tcx.hir(); let body_id = map.body_owned_by(self.mir_def_id()); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4a5ba441878..7fbf4c47ec8 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -32,7 +32,6 @@ use rustc_infer::infer::{ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; @@ -126,7 +125,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { return tcx.arena.alloc(result); } - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0; debug!("mir_borrowck done"); @@ -1606,6 +1605,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(_) @@ -1648,6 +1648,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 63b80445817..9f0e54febe4 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -7,7 +7,6 @@ use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; @@ -133,6 +132,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { let ty = infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); + + // Sometimes, when the hidden type is an inference variable, it can happen that + // the hidden type becomes the opaque type itself. In this case, this was an opaque + // usage of the opaque type and we can ignore it. This check is mirrored in typeck's + // writeback. + // FIXME(-Znext-solver): This should be unnecessary with the new solver. + if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() + && alias_ty.def_id == opaque_type_key.def_id.to_def_id() + && alias_ty.args == opaque_type_key.args + { + continue; + } // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that @@ -321,13 +332,13 @@ fn check_opaque_type_well_formed<'tcx>( parent_def_id = tcx.local_parent(parent_def_id); } - // FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])` + // FIXME(-Znext-solver): We probably should use `&[]` instead of // and prepopulate this `InferCtxt` with known opaque values, rather than - // using the `Bind` anchor here. For now it's fine. + // allowing opaque types to be defined and checking them after the fact. let infcx = tcx .infer_ctxt() .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id)) + .with_opaque_type_inference(parent_def_id) .build(); let ocx = ObligationCtxt::new(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index f94001de357..97ddc45ee47 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -1,8 +1,8 @@ use crate::constraints::ConstraintSccIndex; use crate::RegionInferenceContext; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::graph; use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::WithSuccessors; use rustc_middle::ty::RegionVid; use std::ops::Range; @@ -23,8 +23,7 @@ impl ReverseSccGraph { scc0: ConstraintSccIndex, ) -> impl Iterator<Item = RegionVid> + 'a { let mut duplicates = FxIndexSet::default(); - self.graph - .depth_first_search(scc0) + graph::depth_first_search(&self.graph, scc0) .flat_map(move |scc1| { self.scc_regions .get(&scc1) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index f28b786e4f7..a950f10787b 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -39,6 +39,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx, locations.span(self.body))?; + if cfg!(debug_assertions) { + let data = self.infcx.take_and_reset_region_constraints(); + if !data.is_empty() { + panic!("leftover region constraints: {data:#?}"); + } + } debug!(?output, ?constraints); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 8bdefdfc0ac..6cc0e67c0f8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::WithSuccessors; use rustc_index::bit_set::BitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; @@ -64,7 +63,10 @@ pub(super) fn trace<'mir, 'tcx>( // Traverse each issuing region's constraints, and record the loan as flowing into the // outlived region. for (loan, issuing_region_data) in borrow_set.iter_enumerated() { - for succ in region_graph.depth_first_search(issuing_region_data.region) { + for succ in rustc_data_structures::graph::depth_first_search( + ®ion_graph, + issuing_region_data.region, + ) { // We don't need to mention that a loan flows into its issuing region. if succ == issuing_region_data.region { continue; diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 0a44bd42b91..cb1c9ef90bd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -181,8 +181,8 @@ fn cs_clone( all_fields = af; vdata = &variant.data; } - EnumTag(..) | AllFieldlessEnum(..) => { - cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",)) + EnumDiscr(..) | AllFieldlessEnum(..) => { + cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",)) } StaticEnum(..) | StaticStruct(..) => { cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`")) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 49fe89b18b0..63311c897ab 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord( Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); // Order in which to perform matching - let tag_then_data = if let Annotatable::Item(item) = item + let discr_then_data = if let Annotatable::Item(item) = item && let ItemKind::Enum(def, _) = &item.kind { let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); match dataful.iter().filter(|&&b| b).count() { - // No data, placing the tag check first makes codegen simpler + // No data, placing the discriminant check first makes codegen simpler 0 => true, 1..=2 => false, _ => (0..dataful.len() - 1).any(|i| { @@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord( attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr, tag_then_data) + cs_partial_cmp(cx, span, substr, discr_then_data) })), }; @@ -72,7 +72,7 @@ fn cs_partial_cmp( cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>, - tag_then_data: bool, + discr_then_data: bool, ) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); @@ -108,12 +108,12 @@ fn cs_partial_cmp( // cmp => cmp // } // ``` - // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` - // against the enum variants. This means that we begin by comparing the enum tags, + // where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match` + // against the enum variants. This means that we begin by comparing the enum discriminants, // before either inspecting their contents (if they match), or returning - // the `cmp::Ordering` of comparing the enum tags. + // the `cmp::Ordering` of comparing the enum discriminants. // ``` - // match partial_cmp(self_tag, other_tag) { + // match partial_cmp(self_discr, other_discr) { // Some(Ordering::Equal) => match (self, other) { // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), @@ -126,12 +126,12 @@ fn cs_partial_cmp( // ``` // match (self, other) { // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), - // _ => partial_cmp(self_tag, other_tag) + // _ => partial_cmp(self_discr, other_discr) // } // ``` // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 - if !tag_then_data + if !discr_then_data && let ExprKind::Match(_, arms, _) = &mut expr1.kind && let Some(last) = arms.last_mut() && let PatKind::Wild = last.pat.kind diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e442b3520b2..8b681db9670 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -53,7 +53,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Struct(vdata, fields) => (substr.type_ident, *vdata, fields), EnumMatching(_, v, fields) => (v.ident, &v.data, fields), AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), - EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { + EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => { cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") } }; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index e16d74eed4e..f73106c1835 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -21,7 +21,7 @@ //! `struct T(i32, char)`). //! - `EnumMatching`, when `Self` is an enum and all the arguments are the //! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumTag` when `Self` is an enum, for comparing the enum tags. +//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants. //! - `StaticEnum` and `StaticStruct` for static methods, where the type //! being derived upon is either an enum or struct respectively. (Any //! argument with type Self is just grouped among the non-self @@ -143,11 +143,11 @@ //! ) //! ``` //! -//! For the tags, +//! For the discriminants, //! //! ```text -//! EnumTag( -//! &[<ident of self tag>, <ident of other tag>], +//! EnumDiscr( +//! &[<ident of self discriminant>, <ident of other discriminant>], //! <expr to combine with>, //! ) //! ``` @@ -315,10 +315,10 @@ pub enum SubstructureFields<'a> { /// variant. EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>), - /// The tag of an enum. The first field is a `FieldInfo` for the tags, as + /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as /// if they were fields. The second field is the expression to combine the - /// tag expression with; it will be `None` if no match is necessary. - EnumTag(FieldInfo, Option<P<Expr>>), + /// discriminant expression with; it will be `None` if no match is necessary. + EnumDiscr(FieldInfo, Option<P<Expr>>), /// A static method where `Self` is a struct. StaticStruct(&'a ast::VariantData, StaticFields), @@ -1137,9 +1137,9 @@ impl<'a> MethodDef<'a> { /// impl ::core::cmp::PartialEq for A { /// #[inline] /// fn eq(&self, other: &A) -> bool { - /// let __self_tag = ::core::intrinsics::discriminant_value(self); - /// let __arg1_tag = ::core::intrinsics::discriminant_value(other); - /// __self_tag == __arg1_tag + /// let __self_discr = ::core::intrinsics::discriminant_value(self); + /// let __arg1_discr = ::core::intrinsics::discriminant_value(other); + /// __self_discr == __arg1_discr /// && match (self, other) { /// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0, /// _ => true, @@ -1148,7 +1148,7 @@ impl<'a> MethodDef<'a> { /// } /// ``` /// - /// Creates a tag check combined with a match for a tuple of all + /// Creates a discriminant check combined with a match for a tuple of all /// `selflike_args`, with an arm for each variant with fields, possibly an /// arm for each fieldless variant (if `unify_fieldless_variants` is not /// `Unify`), and possibly a default arm. @@ -1169,7 +1169,7 @@ impl<'a> MethodDef<'a> { let span = trait_.span; let variants = &enum_def.variants; - // Traits that unify fieldless variants always use the tag(s). + // Traits that unify fieldless variants always use the discriminant(s). let unify_fieldless_variants = self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify; @@ -1199,25 +1199,25 @@ impl<'a> MethodDef<'a> { // // e.g. for `PartialEq::eq` builds two statements: // ``` - // let __self_tag = ::core::intrinsics::discriminant_value(self); - // let __arg1_tag = ::core::intrinsics::discriminant_value(other); + // let __self_discr = ::core::intrinsics::discriminant_value(self); + // let __arg1_discr = ::core::intrinsics::discriminant_value(other); // ``` - let get_tag_pieces = |cx: &ExtCtxt<'_>| { - let tag_idents: Vec<_> = prefixes + let get_discr_pieces = |cx: &ExtCtxt<'_>| { + let discr_idents: Vec<_> = prefixes .iter() - .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span)) + .map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span)) .collect(); - let mut tag_exprs: Vec<_> = tag_idents + let mut discr_exprs: Vec<_> = discr_idents .iter() .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident))) .collect(); - let self_expr = tag_exprs.remove(0); - let other_selflike_exprs = tag_exprs; - let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; + let self_expr = discr_exprs.remove(0); + let other_selflike_exprs = discr_exprs; + let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; - let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args) + let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { let variant_value = deriving::call_intrinsic( cx, @@ -1229,7 +1229,7 @@ impl<'a> MethodDef<'a> { }) .collect(); - (tag_field, tag_let_stmts) + (discr_field, discr_let_stmts) }; // There are some special cases involving fieldless enums where no @@ -1239,19 +1239,19 @@ impl<'a> MethodDef<'a> { if variants.len() > 1 { match self.fieldless_variants_strategy { FieldlessVariantsStrategy::Unify => { - // If the type is fieldless and the trait uses the tag and + // If the type is fieldless and the trait uses the discriminant and // there are multiple variants, we need just an operation on - // the tag(s). - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - let mut tag_check = self.call_substructure_method( + // the discriminant(s). + let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx); + let mut discr_check = self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumTag(tag_field, None), + &EnumDiscr(discr_field, None), ); - tag_let_stmts.append(&mut tag_check.0); - return BlockOrExpr(tag_let_stmts, tag_check.1); + discr_let_stmts.append(&mut discr_check.0); + return BlockOrExpr(discr_let_stmts, discr_check.1); } FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => { return self.call_substructure_method( @@ -1266,7 +1266,7 @@ impl<'a> MethodDef<'a> { } } else if variants.len() == 1 { // If there is a single variant, we don't need an operation on - // the tag(s). Just use the most degenerate result. + // the discriminant(s). Just use the most degenerate result. return self.call_substructure_method( cx, trait_, @@ -1380,22 +1380,22 @@ impl<'a> MethodDef<'a> { cx.expr_match(span, match_arg, match_arms) }; - // If the trait uses the tag and there are multiple variants, we need - // to add a tag check operation before the match. Otherwise, the match + // If the trait uses the discriminant and there are multiple variants, we need + // to add a discriminant check operation before the match. Otherwise, the match // is enough. if unify_fieldless_variants && variants.len() > 1 { - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); + let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx); - // Combine a tag check with the match. - let mut tag_check_plus_match = self.call_substructure_method( + // Combine a discriminant check with the match. + let mut discr_check_plus_match = self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumTag(tag_field, Some(get_match_expr(selflike_args))), + &EnumDiscr(discr_field, Some(get_match_expr(selflike_args))), ); - tag_let_stmts.append(&mut tag_check_plus_match.0); - BlockOrExpr(tag_let_stmts, tag_check_plus_match.1) + discr_let_stmts.append(&mut discr_check_plus_match.0); + BlockOrExpr(discr_let_stmts, discr_check_plus_match.1) } else { BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args))) } @@ -1701,16 +1701,16 @@ where rest.iter().rfold(base_expr, op) } } - EnumTag(tag_field, match_expr) => { - let tag_check_expr = f(cx, CsFold::Single(tag_field)); + EnumDiscr(discr_field, match_expr) => { + let discr_check_expr = f(cx, CsFold::Single(discr_field)); if let Some(match_expr) = match_expr { if use_foldl { - f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone())) + f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone())) } else { - f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr)) + f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr)) } } else { - tag_check_expr + discr_check_expr } } StaticEnum(..) | StaticStruct(..) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6bb61311bd2..41e27f65586 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -66,9 +66,9 @@ fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<' fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect(); (stmts, None) } - EnumTag(tag_field, match_expr) => { - assert!(tag_field.other_selflike_exprs.is_empty()); - let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; + EnumDiscr(discr_field, match_expr) => { + assert!(discr_field.other_selflike_exprs.is_empty()); + let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())]; (stmts, match_expr.clone()) } _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"), diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 554dac0852f..1b4c6041294 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -46,6 +46,7 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; +mod pattern_type; mod source_util; mod test; mod trace_macros; @@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, option_env: env::expand_option_env, + pattern_type: pattern_type::expand, std_panic: edition_panic::expand_panic, stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs new file mode 100644 index 00000000000..54039c2c538 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -0,0 +1,29 @@ +use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_span::{sym, Span}; + +pub fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let (ty, pat) = match parse_pat_ty(cx, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat)))) +} + +fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> { + let mut parser = cx.new_parser_from_tts(stream); + + let ty = parser.parse_ty()?; + parser.eat_keyword(sym::is); + let pat = parser.parse_pat_no_top_alt(None, None)?; + + Ok((ty, pat)) +} diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 61a6361ae8d..c79ae716806 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -196,10 +196,10 @@ pub fn expand_include_str( Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { - Ok(bytes) => match std::str::from_utf8(&bytes) { + Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); - MacEager::expr(cx.expr_str(sp, interned_src)) + MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } Err(_) => { let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); @@ -225,7 +225,9 @@ pub fn expand_include_bytes( Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { - Ok(bytes) => { + Ok((bytes, _bsp)) => { + // Don't care about getting the span for the raw bytes, + // because the console can't really show them anyway. let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); MacEager::expr(expr) } @@ -238,7 +240,7 @@ fn load_binary_file( original_path: &Path, macro_span: Span, path_span: Span, -) -> Result<Lrc<[u8]>, Box<dyn MacResult>> { +) -> Result<(Lrc<[u8]>, Span), Box<dyn MacResult>> { let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) { Ok(path) => path, Err(err) => { @@ -333,10 +335,8 @@ fn find_path_suggestion( .flatten() .take(4); - for new_path in root_absolute.chain(add).chain(remove) { - if source_map.file_exists(&base_dir.join(&new_path)) { - return Some(new_path); - } - } - None + root_absolute + .chain(add) + .chain(remove) + .find(|new_path| source_map.file_exists(&base_dir.join(&new_path))) } diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml index 97c2f45d31e..5a464bfac36 100644 --- a/compiler/rustc_codegen_cranelift/.cirrus.yml +++ b/compiler/rustc_codegen_cranelift/.cirrus.yml @@ -7,7 +7,7 @@ task: - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh --default-toolchain none -y --profile=minimal target_cache: - folder: target + folder: build/cg_clif prepare_script: - . $HOME/.cargo/env - ./y.sh prepare @@ -16,4 +16,5 @@ task: # Disabling incr comp reduces cache size and incr comp doesn't save as much # on CI anyway. - export CARGO_BUILD_INCREMENTAL=false - - ./y.sh test + # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 + - ./y.sh test --skip-test test.rust-random/rand diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js index 6fcfca34ea7..1eb2b7f23b2 100644 --- a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js +++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js @@ -56,7 +56,7 @@ async function runOnce() { force: true, }); } catch (e) { - console.log("ERROR: ", JSON.stringify(e.data, null, 2)); + console.log("ERROR: ", JSON.stringify(e.response, null, 2)); core.info(`creating dev tag`); try { await octokit.rest.git.createRef({ @@ -68,7 +68,7 @@ async function runOnce() { } catch (e) { // we might race with others, so assume someone else has created the // tag by this point. - console.log("failed to create tag: ", JSON.stringify(e.data, null, 2)); + console.log("failed to create tag: ", JSON.stringify(e.response, null, 2)); } } diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 913a5c5a850..14aa850ff5c 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -268,6 +268,9 @@ jobs: if: ${{ github.ref == 'refs/heads/master' }} needs: [rustfmt, test, bench, dist] + permissions: + contents: write # for creating the dev tag and release + concurrency: group: release-dev cancel-in-progress: true diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index 646928893e9..a3f370af916 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -82,6 +82,19 @@ index d9de37e..8293fce 100644 #[cfg(target_has_atomic_load_store = "ptr")] macro_rules! atomic_int_ptr_sized { ( $($target_pointer_width:literal $align:literal)* ) => { $( +diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs +index 58b9ba4..91bbd0a 100644 +--- a/library/core/src/cell.rs ++++ b/library/core/src/cell.rs +@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! { + u32 "32" + i64 "64" + u64 "64" +- i128 "128" +- u128 "128" + isize "ptr" + usize "ptr" + } -- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 09e436b3eed..3e7da4e161f 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-04-05" +channel = "nightly-2024-04-11" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index f42a008dc0c..8580f4557e8 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -10,14 +10,13 @@ pushd rust command -v rg >/dev/null 2>&1 || cargo install ripgrep -# FIXME remove this workaround once ICE tests no longer emit an outdated nightly message -for test in $(rg -i --files-with-matches "//@(\[.*\])? failure-status: 101" tests/ui); do - echo "rm $test" +rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true +for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do rm $test done -rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true -for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do +# should-fail tests don't work when compiletest is compiled with panic=abort +for test in $(rg --files-with-matches "//@ should-fail" tests/{codegen-units,ui,incremental}); do rm $test done @@ -79,7 +78,6 @@ rm -r tests/run-make/fmt-write-bloat/ # tests an optimization # ====================== rm tests/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM rm -r tests/run-make/cross-lang-lto # same -rm -r tests/run-make/issue-7349 # same rm -r tests/run-make/sepcomp-inlining # same rm -r tests/run-make/sepcomp-separate # same rm -r tests/run-make/sepcomp-cci-copies # same @@ -116,8 +114,6 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain # genuine bugs # ============ -rm tests/incremental/spike-neg1.rs # errors out for some reason -rm tests/incremental/spike-neg2.rs # same rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 0aa2bae8f78..f07421431da 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -267,10 +267,19 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { .generic_activity("codegen prelude") .run(|| crate::abi::codegen_fn_prelude(fx, start_block)); + let reachable_blocks = traversal::mono_reachable_as_bitset(fx.mir, fx.tcx, fx.instance); + for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() { let block = fx.get_block(bb); fx.bcx.switch_to_block(block); + if !reachable_blocks.contains(bb) { + // We want to skip this block, because it's not reachable. But we still create + // the block so terminators in other blocks can reference it. + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + continue; + } + if bb_data.is_cleanup { // Unwinding after panicking is not supported continue; @@ -789,7 +798,7 @@ fn codegen_stmt<'tcx>( layout.offset_of_subfield(fx, fields.iter()).bytes() } NullOp::UbChecks => { - let val = fx.tcx.sess.opts.debug_assertions; + let val = fx.tcx.sess.ub_checks(); let val = CValue::by_val( fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()), fx.layout_of(fx.tcx.types.bool), diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 96ab7a29205..eebd181341d 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -38,6 +38,14 @@ impl UnwindContext { } pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) { + if let target_lexicon::OperatingSystem::MacOSX { .. } = isa.triple().operating_system { + // The object crate doesn't currently support DW_GNU_EH_PE_absptr, which macOS + // requires for unwinding tables. In addition on arm64 it currently doesn't + // support 32bit relocations as we currently use for the unwinding table. + // See gimli-rs/object#415 and rust-lang/rustc_codegen_cranelift#1371 + return; + } + let unwind_info = if let Some(unwind_info) = context.compiled_code().unwrap().create_unwind_info(isa).unwrap() { diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 75268341a4f..e8c96486041 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -341,6 +341,8 @@ fn emit_cgu( object: Some(global_asm_object_file), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }), existing_work_product: None, }) @@ -378,7 +380,15 @@ fn emit_module( prof.artifact_size("object_file", &*name, file.metadata().unwrap().len()); - Ok(CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None }) + Ok(CompiledModule { + name, + kind, + object: Some(tmp_file), + dwarf_object: None, + bytecode: None, + assembly: None, + llvm_ir: None, + }) } fn reuse_workproduct_for_cgu( @@ -426,6 +436,8 @@ fn reuse_workproduct_for_cgu( object: Some(obj_out_regular), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }, module_global_asm: has_global_asm.then(|| CompiledModule { name: cgu.name().to_string(), @@ -433,6 +445,8 @@ fn reuse_workproduct_for_cgu( object: Some(obj_out_global_asm), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }), existing_work_product: Some((cgu.work_product_id(), work_product)), }) @@ -678,6 +692,8 @@ pub(crate) fn run_aot( object: Some(tmp_file), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }) } else { None diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 76a619a1af7..3ea5be1ee56 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -158,6 +158,8 @@ pub(crate) unsafe fn codegen( config.emit_obj != EmitObj::None, cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, config.emit_bc, + config.emit_asm, + config.emit_ir, &cgcx.output_filenames, )) } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 43cc46cfe68..6253816d37d 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -974,7 +974,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { &mut self, place: PlaceRef<'tcx, RValue<'gcc>>, ) -> OperandRef<'tcx, RValue<'gcc>> { - assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); + assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { return OperandRef::zero_sized(place.layout); @@ -999,10 +999,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } } - let val = if let Some(llextra) = place.llextra { - OperandValue::Ref(place.llval, Some(llextra), place.align) + let val = if let Some(_) = place.val.llextra { + // FIXME: Merge with the `else` below? + OperandValue::Ref(place.val) } else if place.layout.is_gcc_immediate() { - let load = self.load(place.layout.gcc_type(self), place.llval, place.align); + let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align); if let abi::Abi::Scalar(ref scalar) = place.layout.abi { scalar_load_metadata(self, load, scalar); } @@ -1012,9 +1013,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let mut load = |i, scalar: &abi::Scalar, align| { let llptr = if i == 0 { - place.llval + place.val.llval } else { - self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes())) + self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes())) }; let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); @@ -1027,11 +1028,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; OperandValue::Pair( - load(0, a, place.align), - load(1, b, place.align.restrict_for_offset(b_offset)), + load(0, a, place.val.align), + load(1, b, place.val.align.restrict_for_offset(b_offset)), ) } else { - OperandValue::Ref(place.llval, None, place.align) + OperandValue::Ref(place.val) }; OperandRef { val, layout: place.layout } @@ -1045,8 +1046,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) { let zero = self.const_usize(0); let count = self.const_usize(count); - let start = dest.project_index(self, zero).llval; - let end = dest.project_index(self, count).llval; + let start = dest.project_index(self, zero).val.llval; + let end = dest.project_index(self, count).val.llval; let header_bb = self.append_sibling_block("repeat_loop_header"); let body_bb = self.append_sibling_block("repeat_loop_body"); @@ -1064,7 +1065,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.cond_br(keep_going, body_bb, next_bb); self.switch_to_block(body_bb); - let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); + let align = dest.val.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); let next = self.inbounds_gep( diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index cebd45c09aa..bee6bda007c 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -11,7 +11,7 @@ use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; -use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::{ ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods, }; @@ -354,7 +354,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let block = self.llbb(); let extended_asm = block.add_extended_asm(None, ""); - extended_asm.add_input_operand(None, "r", result.llval); + extended_asm.add_input_operand(None, "r", result.val.llval); extended_asm.add_clobber("memory"); extended_asm.set_volatile_flag(true); @@ -388,8 +388,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if !fn_abi.ret.is_ignore() { if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); - let ptr = self.pointercast(result.llval, ptr_llty); - self.store(llval, ptr, result.align); + let ptr = self.pointercast(result.val.llval, ptr_llty); + self.store(llval, ptr, result.val.align); } else { OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) .val @@ -502,7 +502,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { return; } if self.is_sized_indirect() { - OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) + OperandValue::Ref(PlaceValue::new_sized(val, self.layout.align.abi)).store(bx, dst) } else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } else if let PassMode::Cast { ref cast, .. } = self.mode { @@ -511,7 +511,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { let can_store_through_cast_ptr = false; if can_store_through_cast_ptr { let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx)); - let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty); + let cast_dst = bx.pointercast(dst.val.llval, cast_ptr_llty); bx.store(val, cast_dst, self.layout.align.abi); } else { // The actual return type is a struct, but the ABI @@ -539,7 +539,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // ... and then memcpy it to the intended destination. bx.memcpy( - dst.llval, + dst.val.llval, self.layout.align.abi, llscratch, scratch_align, @@ -571,7 +571,12 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { OperandValue::Pair(next(), next()).store(bx, dst); } PassMode::Indirect { meta_attrs: Some(_), .. } => { - OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); + let place_val = PlaceValue { + llval: next(), + llextra: Some(next()), + align: self.layout.align.abi, + }; + OperandValue::Ref(place_val).store(bx, dst); } PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 60361a44c2d..6039a4aaf01 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -82,7 +82,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let place = PlaceRef::alloca(bx, args[0].layout); args[0].val.store(bx, place); let int_ty = bx.type_ix(expected_bytes * 8); - let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty)); + let ptr = bx.pointercast(place.val.llval, bx.cx.type_ptr_to(int_ty)); bx.load(int_ty, ptr, Align::ONE) } _ => return_error!(InvalidMonomorphization::InvalidBitmask { diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 3fda59e8b52..bb5045ec872 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -28,6 +28,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } +rustc_sanitizers = { path = "../rustc_sanitizers" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index d2828669d43..c0b43b77897 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; -use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::MemFlags; use rustc_middle::bug; @@ -150,7 +150,10 @@ impl LlvmType for CastTarget { // Simplify to a single unit or an array if there's no prefix. // This produces the same layout, but using a simpler type. if self.prefix.iter().all(|x| x.is_none()) { - if rest_count == 1 { + // We can't do this if is_consecutive is set and the unit would get + // split on the target. Currently, this is only relevant for i128 + // registers. + if rest_count == 1 && (!self.rest.is_consecutive || self.rest.unit != Reg::i128()) { return rest_ll_unit; } @@ -204,7 +207,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // Sized indirect arguments PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => { let align = attrs.pointee_align.unwrap_or(self.layout.align.abi); - OperandValue::Ref(val, None, align).store(bx, dst); + OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst); } // Unsized indirect qrguments PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { @@ -230,7 +233,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { bx.store(val, llscratch, scratch_align); // ... and then memcpy it to the intended destination. bx.memcpy( - dst.llval, + dst.val.llval, self.layout.align.abi, llscratch, scratch_align, @@ -262,7 +265,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { OperandValue::Pair(next(), next()).store(bx, dst); } PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); + let place_val = PlaceValue { + llval: next(), + llextra: Some(next()), + align: self.layout.align.abi, + }; + OperandValue::Ref(place_val).store(bx, dst); } PassMode::Direct(_) | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 500904ce188..e09869cf425 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -220,7 +220,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { constraints.append(&mut clobbers); if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) { match asm_arch { - InlineAsmArch::AArch64 | InlineAsmArch::Arm => { + InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC | InlineAsmArch::Arm => { constraints.push("~{cc}".to_string()); } InlineAsmArch::X86 | InlineAsmArch::X86_64 => { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 06a681c24e6..e61af863dc0 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -608,7 +608,7 @@ pub(crate) fn run_pass_manager( "LTOPostLink".as_ptr().cast(), 11, ) { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( module.module_llvm.llmod(), llvm::LLVMModFlagBehavior::Error, c"LTOPostLink".as_ptr().cast(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 68ba8cbf7b7..49f9d7ddab6 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -880,6 +880,8 @@ pub(crate) unsafe fn codegen( config.emit_obj != EmitObj::None, dwarf_object_emitted, config.emit_bc, + config.emit_asm, + config.emit_ir, &cgcx.output_filenames, )) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 1a32958d362..160f361b9b5 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -20,12 +20,9 @@ use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; use rustc_span::Span; -use rustc_symbol_mangling::typeid::{ - kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, - TypeIdOptions, -}; use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; @@ -538,7 +535,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { panic!("unsized locals must not be `extern` types"); } } - assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); + assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { return OperandRef::zero_sized(place.layout); @@ -582,13 +579,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - let val = if let Some(llextra) = place.llextra { - OperandValue::Ref(place.llval, Some(llextra), place.align) + let val = if let Some(_) = place.val.llextra { + // FIXME: Merge with the `else` below? + OperandValue::Ref(place.val) } else if place.layout.is_llvm_immediate() { let mut const_llval = None; let llty = place.layout.llvm_type(self); unsafe { - if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) { + if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { if llvm::LLVMIsGlobalConstant(global) == llvm::True { if let Some(init) = llvm::LLVMGetInitializer(global) { if self.val_ty(init) == llty { @@ -599,7 +597,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } let llval = const_llval.unwrap_or_else(|| { - let load = self.load(llty, place.llval, place.align); + let load = self.load(llty, place.val.llval, place.val.align); if let abi::Abi::Scalar(scalar) = place.layout.abi { scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO); } @@ -611,9 +609,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let mut load = |i, scalar: abi::Scalar, layout, align, offset| { let llptr = if i == 0 { - place.llval + place.val.llval } else { - self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes())) + self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes())) }; let llty = place.layout.scalar_pair_element_llvm_type(self, i, false); let load = self.load(llty, llptr, align); @@ -622,11 +620,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { }; OperandValue::Pair( - load(0, a, place.layout, place.align, Size::ZERO), - load(1, b, place.layout, place.align.restrict_for_offset(b_offset), b_offset), + load(0, a, place.layout, place.val.align, Size::ZERO), + load(1, b, place.layout, place.val.align.restrict_for_offset(b_offset), b_offset), ) } else { - OperandValue::Ref(place.llval, None, place.align) + OperandValue::Ref(place.val) }; OperandRef { val, layout: place.layout } @@ -1151,12 +1149,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { order: rustc_codegen_ssa::common::AtomicOrdering, ) -> &'ll Value { // The only RMW operation that LLVM supports on pointers is compare-exchange. - if self.val_ty(src) == self.type_ptr() - && op != rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg - { + let requires_cast_to_int = self.val_ty(src) == self.type_ptr() + && op != rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg; + if requires_cast_to_int { src = self.ptrtoint(src, self.type_isize()); } - unsafe { + let mut res = unsafe { llvm::LLVMBuildAtomicRMW( self.llbuilder, AtomicRmwBinOp::from_generic(op), @@ -1165,7 +1163,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { AtomicOrdering::from_generic(order), llvm::False, // SingleThreaded ) + }; + if requires_cast_to_int { + res = self.inttoptr(res, self.type_ptr()); } + res } fn atomic_fence( @@ -1632,18 +1634,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { return; } - let mut options = TypeIdOptions::empty(); + let mut options = cfi::TypeIdOptions::empty(); if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); + options.insert(cfi::TypeIdOptions::GENERALIZE_POINTERS); } if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + options.insert(cfi::TypeIdOptions::NORMALIZE_INTEGERS); } let typeid = if let Some(instance) = instance { - typeid_for_instance(self.tcx, instance, options) + cfi::typeid_for_instance(self.tcx, instance, options) } else { - typeid_for_fnabi(self.tcx, fn_abi, options) + cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); @@ -1680,18 +1682,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { return None; } - let mut options = TypeIdOptions::empty(); + let mut options = kcfi::TypeIdOptions::empty(); if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); + options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS); } if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS); } let kcfi_typeid = if let Some(instance) = instance { - kcfi_typeid_for_instance(self.tcx, instance, options) + kcfi::typeid_for_instance(self.tcx, instance, options) } else { - kcfi_typeid_for_fnabi(self.tcx, fn_abi, options) + kcfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index df9f066e58a..d32baa6dc02 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -180,13 +180,13 @@ pub unsafe fn create_module<'ll>( // to ensure intrinsic calls don't use it. if !sess.needs_plt() { let avoid_plt = c"RtLibUseGOT".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, canonical_jump_tables, @@ -197,7 +197,7 @@ pub unsafe fn create_module<'ll>( // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, enable_split_lto_unit, @@ -208,7 +208,7 @@ pub unsafe fn create_module<'ll>( // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { let kcfi = c"kcfi".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); } // Control Flow Guard is currently only supported by the MSVC linker on Windows. @@ -217,7 +217,7 @@ pub unsafe fn create_module<'ll>( CFGuard::Disabled => {} CFGuard::NoChecks => { // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Warning, c"cfguard".as_ptr() as *const _, @@ -226,7 +226,7 @@ pub unsafe fn create_module<'ll>( } CFGuard::Checks => { // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Warning, c"cfguard".as_ptr() as *const _, @@ -238,26 +238,26 @@ pub unsafe fn create_module<'ll>( if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch == "aarch64" { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"branch-target-enforcement".as_ptr().cast(), bti.into(), ); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"sign-return-address".as_ptr().cast(), pac_ret.is_some().into(), ); let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"sign-return-address-all".as_ptr().cast(), pac_opts.leaf.into(), ); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"sign-return-address-with-bkey".as_ptr().cast(), @@ -273,7 +273,7 @@ pub unsafe fn create_module<'ll>( // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, c"cf-protection-branch".as_ptr().cast(), @@ -281,7 +281,7 @@ pub unsafe fn create_module<'ll>( ) } if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, c"cf-protection-return".as_ptr().cast(), @@ -290,7 +290,7 @@ pub unsafe fn create_module<'ll>( } if sess.opts.unstable_opts.virtual_function_elimination { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Error, c"Virtual Function Elim".as_ptr().cast(), @@ -300,7 +300,7 @@ pub unsafe fn create_module<'ll>( // Set module flag to enable Windows EHCont Guard (/guard:ehcont). if sess.opts.unstable_opts.ehcont_guard { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Warning, c"ehcontguard".as_ptr() as *const _, @@ -326,6 +326,22 @@ pub unsafe fn create_module<'ll>( llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), ); + // Emit RISC-V specific target-abi metadata + // to workaround lld as the LTO plugin not + // correctly setting target-abi for the LTO object + // FIXME: https://github.com/llvm/llvm-project/issues/50591 + // If llvm_abiname is empty, emit nothing. + let llvm_abiname = &sess.target.options.llvm_abiname; + if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { + llvm::LLVMRustAddModuleFlagString( + llmod, + llvm::LLVMModFlagBehavior::Error, + c"target-abi".as_ptr(), + llvm_abiname.as_ptr().cast(), + llvm_abiname.len(), + ); + } + // Add module flags specified via -Z llvm_module_flag for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { let key = format!("{key}\0"); @@ -341,7 +357,7 @@ pub unsafe fn create_module<'ll>( // We already checked this during option parsing _ => unreachable!(), }; - llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value) + llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) } llmod diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index d3a851b40c0..4fdaa59e0e5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -110,7 +110,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { .unstable_opts .dwarf_version .unwrap_or(sess.target.default_dwarf_version); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, c"Dwarf Version".as_ptr().cast(), @@ -118,7 +118,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { ); } else { // Indicate that we want CodeView debug information on MSVC - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, c"CodeView".as_ptr().cast(), @@ -127,7 +127,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { } // Prevent bitcode readers from deleting the debug info. - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, c"Debug Info Version".as_ptr().cast(), diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index f86cdcaa6f7..7117c4a0ed9 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -22,10 +22,7 @@ use itertools::Itertools; use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{Instance, Ty}; -use rustc_symbol_mangling::typeid::{ - kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, - TypeIdOptions, -}; +use rustc_sanitizers::{cfi, kcfi}; use smallvec::SmallVec; /// Declare a function. @@ -145,27 +142,29 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { if let Some(instance) = instance { let mut typeids = FxIndexSet::default(); for options in [ - TypeIdOptions::GENERALIZE_POINTERS, - TypeIdOptions::NORMALIZE_INTEGERS, - TypeIdOptions::USE_CONCRETE_SELF, + cfi::TypeIdOptions::GENERALIZE_POINTERS, + cfi::TypeIdOptions::NORMALIZE_INTEGERS, + cfi::TypeIdOptions::USE_CONCRETE_SELF, ] .into_iter() .powerset() - .map(TypeIdOptions::from_iter) + .map(cfi::TypeIdOptions::from_iter) { - let typeid = typeid_for_instance(self.tcx, instance, options); + let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { self.add_type_metadata(llfn, typeid); } } } else { - for options in - [TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS] - .into_iter() - .powerset() - .map(TypeIdOptions::from_iter) + for options in [ + cfi::TypeIdOptions::GENERALIZE_POINTERS, + cfi::TypeIdOptions::NORMALIZE_INTEGERS, + ] + .into_iter() + .powerset() + .map(cfi::TypeIdOptions::from_iter) { - let typeid = typeid_for_fnabi(self.tcx, fn_abi, options); + let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); self.add_type_metadata(llfn, typeid); } } @@ -173,19 +172,19 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { if self.tcx.sess.is_sanitizer_kcfi_enabled() { // LLVM KCFI does not support multiple !kcfi_type attachments - let mut options = TypeIdOptions::empty(); + let mut options = kcfi::TypeIdOptions::empty(); if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); + options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS); } if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS); } if let Some(instance) = instance { - let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, instance, options); + let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options); self.set_kcfi_type_metadata(llfn, kcfi_typeid); } else { - let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); + let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options); self.set_kcfi_type_metadata(llfn, kcfi_typeid); } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index dc52dd156b7..2bed7c1bd1c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -264,7 +264,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { llvm::LLVMSetAlignment(load, align); } if !result.layout.is_zst() { - self.store(load, result.llval, result.align); + self.store_to_place(load, result.val); } return Ok(()); } @@ -428,7 +428,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::black_box => { args[0].val.store(self, result); - let result_val_span = [result.llval]; + let result_val_span = [result.val.llval]; // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black @@ -482,7 +482,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { if !fn_abi.ret.is_ignore() { if let PassMode::Cast { .. } = &fn_abi.ret.mode { - self.store(llval, result.llval, result.align); + self.store(llval, result.val.llval, result.val.align); } else { OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) .val @@ -1065,7 +1065,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let place = PlaceRef::alloca(bx, args[0].layout); args[0].val.store(bx, place); let int_ty = bx.type_ix(expected_bytes * 8); - bx.load(int_ty, place.llval, Align::ONE) + bx.load(int_ty, place.val.llval, Align::ONE) } _ => return_error!(InvalidMonomorphization::InvalidBitmask { span, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 284bc74d5c4..5509baaa3e9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1801,12 +1801,21 @@ extern "C" { /// /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What /// "compatible" means depends on the merge behaviors involved. - pub fn LLVMRustAddModuleFlag( + pub fn LLVMRustAddModuleFlagU32( M: &Module, merge_behavior: LLVMModFlagBehavior, name: *const c_char, value: u32, ); + + pub fn LLVMRustAddModuleFlagString( + M: &Module, + merge_behavior: LLVMModFlagBehavior, + name: *const c_char, + value: *const c_char, + value_len: size_t, + ); + pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool; pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index af1bbda4d08..a00f09dc40d 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -281,9 +281,6 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn reg_backend_type(&self, ty: &Reg) -> &'ll Type { ty.llvm_type(self) } - fn scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option<Self::Type> { - layout.scalar_copy_llvm_type(self) - } } impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index d10a083765b..40ed6baa610 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -5,7 +5,6 @@ use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_target::abi::HasDataLayout; use rustc_target::abi::{Abi, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F128, F16, F32, F64}; use rustc_target::abi::{Scalar, Size, Variants}; @@ -166,7 +165,6 @@ pub trait LayoutLlvmExt<'tcx> { index: usize, immediate: bool, ) -> &'a Type; - fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type>; } impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { @@ -308,44 +306,4 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { self.scalar_llvm_type_at(cx, scalar) } - - fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type> { - debug_assert!(self.is_sized()); - - // FIXME: this is a fairly arbitrary choice, but 128 bits on WASM - // (matching the 128-bit SIMD types proposal) and 256 bits on x64 - // (like AVX2 registers) seems at least like a tolerable starting point. - let threshold = cx.data_layout().pointer_size * 4; - if self.layout.size() > threshold { - return None; - } - - // Vectors, even for non-power-of-two sizes, have the same layout as - // arrays but don't count as aggregate types - // While LLVM theoretically supports non-power-of-two sizes, and they - // often work fine, sometimes x86-isel deals with them horribly - // (see #115212) so for now only use power-of-two ones. - if let FieldsShape::Array { count, .. } = self.layout.fields() - && count.is_power_of_two() - && let element = self.field(cx, 0) - && element.ty.is_integral() - { - // `cx.type_ix(bits)` is tempting here, but while that works great - // for things that *stay* as memory-to-memory copies, it also ends - // up suppressing vectorization as it introduces shifts when it - // extracts all the individual values. - - let ety = element.llvm_type(cx); - if *count == 1 { - // Emitting `<1 x T>` would be silly; just use the scalar. - return Some(ety); - } else { - return Some(cx.type_vector(ety, *count)); - } - } - - // FIXME: The above only handled integer arrays; surely more things - // would also be possible. Be careful about provenance, though! - None - } } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 22b58c13949..ef55682d541 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -231,7 +231,11 @@ impl<'a> ArArchiveBuilder<'a> { "gnu" => ArchiveKind::Gnu, "bsd" => ArchiveKind::Bsd, "darwin" => ArchiveKind::Darwin, - "coff" => ArchiveKind::Coff, + "coff" => { + // FIXME: ar_archive_writer doesn't support COFF archives yet. + // https://github.com/rust-lang/ar_archive_writer/issues/9 + ArchiveKind::Gnu + } "aix_big" => ArchiveKind::AixBig, kind => { self.sess.dcx().emit_fatal(UnknownArchiveKind { kind }); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ac278de02af..e7d6a671e12 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -11,6 +11,7 @@ use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME}; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; +use rustc_session::config::LinkerFeaturesCli; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, OutFileName, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintKind, SplitDwarfKind}; use rustc_session::cstore::DllImport; @@ -22,10 +23,10 @@ use rustc_session::utils::NativeLibKind; use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; use rustc_target::spec::crt_objects::CrtObjects; -use rustc_target::spec::LinkSelfContainedComponents; use rustc_target::spec::LinkSelfContainedDefault; use rustc_target::spec::LinkerFlavorCli; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy}; +use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures}; use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo}; use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; @@ -42,7 +43,6 @@ use regex::Regex; use tempfile::Builder as TempFileBuilder; use itertools::Itertools; -use std::cell::OnceCell; use std::collections::BTreeSet; use std::ffi::{OsStr, OsString}; use std::fs::{read, File, OpenOptions}; @@ -52,15 +52,6 @@ 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<Vec<PathBuf>>); - -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 { @@ -71,8 +62,8 @@ pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) { /// Performs the linkage portion of the compilation phase. This will generate all /// of the requested outputs for this compilation session. -pub fn link_binary<'a>( - sess: &'a Session, +pub fn link_binary( + sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, outputs: &OutputFilenames, @@ -310,8 +301,6 @@ fn link_rlib<'a>( flavor: RlibFlavor, tmpdir: &MaybeTempDir, ) -> Result<Box<dyn ArchiveBuilder + 'a>, ErrorGuaranteed> { - let lib_search_paths = archive_search_paths(sess); - let mut ab = archive_builder_builder.new_archive_builder(sess); let trailing_metadata = match flavor { @@ -385,19 +374,14 @@ fn link_rlib<'a>( if flavor == RlibFlavor::Normal && let Some(filename) = lib.filename { - let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess); + let path = find_native_static_library(filename.as_str(), true, sess); let src = read(path) .map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?; let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src); let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); packed_bundled_libs.push(wrapper_file); } else { - let path = find_native_static_library( - lib.name.as_str(), - lib.verbatim, - &lib_search_paths, - sess, - ); + let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess); ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| { sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: path, error }) }); @@ -464,9 +448,9 @@ fn link_rlib<'a>( /// then the CodegenResults value contains one NativeLib instance for each block. However, the /// linker appears to expect only a single import library for each library used, so we need to /// collate the symbols together by library name before generating the import libraries. -fn collate_raw_dylibs<'a, 'b>( - sess: &'a Session, - used_libraries: impl IntoIterator<Item = &'b NativeLib>, +fn collate_raw_dylibs<'a>( + sess: &Session, + used_libraries: impl IntoIterator<Item = &'a NativeLib>, ) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> { // Use index maps to preserve original order of imports and libraries. let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default(); @@ -513,8 +497,8 @@ fn collate_raw_dylibs<'a, 'b>( /// /// There's no need to include metadata in a static archive, so ensure to not link in the metadata /// object file (and also don't prepare the archive with a metadata file). -fn link_staticlib<'a>( - sess: &'a Session, +fn link_staticlib( + sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, out_filename: &Path, @@ -626,11 +610,7 @@ fn link_staticlib<'a>( /// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a /// DWARF package. -fn link_dwarf_object<'a>( - sess: &'a Session, - cg_results: &CodegenResults, - executable_out_filename: &Path, -) { +fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out_filename: &Path) { let mut dwp_out_filename = executable_out_filename.to_path_buf().into_os_string(); dwp_out_filename.push(".dwp"); debug!(?dwp_out_filename, ?executable_out_filename); @@ -734,8 +714,8 @@ fn link_dwarf_object<'a>( /// /// This will invoke the system linker/cc to create the resulting file. This links to all upstream /// files as well. -fn link_natively<'a>( - sess: &'a Session, +fn link_natively( + sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, crate_type: CrateType, out_filename: &Path, @@ -1099,8 +1079,8 @@ fn link_natively<'a>( Ok(()) } -fn strip_symbols_with_external_utility<'a>( - sess: &'a Session, +fn strip_symbols_with_external_utility( + sess: &Session, util: &str, out_filename: &Path, option: Option<&str>, @@ -1337,7 +1317,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { sess: &Session, linker: Option<PathBuf>, flavor: Option<LinkerFlavor>, + features: LinkerFeaturesCli, ) -> Option<(PathBuf, LinkerFlavor)> { + let flavor = flavor.map(|flavor| adjust_flavor_to_features(flavor, features)); match (linker, flavor) { (Some(linker), Some(flavor)) => Some((linker, flavor)), // only the linker flavor is known; use the default linker for the selected flavor @@ -1385,12 +1367,33 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { sess.dcx().emit_fatal(errors::LinkerFileStem); }); let flavor = sess.target.linker_flavor.with_linker_hints(stem); + let flavor = adjust_flavor_to_features(flavor, features); Some((linker, flavor)) } (None, None) => None, } } + // While linker flavors and linker features are isomorphic (and thus targets don't need to + // define features separately), we use the flavor as the root piece of data and have the + // linker-features CLI flag influence *that*, so that downstream code does not have to check for + // both yet. + fn adjust_flavor_to_features( + flavor: LinkerFlavor, + features: LinkerFeaturesCli, + ) -> LinkerFlavor { + // Note: a linker feature cannot be both enabled and disabled on the CLI. + if features.enabled.contains(LinkerFeatures::LLD) { + flavor.with_lld_enabled() + } else if features.disabled.contains(LinkerFeatures::LLD) { + flavor.with_lld_disabled() + } else { + flavor + } + } + + let features = sess.opts.unstable_opts.linker_features; + // linker and linker flavor specified via command line have precedence over what the target // specification specifies let linker_flavor = match sess.opts.cg.linker_flavor { @@ -1404,7 +1407,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { .linker_flavor .map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor)), }; - if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) { + if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor, features) { return ret; } @@ -1412,6 +1415,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { sess, sess.target.linker.as_deref().map(PathBuf::from), Some(sess.target.linker_flavor), + features, ) { return ret; } @@ -1445,10 +1449,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) { } } -fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { - sess.target_filesearch(PathKind::Native).search_path_dirs() -} - #[derive(PartialEq)] enum RlibFlavor { Normal, @@ -2108,10 +2108,10 @@ fn add_rpath_args( /// to the linking process as a whole. /// Order-independent options may still override each other in order-dependent fashion, /// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`. -fn linker_with_args<'a>( +fn linker_with_args( path: &Path, flavor: LinkerFlavor, - sess: &'a Session, + sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, crate_type: CrateType, tmpdir: &Path, @@ -2500,7 +2500,6 @@ fn add_native_libs_from_crate( archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, tmpdir: &Path, - search_paths: &SearchPaths, bundled_libs: &FxIndexSet<Symbol>, cnum: CrateNum, link_static: bool, @@ -2563,7 +2562,7 @@ fn add_native_libs_from_crate( cmd.link_staticlib_by_path(&path, whole_archive); } } else { - cmd.link_staticlib_by_name(name, verbatim, whole_archive, search_paths); + cmd.link_staticlib_by_name(name, verbatim, whole_archive); } } } @@ -2577,7 +2576,7 @@ 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_by_name(name, verbatim, false, search_paths); + cmd.link_staticlib_by_name(name, verbatim, false); } } else { if link_dynamic { @@ -2624,7 +2623,6 @@ fn add_local_native_libraries( } } - 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; @@ -2634,7 +2632,6 @@ fn add_local_native_libraries( archive_builder_builder, codegen_results, tmpdir, - &search_paths, &Default::default(), LOCAL_CRATE, link_static, @@ -2643,9 +2640,9 @@ fn add_local_native_libraries( ); } -fn add_upstream_rust_crates<'a>( +fn add_upstream_rust_crates( cmd: &mut dyn Linker, - sess: &'a Session, + sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, crate_type: CrateType, @@ -2666,7 +2663,6 @@ fn add_upstream_rust_crates<'a>( .find(|(ty, _)| *ty == crate_type) .expect("failed to find crate type in dependency format list"); - 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. @@ -2723,7 +2719,6 @@ fn add_upstream_rust_crates<'a>( archive_builder_builder, codegen_results, tmpdir, - &search_paths, &bundled_libs, cnum, link_static, @@ -2741,7 +2736,6 @@ fn add_upstream_native_libraries( tmpdir: &Path, link_output_kind: LinkOutputKind, ) { - 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 @@ -2763,7 +2757,6 @@ fn add_upstream_native_libraries( archive_builder_builder, codegen_results, tmpdir, - &search_paths, &Default::default(), cnum, link_static, @@ -2782,7 +2775,7 @@ fn add_upstream_native_libraries( // file generated by the MSVC linker. See https://github.com/rust-lang/rust/issues/112586. // // The returned path will always have `fix_windows_verbatim_for_gcc()` applied to it. -fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf { +fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf { let sysroot_lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); let canonical_sysroot_lib_path = { try_canonicalize(&sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) }; @@ -2815,9 +2808,9 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf { // Note, however, that if we're not doing LTO we can just pass the rlib // blindly to the linker (fast) because it's fine if it's not actually // included as we're at the end of the dependency chain. -fn add_static_crate<'a>( +fn add_static_crate( cmd: &mut dyn Linker, - sess: &'a Session, + sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, tmpdir: &Path, @@ -2990,13 +2983,29 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { match flavor { LinkerFlavor::Darwin(Cc::Yes, _) => { - cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]); + // Use `-isysroot` instead of `--sysroot`, as only the former + // makes Clang treat it as a platform SDK. + // + // This is admittedly a bit strange, as on most targets + // `-isysroot` only applies to include header files, but on Apple + // targets this also applies to libraries and frameworks. + cmd.args(&["-isysroot", &sdk_root]); } LinkerFlavor::Darwin(Cc::No, _) => { cmd.args(&["-syslibroot", &sdk_root]); } _ => unreachable!(), } + + if llvm_target.contains("macabi") { + // Mac Catalyst uses the macOS SDK, but to link to iOS-specific + // frameworks, we must have the support library stubs in the library + // search path. + + // The flags are called `-L` and `-F` both in Clang, ld64 and ldd. + cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib")); + cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks")); + } } fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootError<'_>> { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index f5640ea26bc..fad6f439441 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,6 +1,5 @@ use super::command::Command; use super::symbol_export; -use crate::back::link::SearchPaths; use crate::errors; use rustc_span::symbol::sym; @@ -172,13 +171,7 @@ pub trait Linker { 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_name(&mut self, name: &str, verbatim: bool, whole_archive: bool); 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); @@ -482,13 +475,7 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg("-framework").arg(name); } - fn link_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - whole_archive: bool, - search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); let colon = if verbatim && self.is_gnu { ":" } else { "" }; if !whole_archive { @@ -497,8 +484,7 @@ impl<'a> Linker for GccLinker<'a> { // -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)); + self.linker_arg(find_native_static_library(name, verbatim, self.sess)); } else { self.linker_arg("--whole-archive"); self.cmd.arg(format!("-l{colon}{name}")); @@ -825,13 +811,7 @@ impl<'a> Linker for MsvcLinker<'a> { 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, - ) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; let suffix = if verbatim { "" } else { ".lib" }; self.cmd.arg(format!("{prefix}{name}{suffix}")); @@ -1064,13 +1044,7 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg("-l").arg(name); } - fn link_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { self.cmd.arg("-l").arg(name); } @@ -1243,13 +1217,7 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("-l").arg(name); } - fn link_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - whole_archive: bool, - _search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { if !whole_archive { self.cmd.arg("-l").arg(name); } else { @@ -1396,13 +1364,7 @@ impl<'a> Linker for L4Bender<'a> { bug!("dylibs are not supported on L4Re"); } - fn link_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - whole_archive: bool, - _search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { self.cmd.arg(format!("-PC{name}")); @@ -1580,20 +1542,13 @@ impl<'a> Linker for AixLinker<'a> { self.cmd.arg(format!("-l{name}")); } - fn link_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - whole_archive: bool, - search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); 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)); + arg.push(find_native_static_library(name, verbatim, self.sess)); self.cmd.arg(arg); } } @@ -1792,13 +1747,7 @@ impl<'a> Linker for PtxLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } @@ -1880,13 +1829,7 @@ impl<'a> Linker for LlbcLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } @@ -1977,13 +1920,7 @@ impl<'a> Linker for BpfLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b7bcaac3b18..e7f692144ff 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -528,12 +528,20 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) { let mut files = Vec::new(); if let Some(object_file_path) = &module.object { - files.push(("o", object_file_path.as_path())); + files.push((OutputType::Object.extension(), object_file_path.as_path())); } if let Some(dwarf_object_file_path) = &module.dwarf_object { files.push(("dwo", dwarf_object_file_path.as_path())); } - + if let Some(path) = &module.assembly { + files.push((OutputType::Assembly.extension(), path.as_path())); + } + if let Some(path) = &module.llvm_ir { + files.push((OutputType::LlvmAssembly.extension(), path.as_path())); + } + if let Some(path) = &module.bytecode { + files.push((OutputType::Bitcode.extension(), path.as_path())); + } if let Some((id, product)) = copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice()) { @@ -937,12 +945,28 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( load_from_incr_comp_dir(dwarf_obj_out, saved_dwarf_object_file) }); + let load_from_incr_cache = |perform, output_type: OutputType| { + if perform { + let saved_file = module.source.saved_files.get(output_type.extension())?; + let output_path = cgcx.output_filenames.temp_path(output_type, Some(&module.name)); + load_from_incr_comp_dir(output_path, &saved_file) + } else { + None + } + }; + + let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly); + let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly); + let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode); + WorkItemResult::Finished(CompiledModule { name: module.name, kind: ModuleKind::Regular, object, dwarf_object, - bytecode: None, + bytecode, + assembly, + llvm_ir, }) } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 410b5d27c57..930b9b8c0db 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -12,7 +12,7 @@ use crate::mir; use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; -use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; +use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind}; use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; use rustc_attr as attr; @@ -37,7 +37,7 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Symbol; -use rustc_target::abi::{Align, FIRST_VARIANT}; +use rustc_target::abi::FIRST_VARIANT; use std::cmp; use std::collections::BTreeSet; @@ -282,15 +282,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } if src_f.layout.ty == dst_f.layout.ty { - memcpy_ty( - bx, - dst_f.llval, - dst_f.align, - src_f.llval, - src_f.align, - src_f.layout, - MemFlags::empty(), - ); + bx.typed_place_copy(dst_f, src_f); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -382,30 +374,6 @@ pub fn wants_new_eh_instructions(sess: &Session) -> bool { wants_wasm_eh(sess) || wants_msvc_seh(sess) } -pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - dst: Bx::Value, - dst_align: Align, - src: Bx::Value, - src_align: Align, - layout: TyAndLayout<'tcx>, - flags: MemFlags, -) { - let size = layout.size.bytes(); - if size == 0 { - return; - } - - if flags == MemFlags::empty() - && let Some(bty) = bx.cx().scalar_copy_backend_type(layout) - { - let temp = bx.load(bty, src, src_align); - bx.store(temp, dst, dst_align); - } else { - bx.memcpy(dst, dst_align, src, src_align, bx.cx().const_usize(size), flags); - } -} - pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx>, @@ -656,6 +624,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>( object: Some(file_name), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, } }) }); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 64448441acb..5f0dcf9510f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -202,6 +202,16 @@ fn push_debuginfo_type_name<'tcx>( } } } + ty::Pat(inner_type, pat) => { + if cpp_like_debuginfo { + output.push_str("pat$<"); + push_debuginfo_type_name(tcx, inner_type, true, output, visited); + // FIXME(wg-debugging): implement CPP like printing for patterns. + write!(output, ",{:?}>", pat).unwrap(); + } else { + write!(output, "{:?}", t).unwrap(); + } + } ty::Slice(inner_type) => { if cpp_like_debuginfo { output.push_str("slice2$<"); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9be8dcf166d..80fe7e0bb78 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -79,13 +79,26 @@ impl<M> ModuleCodegen<M> { emit_obj: bool, emit_dwarf_obj: bool, emit_bc: bool, + emit_asm: bool, + emit_ir: bool, outputs: &OutputFilenames, ) -> CompiledModule { let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); + let assembly = emit_asm.then(|| outputs.temp_path(OutputType::Assembly, Some(&self.name))); + let llvm_ir = + emit_ir.then(|| outputs.temp_path(OutputType::LlvmAssembly, Some(&self.name))); - CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode } + CompiledModule { + name: self.name.clone(), + kind: self.kind, + object, + dwarf_object, + bytecode, + assembly, + llvm_ir, + } } } @@ -96,6 +109,8 @@ pub struct CompiledModule { pub object: Option<PathBuf>, pub dwarf_object: Option<PathBuf>, pub bytecode: Option<PathBuf>, + pub assembly: Option<PathBuf>, // --emit=asm + pub llvm_ir: Option<PathBuf>, // --emit=llvm-ir, llvm-bc is in bytecode } pub struct CachedModuleCodegen { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1aa52a985ef..24f2c50e882 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1,6 +1,6 @@ use super::operand::OperandRef; use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized}; -use super::place::PlaceRef; +use super::place::{PlaceRef, PlaceValue}; use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base; @@ -242,7 +242,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { bx.switch_to_block(fx.llbb(target)); fx.set_debug_loc(bx, self.terminator.source_info); for tmp in copied_constant_arguments { - bx.lifetime_end(tmp.llval, tmp.layout.size); + bx.lifetime_end(tmp.val.llval, tmp.layout.size); } fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret); } @@ -256,7 +256,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some((ret_dest, target)) = destination { for tmp in copied_constant_arguments { - bx.lifetime_end(tmp.llval, tmp.layout.size); + bx.lifetime_end(tmp.val.llval, tmp.layout.size); } fx.store_return(bx, ret_dest, &fn_abi.ret, llret); self.funclet_br(fx, bx, target, mergeable_succ) @@ -431,7 +431,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let va_list_arg_idx = self.fn_abi.args.len(); match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] { LocalRef::Place(va_list) => { - bx.va_end(va_list.llval); + bx.va_end(va_list.val.llval); } _ => bug!("C-variadic function must have a `VaList` place"), } @@ -455,8 +455,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { PassMode::Direct(_) | PassMode::Pair(..) => { let op = self.codegen_consume(bx, mir::Place::return_place().as_ref()); - if let Ref(llval, _, align) = op.val { - bx.load(bx.backend_type(op.layout), llval, align) + if let Ref(place_val) = op.val { + bx.load_from_place(bx.backend_type(op.layout), place_val) } else { op.immediate_or_packed_pair(bx) } @@ -466,21 +466,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let op = match self.locals[mir::RETURN_PLACE] { LocalRef::Operand(op) => op, LocalRef::PendingOperand => bug!("use of return before def"), - LocalRef::Place(cg_place) => OperandRef { - val: Ref(cg_place.llval, None, cg_place.align), - layout: cg_place.layout, - }, + LocalRef::Place(cg_place) => { + OperandRef { val: Ref(cg_place.val), layout: cg_place.layout } + } LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), }; let llslot = match op.val { Immediate(_) | Pair(..) => { let scratch = PlaceRef::alloca(bx, self.fn_abi.ret.layout); op.val.store(bx, scratch); - scratch.llval + scratch.val.llval } - Ref(llval, _, align) => { - assert_eq!(align, op.layout.align.abi, "return place is unaligned!"); - llval + Ref(place_val) => { + assert_eq!( + place_val.align, op.layout.align.abi, + "return place is unaligned!" + ); + place_val.llval } ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"), }; @@ -512,11 +514,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let place = self.codegen_place(bx, location.as_ref()); let (args1, args2); - let mut args = if let Some(llextra) = place.llextra { - args2 = [place.llval, llextra]; + let mut args = if let Some(llextra) = place.val.llextra { + args2 = [place.val.llval, llextra]; &args2[..] } else { - args1 = [place.llval]; + args1 = [place.val.llval]; &args1[..] }; let (drop_fn, fn_abi, drop_instance) = @@ -918,7 +920,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let dest = match ret_dest { _ if fn_abi.ret.is_indirect() => llargs[0], ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), - ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval, + ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.val.llval, ReturnDest::DirectOperand(_) => { bug!("Cannot use direct operand with an intrinsic call") } @@ -951,7 +953,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(bx, ret_dest, &fn_abi.ret, dst.llval); + self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); } return if let Some(target) = target { @@ -1032,7 +1034,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs.push(data_ptr); continue 'make_args; } - Ref(data_ptr, Some(meta), _) => { + Ref(PlaceValue { llval: data_ptr, llextra: Some(meta), .. }) => { // by-value dynamic dispatch llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( bx, @@ -1058,16 +1060,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { span_bug!(span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); - let data_ptr = place.project_field(bx, 0); - let meta_ptr = place.project_field(bx, 1); - let meta = bx.load_operand(meta_ptr); + let data_place = place.project_field(bx, 0); + let meta_place = place.project_field(bx, 1); + let meta = bx.load_operand(meta_place); llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( bx, meta.immediate(), op.layout.ty, fn_abi, )); - llargs.push(data_ptr.llval); + llargs.push(data_place.val.llval); continue; } _ => { @@ -1079,12 +1081,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The callee needs to own the argument memory if we pass it // by-ref, so make a local copy of non-immediate constants. match (&arg.node, op.val) { - (&mir::Operand::Copy(_), Ref(_, None, _)) - | (&mir::Operand::Constant(_), Ref(_, None, _)) => { + (&mir::Operand::Copy(_), Ref(PlaceValue { llextra: None, .. })) + | (&mir::Operand::Constant(_), Ref(PlaceValue { llextra: None, .. })) => { let tmp = PlaceRef::alloca(bx, op.layout); - bx.lifetime_start(tmp.llval, tmp.layout.size); + bx.lifetime_start(tmp.val.llval, tmp.layout.size); op.val.store(bx, tmp); - op.val = Ref(tmp.llval, None, tmp.align); + op.val = Ref(tmp.val); copied_constant_arguments.push(tmp); } _ => {} @@ -1428,7 +1430,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("codegen_argument: {:?} invalid for pair argument", op), }, PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val { - Ref(a, Some(b), _) => { + Ref(PlaceValue { llval: a, llextra: Some(b), .. }) => { llargs.push(a); llargs.push(b); return; @@ -1450,41 +1452,34 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); op.val.store(bx, scratch); - (scratch.llval, scratch.align, true) + (scratch.val.llval, scratch.val.align, true) } PassMode::Cast { .. } => { let scratch = PlaceRef::alloca(bx, arg.layout); op.val.store(bx, scratch); - (scratch.llval, scratch.align, true) + (scratch.val.llval, scratch.val.align, true) } _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false), }, - Ref(llval, _, align) => match arg.mode { + Ref(op_place_val) => match arg.mode { PassMode::Indirect { attrs, .. } => { let required_align = match attrs.pointee_align { Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), None => arg.layout.align.abi, }; - if align < required_align { + if op_place_val.align < required_align { // For `foo(packed.large_field)`, and types with <4 byte alignment on x86, // alignment requirements may be higher than the type's alignment, so copy // to a higher-aligned alloca. let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); - base::memcpy_ty( - bx, - scratch.llval, - scratch.align, - llval, - align, - op.layout, - MemFlags::empty(), - ); - (scratch.llval, scratch.align, true) + let op_place = PlaceRef { val: op_place_val, layout: op.layout }; + bx.typed_place_copy(scratch, op_place); + (scratch.val.llval, scratch.val.align, true) } else { - (llval, align, true) + (op_place_val.llval, op_place_val.align, true) } } - _ => (llval, align, true), + _ => (op_place_val.llval, op_place_val.align, true), }, ZeroSized => match arg.mode { PassMode::Indirect { on_stack, .. } => { @@ -1497,7 +1492,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // a pointer for `repr(C)` structs even when empty, so get // one from an `alloca` (which can be left uninitialized). let scratch = PlaceRef::alloca(bx, arg.layout); - (scratch.llval, scratch.align, true) + (scratch.val.llval, scratch.val.align, true) } _ => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"), }, @@ -1564,15 +1559,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. - if let Ref(llval, None, align) = tuple.val { - let tuple_ptr = PlaceRef::new_sized_aligned(llval, tuple.layout, align); + if let Ref(place_val) = tuple.val { + if place_val.llextra.is_some() { + bug!("closure arguments must be sized"); + } + let tuple_ptr = PlaceRef { val: place_val, layout: tuple.layout }; for i in 0..tuple.layout.fields.count() { let field_ptr = tuple_ptr.project_field(bx, i); let field = bx.load_operand(field_ptr); self.codegen_argument(bx, field, llargs, &args[i]); } - } else if let Ref(_, Some(_), _) = tuple.val { - bug!("closure arguments must be sized") } else { // If the tuple is immediate, the elements are as well. for i in 0..tuple.layout.fields.count() { @@ -1789,7 +1785,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // but the calling convention has an indirect return. let tmp = PlaceRef::alloca(bx, fn_ret.layout); tmp.storage_live(bx); - llargs.push(tmp.llval); + llargs.push(tmp.val.llval); ReturnDest::IndirectOperand(tmp, index) } else if intrinsic.is_some() { // Currently, intrinsics always need a location to store @@ -1810,7 +1806,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection }) }; if fn_ret.is_indirect() { - if dest.align < dest.layout.align.abi { + if dest.val.align < dest.layout.align.abi { // Currently, MIR code generation does not create calls // that store directly to fields of packed structs (in // fact, the calls it creates write only to temps). @@ -1819,7 +1815,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to create a temporary. span_bug!(self.mir.span, "can't directly store to unaligned value"); } - llargs.push(dest.llval); + llargs.push(dest.val.llval); ReturnDest::Nothing } else { ReturnDest::Store(dest) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 0387c430d32..a5fd82a3054 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -14,7 +14,7 @@ use rustc_span::{BytePos, Span}; use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; -use super::place::PlaceRef; +use super::place::{PlaceRef, PlaceValue}; use super::{FunctionCx, LocalRef}; use std::ops::Range; @@ -252,7 +252,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // at least for the cases which LLVM handles correctly. let spill_slot = PlaceRef::alloca(bx, operand.layout); if let Some(name) = name { - bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); + bx.set_var_name(spill_slot.val.llval, &(name + ".dbg.spill")); } operand.val.store(bx, spill_slot); spill_slot @@ -331,10 +331,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(name) = &name { match local_ref { LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => { - bx.set_var_name(place.llval, name); + bx.set_var_name(place.val.llval, name); } LocalRef::Operand(operand) => match operand.val { - OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { + OperandValue::Ref(PlaceValue { llval: x, .. }) | OperandValue::Immediate(x) => { bx.set_var_name(x, name); } OperandValue::Pair(a, b) => { @@ -417,16 +417,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty); let ptr_layout = bx.layout_of(ptr_ty); let alloca = PlaceRef::alloca(bx, ptr_layout); - bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); + bx.set_var_name(alloca.val.llval, &(var.name.to_string() + ".dbg.spill")); // Write the pointer to the variable - bx.store(place.llval, alloca.llval, alloca.align); + bx.store_to_place(place.val.llval, alloca.val); // Point the debug info to `*alloca` for the current variable bx.dbg_var_addr( dbg_var, dbg_loc, - alloca.llval, + alloca.val.llval, Size::ZERO, &[Size::ZERO], var.fragment, @@ -435,7 +435,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.dbg_var_addr( dbg_var, dbg_loc, - base.llval, + base.val.llval, direct_offset, &indirect_offsets, var.fragment, @@ -553,7 +553,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let base = Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx); - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment); + bx.dbg_var_addr( + dbg_var, + dbg_loc, + base.val.llval, + Size::ZERO, + &[], + fragment, + ); } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3e6cf0ece29..eb14a90412d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -387,9 +387,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let success = bx.from_immediate(success); let dest = result.project_field(bx, 0); - bx.store(val, dest.llval, dest.align); + bx.store_to_place(val, dest.val); let dest = result.project_field(bx, 1); - bx.store(success, dest.llval, dest.align); + bx.store_to_place(success, dest.val); } else { invalid_monomorphization(ty); } @@ -511,7 +511,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if !fn_abi.ret.is_ignore() { if let PassMode::Cast { .. } = &fn_abi.ret.mode { - bx.store(llval, result.llval, result.align); + bx.store_to_place(llval, result.val); } else { OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) .val diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 387a5366b20..b98e90b5cde 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -2,6 +2,7 @@ use crate::base; use crate::traits::*; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::mir::traversal; use rustc_middle::mir::UnwindTerminateReason; @@ -257,20 +258,19 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Apply debuginfo to the newly allocated locals. fx.debug_introduce_locals(&mut start_bx); - let reachable_blocks = mir.reachable_blocks_in_mono(cx.tcx(), instance); - // The builders will be created separately for each basic block at `codegen_block`. // So drop the builder of `start_llbb` to avoid having two at the same time. drop(start_bx); + let reachable_blocks = traversal::mono_reachable_as_bitset(mir, cx.tcx(), instance); + // Codegen the body of each block using reverse postorder for (bb, _) in traversal::reverse_postorder(mir) { if reachable_blocks.contains(bb) { fx.codegen_block(bb); } else { - // This may have references to things we didn't monomorphize, so we - // don't actually codegen the body. We still create the block so - // terminators in other blocks can reference it without worry. + // We want to skip this block, because it's not reachable. But we still create + // the block so terminators in other blocks can reference it. fx.codegen_block_as_unreachable(bb); } } @@ -290,6 +290,12 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut num_untupled = None; + let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id()); + let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED); + if naked { + return vec![]; + } + let args = mir .args_iter() .enumerate() @@ -337,7 +343,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() { let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); - bx.va_start(va_list.llval); + bx.va_start(va_list.val.llval); return LocalRef::Place(va_list); } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 932926976b5..9cf64e2d676 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -1,7 +1,6 @@ -use super::place::PlaceRef; +use super::place::{PlaceRef, PlaceValue}; use super::{FunctionCx, LocalRef}; -use crate::base; use crate::size_of_val; use crate::traits::*; use crate::MemFlags; @@ -24,11 +23,14 @@ pub enum OperandValue<V> { /// The second value, if any, is the extra data (vtable or length) /// which indicates that it refers to an unsized rvalue. /// - /// An `OperandValue` has this variant for types which are neither - /// `Immediate` nor `Pair`s. The backend value in this variant must be a - /// pointer to the *non*-immediate backend type. That pointee type is the + /// An `OperandValue` *must* be this variant for any type for which + /// [`LayoutTypeMethods::is_backend_ref`] returns `true`. + /// (That basically amounts to "isn't one of the other variants".) + /// + /// This holds a [`PlaceValue`] (like a [`PlaceRef`] does) with a pointer + /// to the location holding the value. The type behind that pointer is the /// one returned by [`LayoutTypeMethods::backend_type`]. - Ref(V, Option<V>, Align), + Ref(PlaceValue<V>), /// A single LLVM immediate value. /// /// An `OperandValue` *must* be this variant for any type for which @@ -222,7 +224,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self), }; let layout = cx.layout_of(projected_ty); - PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi } + let val = PlaceValue { llval: llptr, llextra, align: layout.align.abi }; + PlaceRef { val, layout } } /// If this operand is a `Pair`, we return an aggregate with the two values. @@ -362,7 +365,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1)) } else { let ptr = bx.cx().type_ptr(); - OperandValue::Ref(bx.const_poison(ptr), None, layout.align.abi) + OperandValue::Ref(PlaceValue::new_sized(bx.const_poison(ptr), layout.align.abi)) } } @@ -398,7 +401,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); } - fn store_with_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>( + pub(crate) fn store_with_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>( self, bx: &mut Bx, dest: PlaceRef<'tcx, V>, @@ -410,23 +413,17 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { // Avoid generating stores of zero-sized values, because the only way to have a zero-sized // value is through `undef`/`poison`, and the store itself is useless. } - OperandValue::Ref(r, None, source_align) => { + OperandValue::Ref(val) => { assert!(dest.layout.is_sized(), "cannot directly store unsized values"); - if flags.contains(MemFlags::NONTEMPORAL) { - // HACK(nox): This is inefficient but there is no nontemporal memcpy. - let ty = bx.backend_type(dest.layout); - let val = bx.load(ty, r, source_align); - bx.store_with_flags(val, dest.llval, dest.align, flags); - return; + if val.llextra.is_some() { + bug!("cannot directly store unsized values"); } - base::memcpy_ty(bx, dest.llval, dest.align, r, source_align, dest.layout, flags) - } - OperandValue::Ref(_, Some(_), _) => { - bug!("cannot directly store unsized values"); + let source_place = PlaceRef { val, layout: dest.layout }; + bx.typed_place_copy_with_flags(dest, source_place, flags); } OperandValue::Immediate(s) => { let val = bx.from_immediate(s); - bx.store_with_flags(val, dest.llval, dest.align, flags); + bx.store_with_flags(val, dest.val.llval, dest.val.align, flags); } OperandValue::Pair(a, b) => { let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else { @@ -435,12 +432,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi); let val = bx.from_immediate(a); - let align = dest.align; - bx.store_with_flags(val, dest.llval, align, flags); + let align = dest.val.align; + bx.store_with_flags(val, dest.val.llval, align, flags); - let llptr = bx.inbounds_ptradd(dest.llval, bx.const_usize(b_offset.bytes())); + let llptr = bx.inbounds_ptradd(dest.val.llval, bx.const_usize(b_offset.bytes())); let val = bx.from_immediate(b); - let align = dest.align.restrict_for_offset(b_offset); + let align = dest.val.align.restrict_for_offset(b_offset); bx.store_with_flags(val, llptr, align, flags); } } @@ -460,7 +457,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)) .ty; - let OperandValue::Ref(llptr, Some(llextra), _) = self else { + let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self + else { bug!("store_unsized called with a sized value (or with an extern type)") }; diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 1ec6c351e25..90627da579e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -12,25 +12,48 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; +/// The location and extra runtime properties of the place. +/// +/// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`]. #[derive(Copy, Clone, Debug)] -pub struct PlaceRef<'tcx, V> { +pub struct PlaceValue<V> { /// A pointer to the contents of the place. pub llval: V, /// This place's extra data if it is unsized, or `None` if null. pub llextra: Option<V>, - /// The monomorphized type of this place, including variant information. - pub layout: TyAndLayout<'tcx>, - /// The alignment we know for this place. pub align: Align, } +impl<V: CodegenObject> PlaceValue<V> { + /// Constructor for the ordinary case of `Sized` types. + /// + /// Sets `llextra` to `None`. + pub fn new_sized(llval: V, align: Align) -> PlaceValue<V> { + PlaceValue { llval, llextra: None, align } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct PlaceRef<'tcx, V> { + /// The location and extra runtime properties of the place. + pub val: PlaceValue<V>, + + /// The monomorphized type of this place, including variant information. + /// + /// You probably shouldn't use the alignment from this layout; + /// rather you should use the `.val.align` of the actual place, + /// which might be different from the type's normal alignment. + pub layout: TyAndLayout<'tcx>, +} + impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { assert!(layout.is_sized()); - PlaceRef { llval, llextra: None, layout, align: layout.align.abi } + let val = PlaceValue::new_sized(llval, layout.align.abi); + PlaceRef { val, layout } } pub fn new_sized_aligned( @@ -39,7 +62,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { align: Align, ) -> PlaceRef<'tcx, V> { assert!(layout.is_sized()); - PlaceRef { llval, llextra: None, layout, align } + let val = PlaceValue::new_sized(llval, align); + PlaceRef { val, layout } } // FIXME(eddyb) pass something else for the name so no work is done @@ -78,7 +102,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { if let FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); - self.llextra.unwrap() + self.val.llextra.unwrap() } else { cx.const_usize(count) } @@ -97,21 +121,27 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { ) -> Self { let field = self.layout.field(bx.cx(), ix); let offset = self.layout.fields.offset(ix); - let effective_field_align = self.align.restrict_for_offset(offset); + let effective_field_align = self.val.align.restrict_for_offset(offset); // `simple` is called when we don't need to adjust the offset to // the dynamic alignment of the field. let mut simple = || { let llval = if offset.bytes() == 0 { - self.llval + self.val.llval } else { - bx.inbounds_ptradd(self.llval, bx.const_usize(offset.bytes())) + bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes())) }; PlaceRef { - llval, - llextra: if bx.cx().type_has_metadata(field.ty) { self.llextra } else { None }, + val: PlaceValue { + llval, + llextra: if bx.cx().type_has_metadata(field.ty) { + self.val.llextra + } else { + None + }, + align: effective_field_align, + }, layout: field, - align: effective_field_align, } }; @@ -142,7 +172,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // The type `Foo<Foo<Trait>>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that // the `y` field has 16-bit alignment. - let meta = self.llextra; + let meta = self.val.llextra; let unaligned_offset = bx.cx().const_usize(offset.bytes()); @@ -164,9 +194,10 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { debug!("struct_field_ptr: DST field offset: {:?}", offset); // Adjust pointer. - let ptr = bx.inbounds_ptradd(self.llval, offset); - - PlaceRef { llval: ptr, llextra: self.llextra, layout: field, align: effective_field_align } + let ptr = bx.inbounds_ptradd(self.val.llval, offset); + let val = + PlaceValue { llval: ptr, llextra: self.val.llextra, align: effective_field_align }; + PlaceRef { val, layout: field } } /// Obtain the actual discriminant of a value. @@ -312,10 +343,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let ptr = self.project_field(bx, tag_field); let to = self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; - bx.store( + bx.store_to_place( bx.cx().const_uint_big(bx.cx().backend_type(ptr.layout), to), - ptr.llval, - ptr.align, + ptr.val, ); } Variants::Multiple { @@ -357,14 +387,16 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { }; PlaceRef { - llval: bx.inbounds_gep( - bx.cx().backend_type(self.layout), - self.llval, - &[bx.cx().const_usize(0), llindex], - ), - llextra: None, + val: PlaceValue { + llval: bx.inbounds_gep( + bx.cx().backend_type(self.layout), + self.val.llval, + &[bx.cx().const_usize(0), llindex], + ), + llextra: None, + align: self.val.align.restrict_for_offset(offset), + }, layout, - align: self.align.restrict_for_offset(offset), } } @@ -389,11 +421,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { - bx.lifetime_start(self.llval, self.layout.size); + bx.lifetime_start(self.val.llval, self.layout.size); } pub fn storage_dead<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { - bx.lifetime_end(self.llval, self.layout.size); + bx.lifetime_end(self.val.llval, self.layout.size); } } @@ -461,8 +493,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if subslice.layout.is_unsized() { assert!(from_end, "slice subslices should be `from_end`"); - subslice.llextra = - Some(bx.sub(cg_base.llextra.unwrap(), bx.cx().const_usize(from + to))); + subslice.val.llextra = Some( + bx.sub(cg_base.val.llextra.unwrap(), bx.cx().const_usize(from + to)), + ); } subslice diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4d746c89f1f..6725a6d9e38 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -68,13 +68,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { base::coerce_unsized_into(bx, scratch, dest); scratch.storage_dead(bx); } - OperandValue::Ref(llref, None, align) => { - let source = PlaceRef::new_sized_aligned(llref, operand.layout, align); + OperandValue::Ref(val) => { + if val.llextra.is_some() { + bug!("unsized coercion on an unsized rvalue"); + } + let source = PlaceRef { val, layout: operand.layout }; base::coerce_unsized_into(bx, source, dest); } - OperandValue::Ref(_, Some(_), _) => { - bug!("unsized coercion on an unsized rvalue"); - } OperandValue::ZeroSized => { bug!("unsized coercion on a ZST rvalue"); } @@ -95,20 +95,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } if let OperandValue::Immediate(v) = cg_elem.val { - let start = dest.llval; + let start = dest.val.llval; let size = bx.const_usize(dest.layout.size.bytes()); // Use llvm.memset.p0i8.* to initialize all zero arrays if bx.cx().const_to_opt_u128(v, false) == Some(0) { let fill = bx.cx().const_u8(0); - bx.memset(start, fill, size, dest.align, MemFlags::empty()); + bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); return; } // Use llvm.memset.p0i8.* to initialize byte arrays let v = bx.from_immediate(v); if bx.cx().val_ty(v) == bx.cx().type_i8() { - bx.memset(start, v, size, dest.align, MemFlags::empty()); + bx.memset(start, v, size, dest.val.align, MemFlags::empty()); return; } } @@ -182,7 +182,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Immediate(..) | OperandValue::Pair(..) => { // When we have immediate(s), the alignment of the source is irrelevant, // so we can store them using the destination's alignment. - src.val.store(bx, PlaceRef::new_sized_aligned(dst.llval, src.layout, dst.align)); + src.val.store( + bx, + PlaceRef::new_sized_aligned(dst.val.llval, src.layout, dst.val.align), + ); } } } @@ -217,10 +220,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast_kind = self.value_kind(cast); match operand.val { - OperandValue::Ref(ptr, meta, align) => { - debug_assert_eq!(meta, None); + OperandValue::Ref(source_place_val) => { + debug_assert_eq!(source_place_val.llextra, None); debug_assert!(matches!(operand_kind, OperandValueKind::Ref)); - let fake_place = PlaceRef::new_sized_aligned(ptr, cast, align); + let fake_place = PlaceRef { val: source_place_val, layout: cast }; Some(bx.load_operand(fake_place).val) } OperandValue::ZeroSized => { @@ -375,7 +378,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) { debug!( "codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})", - indirect_dest.llval, rvalue + indirect_dest.val.llval, rvalue ); match *rvalue { @@ -487,7 +490,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::CastKind::DynStar => { let (lldata, llextra) = match operand.val { - OperandValue::Ref(_, _, _) => todo!(), + OperandValue::Ref(..) => todo!(), OperandValue::Immediate(v) => (v, None), OperandValue::Pair(v, l) => (v, Some(l)), OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"), @@ -682,7 +685,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.cx().const_usize(val) } mir::NullOp::UbChecks => { - let val = bx.tcx().sess.opts.debug_assertions; + let val = bx.tcx().sess.ub_checks(); bx.cx().const_bool(val) } }; @@ -765,9 +768,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Note: places are indirect, so storing the `llval` into the // destination effectively creates a reference. let val = if !bx.cx().type_has_metadata(ty) { - OperandValue::Immediate(cg_place.llval) + OperandValue::Immediate(cg_place.val.llval) } else { - OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap()) + OperandValue::Pair(cg_place.val.llval, cg_place.val.llextra.unwrap()) }; OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 6c8dcc5b690..9191618c064 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -12,7 +12,7 @@ use crate::common::{ AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, }; use crate::mir::operand::{OperandRef, OperandValue}; -use crate::mir::place::PlaceRef; +use crate::mir::place::{PlaceRef, PlaceValue}; use crate::MemFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -156,6 +156,10 @@ pub trait BuilderMethods<'a, 'tcx>: order: AtomicOrdering, size: Size, ) -> Self::Value; + fn load_from_place(&mut self, ty: Self::Type, place: PlaceValue<Self::Value>) -> Self::Value { + debug_assert_eq!(place.llextra, None); + self.load(ty, place.llval, place.align) + } fn load_operand(&mut self, place: PlaceRef<'tcx, Self::Value>) -> OperandRef<'tcx, Self::Value>; @@ -171,6 +175,10 @@ pub trait BuilderMethods<'a, 'tcx>: fn nonnull_metadata(&mut self, load: Self::Value); fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value; + fn store_to_place(&mut self, val: Self::Value, place: PlaceValue<Self::Value>) -> Self::Value { + debug_assert_eq!(place.llextra, None); + self.store(val, place.llval, place.align) + } fn store_with_flags( &mut self, val: Self::Value, @@ -281,17 +289,32 @@ pub trait BuilderMethods<'a, 'tcx>: dst: PlaceRef<'tcx, Self::Value>, src: PlaceRef<'tcx, Self::Value>, ) { - debug_assert!(src.llextra.is_none()); - debug_assert!(dst.llextra.is_none()); + self.typed_place_copy_with_flags(dst, src, MemFlags::empty()); + } + + fn typed_place_copy_with_flags( + &mut self, + dst: PlaceRef<'tcx, Self::Value>, + src: PlaceRef<'tcx, Self::Value>, + flags: MemFlags, + ) { + debug_assert!(src.val.llextra.is_none(), "cannot directly copy from unsized values"); + debug_assert!(dst.val.llextra.is_none(), "cannot directly copy into unsized values"); debug_assert_eq!(dst.layout.size, src.layout.size); - if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memcpy. + let ty = self.backend_type(dst.layout); + let val = self.load_from_place(ty, src.val); + self.store_with_flags(val, dst.val.llval, dst.val.align, flags); + } else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout) + { // If we're not optimizing, the aliasing information from `memcpy` // isn't useful, so just load-store the value for smaller code. let temp = self.load_operand(src); - temp.val.store(self, dst); + temp.val.store_with_flags(self, dst, flags); } else if !dst.layout.is_zst() { let bytes = self.const_usize(dst.layout.size.bytes()); - self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, MemFlags::empty()); + self.memcpy(dst.val.llval, dst.val.align, src.val.llval, src.val.align, bytes, flags); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 555833759eb..34d9e75036f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -133,28 +133,6 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { || self.is_backend_immediate(layout) || self.is_backend_scalar_pair(layout)) } - - /// A type that can be used in a [`super::BuilderMethods::load`] + - /// [`super::BuilderMethods::store`] pair to implement a *typed* copy, - /// such as a MIR `*_0 = *_1`. - /// - /// It's always legal to return `None` here, as the provided impl does, - /// in which case callers should use [`super::BuilderMethods::memcpy`] - /// instead of the `load`+`store` pair. - /// - /// This can be helpful for things like arrays, where the LLVM backend type - /// `[3 x i16]` optimizes to three separate loads and stores, but it can - /// instead be copied via an `i48` that stays as the single `load`+`store`. - /// (As of 2023-05 LLVM cannot necessarily optimize away a `memcpy` in these - /// cases, due to `poison` handling, but in codegen we have more information - /// about the type invariants, so can emit something better instead.) - /// - /// This *should* return `None` for particularly-large types, where leaving - /// the `memcpy` may well be important to avoid code size explosion. - fn scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option<Self::Type> { - let _ = layout; - None - } } // For backends that support CFI using type membership (i.e., testing whether a given pointer is diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index d91ad3fcab1..dcfce4e35e0 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; @@ -98,6 +99,16 @@ fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::Leaf(val.assert_int())) } + ty::Pat(base, ..) => { + let mut place = place.clone(); + // The valtree of the base type is the same as the valtree of the pattern type. + // Since the returned valtree does not contain the type or layout, we can just + // switch to the base type. + place.layout = ecx.layout_of(*base).unwrap(); + ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes)) + }, + + ty::RawPtr(_, _) => { // Not all raw pointers are allowed, as we cannot properly test them for // equality at compile-time (see `ptr_guaranteed_cmp`). @@ -273,7 +284,7 @@ pub fn valtree_to_const_value<'tcx>( let (param_env, ty) = param_env_ty.into_parts(); - match ty.kind() { + match *ty.kind() { ty::FnDef(..) => { assert!(valtree.unwrap_branch().is_empty()); mir::ConstValue::ZeroSized @@ -286,10 +297,11 @@ pub fn valtree_to_const_value<'tcx>( ), } } + ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree), ty::Ref(_, inner_ty, _) => { let mut ecx = mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); - let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty); + let imm = valtree_to_ref(&mut ecx, valtree, inner_ty); let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap()); op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3283bcc4c45..62d169db628 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1060,6 +1060,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), + ty::Pat(ty, ..) => is_very_trivially_sized(*ty), + // We don't want to do any queries, so there is not much we can do with ADTs. ty::Adt(..) => false, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a8478f721c7..63c709d8aed 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -69,6 +69,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { throw_inval!(TooGeneric) } + ty::Pat(_, pat) => match **pat { + ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx), + // Future pattern kinds may have more variants + }, ty::Bound(_, _) => bug!("bound ty during ctfe"), ty::Bool | ty::Char diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9114ffff6fd..db6c2833b9d 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -258,7 +258,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = layout.offset_of_subfield(self, fields.iter()).bytes(); Scalar::from_target_usize(val, self) } - mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.opts.debug_assertions), + mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()), }; self.write_scalar(val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d18600ce7d7..9911c59d4b8 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -640,6 +640,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Str | ty::Dynamic(..) | ty::Closure(..) + | ty::Pat(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => Ok(false), // Some types only occur during typechecking, they have no layout. diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index f3db7d4cd42..e474b952938 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -31,6 +31,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::Uint(_) | ty::Float(_) | ty::Str + | ty::Pat(_, _) | ty::Array(_, _) | ty::Slice(_) | ty::RawPtr(_, _) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 9eb4b5278c0..7a77f2c0dbb 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -1,4 +1,4 @@ -use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors}; +use super::{DirectedGraph, StartNode, Successors}; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use std::ops::ControlFlow; @@ -6,14 +6,14 @@ use std::ops::ControlFlow; #[cfg(test)] mod tests; -pub fn post_order_from<G: DirectedGraph + WithSuccessors + WithNumNodes>( +pub fn post_order_from<G: DirectedGraph + Successors>( graph: &G, start_node: G::Node, ) -> Vec<G::Node> { post_order_from_to(graph, start_node, None) } -pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>( +pub fn post_order_from_to<G: DirectedGraph + Successors>( graph: &G, start_node: G::Node, end_node: Option<G::Node>, @@ -27,7 +27,7 @@ pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>( result } -fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>( +fn post_order_walk<G: DirectedGraph + Successors>( graph: &G, node: G::Node, result: &mut Vec<G::Node>, @@ -60,7 +60,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>( } } -pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>( +pub fn reverse_post_order<G: DirectedGraph + Successors>( graph: &G, start_node: G::Node, ) -> Vec<G::Node> { @@ -72,7 +72,7 @@ pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>( /// A "depth-first search" iterator for a directed graph. pub struct DepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { graph: &'graph G, stack: Vec<G::Node>, @@ -81,7 +81,7 @@ where impl<'graph, G> DepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { pub fn new(graph: &'graph G) -> Self { Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } @@ -127,7 +127,7 @@ where impl<G> std::fmt::Debug for DepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut f = fmt.debug_set(); @@ -140,7 +140,7 @@ where impl<G> Iterator for DepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { type Item = G::Node; @@ -201,7 +201,7 @@ struct Event<N> { /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms pub struct TriColorDepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { graph: &'graph G, stack: Vec<Event<G::Node>>, @@ -211,7 +211,7 @@ where impl<'graph, G> TriColorDepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { pub fn new(graph: &'graph G) -> Self { TriColorDepthFirstSearch { @@ -278,7 +278,7 @@ where impl<G> TriColorDepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode, + G: ?Sized + DirectedGraph + Successors + StartNode, { /// Performs a depth-first search, starting from `G::start_node()`. /// diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index e06ab2fe36b..3ae3023a91b 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -12,70 +12,43 @@ mod tests; pub trait DirectedGraph { type Node: Idx; -} -pub trait WithNumNodes: DirectedGraph { fn num_nodes(&self) -> usize; } -pub trait WithNumEdges: DirectedGraph { +pub trait NumEdges: DirectedGraph { fn num_edges(&self) -> usize; } -pub trait WithSuccessors: DirectedGraph -where - Self: for<'graph> GraphSuccessors<'graph, Item = <Self as DirectedGraph>::Node>, -{ - fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter; - - fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> - where - Self: WithNumNodes, - { - iterate::DepthFirstSearch::new(self).with_start_node(from) - } -} - -#[allow(unused_lifetimes)] -pub trait GraphSuccessors<'graph> { - type Item; - type Iter: Iterator<Item = Self::Item>; -} - -pub trait WithPredecessors: DirectedGraph -where - Self: for<'graph> GraphPredecessors<'graph, Item = <Self as DirectedGraph>::Node>, -{ - fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter; -} - -#[allow(unused_lifetimes)] -pub trait GraphPredecessors<'graph> { - type Item; - type Iter: Iterator<Item = Self::Item>; -} - -pub trait WithStartNode: DirectedGraph { +pub trait StartNode: DirectedGraph { fn start_node(&self) -> Self::Node; } -pub trait ControlFlowGraph: - DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes -{ - // convenient trait +pub trait Successors: DirectedGraph { + fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node>; } -impl<T> ControlFlowGraph for T where - T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes -{ +pub trait Predecessors: DirectedGraph { + fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node>; } +/// Alias for [`DirectedGraph`] + [`StartNode`] + [`Predecessors`] + [`Successors`]. +pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors {} +impl<T> ControlFlowGraph for T where T: DirectedGraph + StartNode + Predecessors + Successors {} + /// Returns `true` if the graph has a cycle that is reachable from the start node. pub fn is_cyclic<G>(graph: &G) -> bool where - G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, + G: ?Sized + DirectedGraph + StartNode + Successors, { iterate::TriColorDepthFirstSearch::new(graph) .run_from_start(&mut iterate::CycleDetector) .is_some() } + +pub fn depth_first_search<G>(graph: &G, from: G::Node) -> iterate::DepthFirstSearch<'_, G> +where + G: ?Sized + Successors, +{ + iterate::DepthFirstSearch::new(graph).with_start_node(from) +} diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs index c259fe56c15..7a487552f53 100644 --- a/compiler/rustc_data_structures/src/graph/reference.rs +++ b/compiler/rustc_data_structures/src/graph/reference.rs @@ -2,38 +2,26 @@ use super::*; impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { type Node = G::Node; -} -impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { fn num_nodes(&self) -> usize { (**self).num_nodes() } } -impl<'graph, G: WithStartNode> WithStartNode for &'graph G { +impl<'graph, G: StartNode> StartNode for &'graph G { fn start_node(&self) -> Self::Node { (**self).start_node() } } -impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { - fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { +impl<'graph, G: Successors> Successors for &'graph G { + fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { (**self).successors(node) } } -impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { - fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter { +impl<'graph, G: Predecessors> Predecessors for &'graph G { + fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { (**self).predecessors(node) } } - -impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = <G as GraphPredecessors<'iter>>::Iter; -} - -impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = <G as GraphSuccessors<'iter>>::Iter; -} diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index b54d75f7ed7..5021e5e8fc0 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -7,7 +7,7 @@ use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors}; +use crate::graph::{DirectedGraph, NumEdges, Successors}; use rustc_index::{Idx, IndexSlice, IndexVec}; use std::ops::Range; @@ -39,7 +39,7 @@ pub struct SccData<S: Idx> { } impl<N: Idx, S: Idx + Ord> Sccs<N, S> { - pub fn new(graph: &(impl DirectedGraph<Node = N> + WithNumNodes + WithSuccessors)) -> Self { + pub fn new(graph: &(impl DirectedGraph<Node = N> + Successors)) -> Self { SccsConstruction::construct(graph) } @@ -89,30 +89,22 @@ impl<N: Idx, S: Idx + Ord> Sccs<N, S> { } } -impl<N: Idx, S: Idx> DirectedGraph for Sccs<N, S> { +impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> { type Node = S; -} -impl<N: Idx, S: Idx + Ord> WithNumNodes for Sccs<N, S> { fn num_nodes(&self) -> usize { self.num_sccs() } } -impl<N: Idx, S: Idx> WithNumEdges for Sccs<N, S> { +impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> { fn num_edges(&self) -> usize { self.scc_data.all_successors.len() } } -impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> { - type Item = S; - - type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>; -} - -impl<N: Idx, S: Idx + Ord> WithSuccessors for Sccs<N, S> { - fn successors(&self, node: S) -> <Self as GraphSuccessors<'_>>::Iter { +impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> { + fn successors(&self, node: S) -> impl Iterator<Item = Self::Node> { self.successors(node).iter().cloned() } } @@ -158,7 +150,7 @@ impl<S: Idx> SccData<S> { } } -struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> { +struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> { graph: &'c G, /// The state of each node; used during walk to record the stack @@ -218,7 +210,7 @@ enum WalkReturn<S> { impl<'c, G, S> SccsConstruction<'c, G, S> where - G: DirectedGraph + WithNumNodes + WithSuccessors, + G: DirectedGraph + Successors, S: Idx, { /// Identifies SCCs in the graph `G` and computes the resulting diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index 7f4ef906b36..85c2703cc25 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -1,7 +1,5 @@ use crate::fx::FxHashMap; use std::cmp::max; -use std::iter; -use std::slice; use super::*; @@ -36,38 +34,26 @@ impl TestGraph { impl DirectedGraph for TestGraph { type Node = usize; -} -impl WithStartNode for TestGraph { - fn start_node(&self) -> usize { - self.start_node + fn num_nodes(&self) -> usize { + self.num_nodes } } -impl WithNumNodes for TestGraph { - fn num_nodes(&self) -> usize { - self.num_nodes +impl StartNode for TestGraph { + fn start_node(&self) -> usize { + self.start_node } } -impl WithPredecessors for TestGraph { - fn predecessors(&self, node: usize) -> <Self as GraphPredecessors<'_>>::Iter { +impl Predecessors for TestGraph { + fn predecessors(&self, node: usize) -> impl Iterator<Item = Self::Node> { self.predecessors[&node].iter().cloned() } } -impl WithSuccessors for TestGraph { - fn successors(&self, node: usize) -> <Self as GraphSuccessors<'_>>::Iter { +impl Successors for TestGraph { + fn successors(&self, node: usize) -> impl Iterator<Item = Self::Node> { self.successors[&node].iter().cloned() } } - -impl<'graph> GraphPredecessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned<slice::Iter<'graph, usize>>; -} - -impl<'graph> GraphSuccessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned<slice::Iter<'graph, usize>>; -} diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs index 00f6266ce1d..26c86469fad 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -1,4 +1,4 @@ -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors}; +use crate::graph::{DirectedGraph, NumEdges, Successors}; use rustc_index::{Idx, IndexVec}; #[cfg(test)] @@ -80,28 +80,20 @@ impl<N: Idx + Ord> VecGraph<N> { impl<N: Idx> DirectedGraph for VecGraph<N> { type Node = N; -} -impl<N: Idx> WithNumNodes for VecGraph<N> { fn num_nodes(&self) -> usize { self.node_starts.len() - 1 } } -impl<N: Idx> WithNumEdges for VecGraph<N> { +impl<N: Idx> NumEdges for VecGraph<N> { fn num_edges(&self) -> usize { self.edge_targets.len() } } -impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph<N> { - type Item = N; - - type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>; -} - -impl<N: Idx + Ord> WithSuccessors for VecGraph<N> { - fn successors(&self, node: N) -> <Self as GraphSuccessors<'_>>::Iter { +impl<N: Idx + Ord> Successors for VecGraph<N> { + fn successors(&self, node: N) -> impl Iterator<Item = Self::Node> { self.successors(node).iter().cloned() } } diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs index 7c866da6009..87c8d25f094 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs @@ -1,3 +1,5 @@ +use crate::graph; + use super::*; fn create_graph() -> VecGraph<usize> { @@ -37,6 +39,6 @@ fn successors() { #[test] fn dfs() { let graph = create_graph(); - let dfs: Vec<_> = graph.depth_first_search(0).collect(); + let dfs: Vec<_> = graph::depth_first_search(&graph, 0).collect(); assert_eq!(dfs, vec![0, 1, 3, 4, 2]); } diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 4a0ed87f77c..4c9acfe0f71 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -1,5 +1,8 @@ //! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes. +// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. +// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 +use rustc_serialize::int_overflow::{DebugStrictAdd, DebugStrictSub}; use std::hash::Hasher; use std::mem::{self, MaybeUninit}; use std::ptr; @@ -103,19 +106,19 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) } let mut i = 0; - if i + 3 < count { + if i.debug_strict_add(3) < count { ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); - i += 4; + i = i.debug_strict_add(4); } - if i + 1 < count { + if i.debug_strict_add(1) < count { ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); - i += 2 + i = i.debug_strict_add(2) } if i < count { *dst.add(i) = *src.add(i); - i += 1; + i = i.debug_strict_add(1); } debug_assert_eq!(i, count); @@ -211,14 +214,14 @@ impl SipHasher128 { debug_assert!(nbuf < BUFFER_SIZE); debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - if nbuf + LEN < BUFFER_SIZE { + if nbuf.debug_strict_add(LEN) < BUFFER_SIZE { unsafe { // The memcpy call is optimized away because the size is known. let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); } - self.nbuf = nbuf + LEN; + self.nbuf = nbuf.debug_strict_add(LEN); return; } @@ -265,8 +268,9 @@ impl SipHasher128 { // This function should only be called when the write fills the buffer. // Therefore, when LEN == 1, the new `self.nbuf` must be zero. // LEN is statically known, so the branch is optimized away. - self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE }; - self.processed += BUFFER_SIZE; + self.nbuf = + if LEN == 1 { 0 } else { nbuf.debug_strict_add(LEN).debug_strict_sub(BUFFER_SIZE) }; + self.processed = self.processed.debug_strict_add(BUFFER_SIZE); } } @@ -277,7 +281,7 @@ impl SipHasher128 { let nbuf = self.nbuf; debug_assert!(nbuf < BUFFER_SIZE); - if nbuf + length < BUFFER_SIZE { + if nbuf.debug_strict_add(length) < BUFFER_SIZE { unsafe { let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); @@ -289,7 +293,7 @@ impl SipHasher128 { } } - self.nbuf = nbuf + length; + self.nbuf = nbuf.debug_strict_add(length); return; } @@ -315,7 +319,7 @@ impl SipHasher128 { // This function should only be called when the write fills the buffer, // so we know that there is enough input to fill the current element. let valid_in_elem = nbuf % ELEM_SIZE; - let needed_in_elem = ELEM_SIZE - valid_in_elem; + let needed_in_elem = ELEM_SIZE.debug_strict_sub(valid_in_elem); let src = msg.as_ptr(); let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); @@ -327,7 +331,7 @@ impl SipHasher128 { // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. // We know that is true, because last step ensured we have a full // element in the buffer. - let last = nbuf / ELEM_SIZE + 1; + let last = (nbuf / ELEM_SIZE).debug_strict_add(1); for i in 0..last { let elem = self.buf.get_unchecked(i).assume_init().to_le(); @@ -338,7 +342,7 @@ impl SipHasher128 { // Process the remaining element-sized chunks of input. let mut processed = needed_in_elem; - let input_left = length - processed; + let input_left = length.debug_strict_sub(processed); let elems_left = input_left / ELEM_SIZE; let extra_bytes_left = input_left % ELEM_SIZE; @@ -347,7 +351,7 @@ impl SipHasher128 { self.state.v3 ^= elem; Sip13Rounds::c_rounds(&mut self.state); self.state.v0 ^= elem; - processed += ELEM_SIZE; + processed = processed.debug_strict_add(ELEM_SIZE); } // Copy remaining input into start of buffer. @@ -356,7 +360,7 @@ impl SipHasher128 { copy_nonoverlapping_small(src, dst, extra_bytes_left); self.nbuf = extra_bytes_left; - self.processed += nbuf + processed; + self.processed = self.processed.debug_strict_add(nbuf.debug_strict_add(processed)); } } @@ -394,7 +398,7 @@ impl SipHasher128 { }; // Finalize the hash. - let length = self.processed + self.nbuf; + let length = self.processed.debug_strict_add(self.nbuf); let b: u64 = ((length as u64 & 0xff) << 56) | elem; state.v3 ^= b; diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index e4fb13822f8..a8bba3afb7e 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -ctrlc = "3.4.4" rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } @@ -66,6 +65,11 @@ features = [ "Win32_System_Diagnostics_Debug", ] +[target.'cfg(not(target_family = "wasm"))'.dependencies] +# tidy-alphabetical-start +ctrlc = "3.4.4" +# tidy-alphabetical-end + [features] # tidy-alphabetical-start llvm = ['rustc_interface/llvm'] diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 1b69a6e2fbe..5b39248302e 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,10 +1,7 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly -driver_impl_ice_bug_report_outdated = - it seems that this compiler `{$version}` is outdated, a newer nightly should have been released in the mean time - .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists - .url = if the problem still persists, we would appreciate a bug report: {$bug_report_url} +driver_impl_ice_bug_report_update_note = please make sure that you have updated to the latest nightly driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden driver_impl_ice_flags = compiler flags: {$flags} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b4007aeb8d7..b3cba4dbfc2 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -61,7 +61,7 @@ use std::str; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; -use time::{Date, OffsetDateTime, Time}; +use time::OffsetDateTime; #[allow(unused_macros)] macro do_not_use_print($($t:tt)*) { @@ -1385,9 +1385,6 @@ pub fn install_ice_hook( using_internal_features } -const DATE_FORMAT: &[time::format_description::FormatItem<'static>] = - &time::macros::format_description!("[year]-[month]-[day]"); - /// Prints the ICE message, including query stack, but without backtrace. /// /// The message will point the user at `bug_report_url` to report the ICE. @@ -1416,33 +1413,14 @@ fn report_ice( dcx.emit_err(session_diagnostics::Ice); } - use time::ext::NumericalDuration; - - // Try to hint user to update nightly if applicable when reporting an ICE. - // Attempt to calculate when current version was released, and add 12 hours - // as buffer. If the current version's release timestamp is older than - // the system's current time + 24 hours + 12 hours buffer if we're on - // nightly. - if let Some("nightly") = option_env!("CFG_RELEASE_CHANNEL") - && let Some(version) = option_env!("CFG_VERSION") - && let Some(ver_date_str) = option_env!("CFG_VER_DATE") - && let Ok(ver_date) = Date::parse(&ver_date_str, DATE_FORMAT) - && let ver_datetime = OffsetDateTime::new_utc(ver_date, Time::MIDNIGHT) - && let system_datetime = OffsetDateTime::from(SystemTime::now()) - && system_datetime.checked_sub(36.hours()).is_some_and(|d| d > ver_datetime) - && !using_internal_features.load(std::sync::atomic::Ordering::Relaxed) - { - dcx.emit_note(session_diagnostics::IceBugReportOutdated { - version, - bug_report_url, - note_update: (), - note_url: (), - }); + if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { + dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); } else { - if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { - dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); - } else { - dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + + // Only emit update nightly hint for users on nightly builds. + if rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { + dcx.emit_note(session_diagnostics::UpdateNightlyNote); } } @@ -1522,6 +1500,7 @@ pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) { /// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`]. /// Making this handler optional lets tools can install a different handler, if they wish. pub fn install_ctrlc_handler() { + #[cfg(not(target_family = "wasm"))] ctrlc::set_handler(move || { // Indicate that we have been signaled to stop. If we were already signaled, exit // immediately. In our interpreter loop we try to consult this value often, but if for diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index c9bbe45b212..c0c6201f73d 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -336,7 +336,8 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirTree => { let tcx = ex.tcx(); let mut out = String::new(); - if rustc_hir_analysis::check_crate(tcx).is_err() { + rustc_hir_analysis::check_crate(tcx); + if tcx.dcx().has_errors().is_some() { FatalError.raise(); } debug!("pretty printing THIR tree"); @@ -348,7 +349,8 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirFlat => { let tcx = ex.tcx(); let mut out = String::new(); - if rustc_hir_analysis::check_crate(tcx).is_err() { + rustc_hir_analysis::check_crate(tcx); + if tcx.dcx().has_errors().is_some() { FatalError.raise(); } debug!("pretty printing THIR flat"); diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 62d0da62d2a..1a9683e840a 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -43,19 +43,12 @@ pub(crate) struct IceBugReport<'a> { } #[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_internal_feature)] -pub(crate) struct IceBugReportInternalFeature; +#[diag(driver_impl_ice_bug_report_update_note)] +pub(crate) struct UpdateNightlyNote; #[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_outdated)] -pub(crate) struct IceBugReportOutdated<'a> { - pub version: &'a str, - pub bug_report_url: &'a str, - #[note(driver_impl_update)] - pub note_update: (), - #[note(driver_impl_url)] - pub note_url: (), -} +#[diag(driver_impl_ice_bug_report_internal_feature)] +pub(crate) struct IceBugReportInternalFeature; #[derive(Diagnostic)] #[diag(driver_impl_ice_version)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0384.md b/compiler/rustc_error_codes/src/error_codes/E0384.md index e21fac0797c..6680dbed3dd 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0384.md +++ b/compiler/rustc_error_codes/src/error_codes/E0384.md @@ -18,3 +18,16 @@ fn main() { x = 5; } ``` + +Alternatively, you might consider initializing a new variable: either with a new +bound name or (by [shadowing]) with the bound name of your existing variable. +For example: + +[shadowing]: https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing + +``` +fn main() { + let x = 3; + let x = 5; +} +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0699.md b/compiler/rustc_error_codes/src/error_codes/E0699.md index 454d2507e5e..1094ebf4b8f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0699.md +++ b/compiler/rustc_error_codes/src/error_codes/E0699.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + A method was called on a raw pointer whose inner type wasn't completely known. Erroneous code example: -```compile_fail,edition2018,E0699 +```compile_fail,edition2018 # #![deny(warnings)] # fn main() { let foo = &1; diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index da688e385aa..f4a33a05c1b 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -441,7 +441,7 @@ E0695: 0695, E0696: 0696, E0697: 0697, E0698: 0698, -E0699: 0699, +E0699: 0699, // REMOVED: merged into generic inference var error E0700: 0700, E0701: 0701, E0703: 0703, diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index f90190797ae..6c0551848d6 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -46,6 +46,7 @@ impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T { } } +#[macro_export] macro_rules! into_diag_arg_using_display { ($( $ty:ty ),+ $(,)?) => { $( diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index bd8e78bda26..6ce3fa3535d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1513,7 +1513,9 @@ impl HumanEmitter { for line_idx in 0..annotated_file.lines.len() { let file = annotated_file.file.clone(); let line = &annotated_file.lines[line_idx]; - if let Some(source_string) = file.get_line(line.line_index - 1) { + if let Some(source_string) = + line.line_index.checked_sub(1).and_then(|l| file.get_line(l)) + { let leading_whitespace = source_string .chars() .take_while(|c| c.is_whitespace()) @@ -1553,7 +1555,10 @@ impl HumanEmitter { for line in &annotated_file.lines { max_line_len = max( max_line_len, - annotated_file.file.get_line(line.line_index - 1).map_or(0, |s| s.len()), + line.line_index + .checked_sub(1) + .and_then(|l| annotated_file.file.get_line(l)) + .map_or(0, |s| s.len()), ); for ann in &line.annotations { span_right_margin = max(span_right_margin, ann.start_col.display); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index a83f9f56beb..1eee11604ce 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -355,6 +355,8 @@ declare_features! ( (accepted, type_alias_enum_variants, "1.37.0", Some(49683)), /// Allows macros to appear in the type position. (accepted, type_macros, "1.13.0", Some(27245)), + /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`). + (accepted, type_privacy_lints, "CURRENT_RUSTC_VERSION", Some(48054)), /// Allows `const _: TYPE = VALUE`. (accepted, underscore_const_names, "1.37.0", Some(54912)), /// Allows `use path as _;` and `extern crate c as _;`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6a8a1722bcb..4f62323231a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -25,6 +25,7 @@ pub type GatedCfg = (Symbol, Symbol, GateFn); const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), + (sym::ub_checks, sym::cfg_ub_checks, cfg_fn!(cfg_ub_checks)), (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), ( sym::target_has_atomic_equal_alignment, @@ -1081,7 +1082,7 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { /// This means it can be used cross crate. pub fn encode_cross_crate(name: Symbol) -> bool { if let Some(attr) = BUILTIN_ATTRIBUTE_MAP.get(&name) { - if attr.encode_cross_crate == EncodeCrossCrate::Yes { true } else { false } + attr.encode_cross_crate == EncodeCrossCrate::Yes } else { true } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 36db377f7e0..e6b19817de3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -215,6 +215,8 @@ declare_features! ( (internal, omit_gdb_pretty_printer_section, "1.5.0", None), /// Set the maximum pattern complexity allowed (not limited by default). (internal, pattern_complexity, "1.78.0", None), + /// Allows using pattern types. + (internal, pattern_types, "CURRENT_RUSTC_VERSION", Some(123646)), /// Allows using `#[prelude_import]` on glob `use` items. (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. @@ -381,6 +383,8 @@ declare_features! ( (unstable, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822)), /// Allows `cfg(target_thread_local)`. (unstable, cfg_target_thread_local, "1.7.0", Some(29594)), + /// Allows the use of `#[cfg(ub_checks)` to check if UB checks are enabled. + (unstable, cfg_ub_checks, "CURRENT_RUSTC_VERSION", Some(123499)), /// Allow conditional compilation depending on rust version (unstable, cfg_version, "1.45.0", Some(64796)), /// Allows to use the `#[cfi_encoding = ""]` attribute. @@ -613,8 +617,6 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), - /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`). - (unstable, type_privacy_lints, "1.72.0", Some(48054)), /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE. (unstable, unix_sigpipe, "1.65.0", Some(97889)), /// Allows unnamed fields of struct and union type diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index e8cecb1930f..2662f5661ba 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -113,6 +113,9 @@ pub enum DefKind { InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, + /// A field in a struct, enum or union. e.g. + /// - `bar` in `struct Foo { bar: u8 }` + /// - `Foo::Bar::0` in `enum Foo { Bar(u8) }` Field, /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` LifetimeParam, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f21cd653f96..c6e3ad31f01 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2624,6 +2624,8 @@ pub enum TyKind<'hir> { Infer, /// Placeholder for a type that has failed to be defined. Err(rustc_span::ErrorGuaranteed), + /// Pattern types (`pattern_type!(u32 is 1..)`) + Pat(&'hir Ty<'hir>, &'hir Pat<'hir>), } #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8c44f21a57b..5da9d4444da 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -356,6 +356,11 @@ pub trait Visitor<'v>: Sized { fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result { walk_ty(self, t) } + fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) { + // Do nothing. Only a few visitors need to know the details of the pattern type, + // and they opt into it. All other visitors will just choke on our fake patterns + // because they aren't in a body. + } fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result { walk_generic_param(self, p) } @@ -882,6 +887,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::AnonAdt(item_id) => { try_visit!(visitor.visit_nested_item(item_id)); } + TyKind::Pat(ty, pat) => { + try_visit!(visitor.visit_ty(ty)); + try_visit!(visitor.visit_pattern_type_pattern(pat)); + } } V::Result::output() } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8a90d62dac..86b8b6d6b2b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -349,9 +349,15 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .help = cast the value to `{$cast_ty}` +hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end" +hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types" + .label = "this type is the same as the inner type without a pattern" hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} .label = not allowed in type signatures +hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}` + .note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}` + hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}` hir_analysis_return_type_notation_equality_bound = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 739a7086992..216b89fd4f1 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; @@ -22,7 +22,6 @@ use rustc_middle::ty::{ AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; -use rustc_span::symbol::sym; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -345,10 +344,7 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - let infcx = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::bind(tcx, defining_use_anchor)) - .build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); let ocx = ObligationCtxt::new(&infcx); let args = match *origin { @@ -509,7 +505,6 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { } pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let _indenter = indenter(); match tcx.def_kind(def_id) { DefKind::Static { .. } => { tcx.ensure().typeck(def_id); @@ -1567,7 +1562,7 @@ pub(super) fn check_coroutine_obligations( .ignoring_regions() // Bind opaque types to type checking root, as they should have been checked by borrowck, // but may show up in some cases, like when (root) obligations are stalled in the new solver. - .with_opaque_type_inference(DefiningAnchor::bind(tcx, typeck.hir_owner.def_id)) + .with_opaque_type_inference(typeck.hir_owner.def_id) .build(); let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx); 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 50f88eb970a..a668a104575 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1723,6 +1723,7 @@ pub(super) fn compare_impl_const_raw( compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; + check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?; compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref) } @@ -1763,8 +1764,6 @@ fn compare_const_predicate_entailment<'tcx>( let impl_ct_predicates = tcx.predicates_of(impl_ct.def_id); let trait_ct_predicates = tcx.predicates_of(trait_ct.def_id); - check_region_bounds_on_impl_item(tcx, impl_ct, trait_ct, false)?; - // The predicates declared by the impl definition, the trait and the // associated const in the trait are assumed. let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap()); @@ -1866,6 +1865,7 @@ pub(super) fn compare_impl_ty<'tcx>( let _: Result<(), ErrorGuaranteed> = try { compare_number_of_generics(tcx, impl_ty, trait_ty, false)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; + check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?; check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)?; }; @@ -1886,8 +1886,6 @@ fn compare_type_predicate_entailment<'tcx>( let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id); let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id); - check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; - let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_args); if impl_ty_own_bounds.len() == 0 { // Nothing to check. diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 1958a80d47c..45ccd0fa2e0 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -143,7 +143,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { }; assert!( ty.is_manually_drop(), - "expected first field of `MaybeUnit` to be `ManuallyDrop`" + "expected first field of `MaybeUninit` to be `ManuallyDrop`" ); let fields = &ty.non_enum_variant().fields; let ty = fields[FieldIdx::ZERO].ty(self.tcx, args); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 8760901b71b..eb0ffc19d45 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -91,17 +91,18 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::parse::feature_err; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; +use rustc_trait_selection::traits::error_reporting::suggestions::{ + ReturnsVisitor, TypeErrCtxtExt as _, +}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::ObligationCtxt; use crate::errors; use crate::require_c_abi_if_c_variadic; -use crate::util::common::indenter; use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; @@ -466,17 +467,6 @@ fn fn_sig_suggestion<'tcx>( ) } -pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { - Some(match ty.kind() { - ty::Bool => "true", - ty::Char => "'a'", - ty::Int(_) | ty::Uint(_) => "42", - ty::Float(_) => "3.14159", - ty::Error(_) | ty::Never => return None, - _ => "value", - }) -} - /// Return placeholder code for the given associated item. /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a /// structured suggestion. @@ -511,7 +501,12 @@ fn suggestion_signature<'tcx>( } ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id).instantiate_identity(); - let val = ty_kind_suggestion(ty).unwrap_or("todo!()"); + let val = tcx + .infer_ctxt() + .build() + .err_ctxt() + .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) + .unwrap_or_else(|| "value".to_string()); format!("const {}: {} = {};", assoc.name, ty, val) } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 3bdb9a214ec..397893491a3 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -689,6 +689,8 @@ fn resolve_local<'tcx>( /// | [ ..., E&, ... ] /// | ( ..., E&, ... ) /// | {...; E&} + /// | if _ { ...; E& } else { ...; E& } + /// | match _ { ..., _ => E&, ... } /// | box E& /// | E& as ... /// | ( E& ) @@ -727,6 +729,17 @@ fn resolve_local<'tcx>( record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id); } } + hir::ExprKind::If(_, then_block, else_block) => { + record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id); + if let Some(else_block) = else_block { + record_rvalue_scope_if_borrow_expr(visitor, else_block, blk_id); + } + } + hir::ExprKind::Match(_, arms, _) => { + for arm in arms { + record_rvalue_scope_if_borrow_expr(visitor, arm.body, blk_id); + } + } hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => { // FIXME(@dingxiangfei2009): choose call arguments here // for candidacy for extended parameter rule application diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4fd7c870fc7..c26f982fa47 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -8,11 +8,13 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; +use rustc_hir::def::DefKind; 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; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_macros::LintDiagnostic; use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -136,6 +138,8 @@ where infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + lint_redundant_lifetimes(tcx, body_def_id, &outlives_env); + let errors = infcx.resolve_regions(&outlives_env); if errors.is_empty() { return Ok(()); @@ -2010,6 +2014,137 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error res } +fn lint_redundant_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, + owner_id: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, +) { + let def_kind = tcx.def_kind(owner_id); + match def_kind { + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Fn + | DefKind::Const + | DefKind::Impl { of_trait: _ } => { + // Proceed + } + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + let parent_def_id = tcx.local_parent(owner_id); + if matches!(tcx.def_kind(parent_def_id), DefKind::Impl { of_trait: true }) { + // Don't check for redundant lifetimes for associated items of trait + // implementations, since the signature is required to be compatible + // with the trait, even if the implementation implies some lifetimes + // are redundant. + return; + } + } + DefKind::Mod + | DefKind::Variant + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TyParam + | DefKind::ConstParam + | DefKind::Static { .. } + | DefKind::Ctor(_, _) + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Closure => return, + } + + // The ordering of this lifetime map is a bit subtle. + // + // Specifically, we want to find a "candidate" lifetime that precedes a "victim" lifetime, + // where we can prove that `'candidate = 'victim`. + // + // `'static` must come first in this list because we can never replace `'static` with + // something else, but if we find some lifetime `'a` where `'a = 'static`, we want to + // suggest replacing `'a` with `'static`. + let mut lifetimes = vec![tcx.lifetimes.re_static]; + lifetimes.extend( + ty::GenericArgs::identity_for_item(tcx, owner_id).iter().filter_map(|arg| arg.as_region()), + ); + // If we are in a function, add its late-bound lifetimes too. + if matches!(def_kind, DefKind::Fn | DefKind::AssocFn) { + for var in tcx.fn_sig(owner_id).instantiate_identity().bound_vars() { + let ty::BoundVariableKind::Region(kind) = var else { continue }; + lifetimes.push(ty::Region::new_late_param(tcx, owner_id.to_def_id(), kind)); + } + } + lifetimes.retain(|candidate| candidate.has_name()); + + // Keep track of lifetimes which have already been replaced with other lifetimes. + // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by + // both `'a` and `'b`. + let mut shadowed = FxHashSet::default(); + + for (idx, &candidate) in lifetimes.iter().enumerate() { + // Don't suggest removing a lifetime twice. We only need to check this + // here and not up in the `victim` loop because equality is transitive, + // so if A = C and B = C, then A must = B, so it'll be shadowed too in + // A's victim loop. + if shadowed.contains(&candidate) { + continue; + } + + for &victim in &lifetimes[(idx + 1)..] { + // We should only have late-bound lifetimes of the `BrNamed` variety, + // since we get these signatures straight from `hir_lowering`. And any + // other regions (ReError/ReStatic/etc.) shouldn't matter, since we + // can't really suggest to remove them. + let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) + | ty::ReLateParam(ty::LateParamRegion { + bound_region: ty::BoundRegionKind::BrNamed(def_id, _), + .. + })) = victim.kind() + else { + continue; + }; + + // Do not rename lifetimes not local to this item since they'll overlap + // with the lint running on the parent. We still want to consider parent + // lifetimes which make child lifetimes redundant, otherwise we would + // have truncated the `identity_for_item` args above. + if tcx.parent(def_id) != owner_id.to_def_id() { + continue; + } + + // If `candidate <: victim` and `victim <: candidate`, then they're equal. + if outlives_env.free_region_map().sub_free_regions(tcx, candidate, victim) + && outlives_env.free_region_map().sub_free_regions(tcx, victim, candidate) + { + shadowed.insert(victim); + tcx.emit_node_span_lint( + rustc_lint_defs::builtin::REDUNDANT_LIFETIMES, + tcx.local_def_id_to_hir_id(def_id.expect_local()), + tcx.def_span(def_id), + RedundantLifetimeArgsLint { candidate, victim }, + ); + } + } + } +} + +#[derive(LintDiagnostic)] +#[diag(hir_analysis_redundant_lifetime_args)] +#[note] +struct RedundantLifetimeArgsLint<'tcx> { + /// The lifetime we have found to be redundant. + victim: ty::Region<'tcx>, + // The lifetime we can replace the victim with. + candidate: ty::Region<'tcx>, +} + pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 067878091a7..4a85e9983f4 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -144,7 +144,12 @@ impl<'tcx> InherentCollect<'tcx> { let id = id.owner_id.def_id; let item_span = self.tcx.def_span(id); let self_ty = self.tcx.type_of(id).instantiate_identity(); - let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty); + let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty); + // We allow impls on pattern types exactly when we allow impls on the base type. + // FIXME(pattern_types): Figure out the exact coherence rules we want here. + while let ty::Pat(base, _) = *self_ty.kind() { + self_ty = base; + } match *self_ty.kind() { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), @@ -154,6 +159,7 @@ impl<'tcx> InherentCollect<'tcx> { ty::Dynamic(..) => { Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span })) } + ty::Pat(_, _) => unreachable!(), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1770f7b4e91..5585d2e069c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -206,6 +206,11 @@ pub(crate) fn orphan_check_impl( (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) } + ty::Pat(..) => ( + LocalImpl::Disallow { problematic_kind: "pattern type" }, + NonlocalImpl::DisallowOther, + ), + ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a705d3bc107..1085caa310b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -30,7 +30,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; use rustc_target::spec::abi; use rustc_trait_selection::infer::InferCtxtExt; @@ -1373,17 +1373,19 @@ fn infer_return_ty_for_fn_sig<'tcx>( // Don't leak types into signatures unless they're nameable! // For example, if a function returns itself, we don't want that // recursive function definition to leak out into the fn sig. - let mut should_recover = false; + let mut recovered_ret_ty = None; - if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) { + if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { diag.span_suggestion( ty.span, "replace with the correct return type", - ret_ty, + suggestable_ret_ty, Applicability::MachineApplicable, ); - should_recover = true; - } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) { + recovered_ret_ty = Some(suggestable_ret_ty); + } else if let Some(sugg) = + suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty) + { diag.span_suggestion( ty.span, "replace with an appropriate return type", @@ -1402,18 +1404,13 @@ fn infer_return_ty_for_fn_sig<'tcx>( } let guar = diag.emit(); - - if should_recover { - ty::Binder::dummy(fn_sig) - } else { - ty::Binder::dummy(tcx.mk_fn_sig( - fn_sig.inputs().iter().copied(), - Ty::new_error(tcx, guar), - fn_sig.c_variadic, - fn_sig.unsafety, - fn_sig.abi, - )) - } + ty::Binder::dummy(tcx.mk_fn_sig( + fn_sig.inputs().iter().copied(), + recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), + fn_sig.c_variadic, + fn_sig.unsafety, + fn_sig.abi, + )) } None => icx.lowerer().lower_fn_ty( hir_id, @@ -1426,11 +1423,10 @@ fn infer_return_ty_for_fn_sig<'tcx>( } } -fn suggest_impl_trait<'tcx>( - tcx: TyCtxt<'tcx>, +pub fn suggest_impl_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, ret_ty: Ty<'tcx>, - span: Span, - def_id: LocalDefId, ) -> Option<String> { let format_as_assoc: fn(_, _, _, _, _) -> _ = |tcx: TyCtxt<'tcx>, @@ -1464,24 +1460,28 @@ fn suggest_impl_trait<'tcx>( for (trait_def_id, assoc_item_def_id, formatter) in [ ( - tcx.get_diagnostic_item(sym::Iterator), - tcx.get_diagnostic_item(sym::IteratorItem), + infcx.tcx.get_diagnostic_item(sym::Iterator), + infcx.tcx.get_diagnostic_item(sym::IteratorItem), format_as_assoc, ), ( - tcx.lang_items().future_trait(), - tcx.get_diagnostic_item(sym::FutureOutput), + infcx.tcx.lang_items().future_trait(), + infcx.tcx.get_diagnostic_item(sym::FutureOutput), format_as_assoc, ), - (tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized), ( - tcx.lang_items().fn_mut_trait(), - tcx.lang_items().fn_once_output(), + infcx.tcx.lang_items().fn_trait(), + infcx.tcx.lang_items().fn_once_output(), + format_as_parenthesized, + ), + ( + infcx.tcx.lang_items().fn_mut_trait(), + infcx.tcx.lang_items().fn_once_output(), format_as_parenthesized, ), ( - tcx.lang_items().fn_once_trait(), - tcx.lang_items().fn_once_output(), + infcx.tcx.lang_items().fn_once_trait(), + infcx.tcx.lang_items().fn_once_output(), format_as_parenthesized, ), ] { @@ -1491,36 +1491,45 @@ fn suggest_impl_trait<'tcx>( let Some(assoc_item_def_id) = assoc_item_def_id else { continue; }; - if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy { + if infcx.tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy { continue; } - let param_env = tcx.param_env(def_id); - let infcx = tcx.infer_ctxt().build(); - let args = ty::GenericArgs::for_item(tcx, trait_def_id, |param, _| { - if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) } + let sugg = infcx.probe(|_| { + let args = ty::GenericArgs::for_item(infcx.tcx, trait_def_id, |param, _| { + if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(DUMMY_SP, param) } + }); + if !infcx + .type_implements_trait(trait_def_id, args, param_env) + .must_apply_modulo_regions() + { + return None; + } + let ocx = ObligationCtxt::new(&infcx); + let item_ty = ocx.normalize( + &ObligationCause::dummy(), + param_env, + Ty::new_projection(infcx.tcx, assoc_item_def_id, args), + ); + // FIXME(compiler-errors): We may benefit from resolving regions here. + if ocx.select_where_possible().is_empty() + && let item_ty = infcx.resolve_vars_if_possible(item_ty) + && let Some(item_ty) = item_ty.make_suggestable(infcx.tcx, false, None) + && let Some(sugg) = formatter( + infcx.tcx, + infcx.resolve_vars_if_possible(args), + trait_def_id, + assoc_item_def_id, + item_ty, + ) + { + return Some(sugg); + } + + None }); - if !infcx.type_implements_trait(trait_def_id, args, param_env).must_apply_modulo_regions() { - continue; - } - let ocx = ObligationCtxt::new(&infcx); - let item_ty = ocx.normalize( - &ObligationCause::misc(span, def_id), - param_env, - Ty::new_projection(tcx, assoc_item_def_id, args), - ); - // FIXME(compiler-errors): We may benefit from resolving regions here. - if ocx.select_where_possible().is_empty() - && let item_ty = infcx.resolve_vars_if_possible(item_ty) - && let Some(item_ty) = item_ty.make_suggestable(tcx, false, None) - && let Some(sugg) = formatter( - tcx, - infcx.resolve_vars_if_possible(args), - trait_def_id, - assoc_item_def_id, - item_ty, - ) - { - return Some(sugg); + + if sugg.is_some() { + return sugg; } } None diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index f1b14adcb7a..c2205815ba6 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -165,10 +165,7 @@ pub(super) fn explicit_item_bounds_with_filter( ty::EarlyBinder::bind(bounds) } -pub(super) fn item_bounds( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { +pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) @@ -177,7 +174,7 @@ pub(super) fn item_bounds( pub(super) fn item_super_predicates( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { +) -> ty::EarlyBinder<ty::Clauses<'_>> { tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter( util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(), @@ -188,12 +185,12 @@ pub(super) fn item_super_predicates( pub(super) fn item_non_self_assumptions( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { +) -> ty::EarlyBinder<ty::Clauses<'_>> { let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect(); let own_bounds: FxIndexSet<_> = tcx.item_super_predicates(def_id).skip_binder().iter().collect(); if all_bounds.len() == own_bounds.len() { - ty::EarlyBinder::bind(ty::List::empty()) + ty::EarlyBinder::bind(ty::ListWithCachedTypeInfo::empty()) } else { ty::EarlyBinder::bind(tcx.mk_clauses_from_iter(all_bounds.difference(&own_bounds).copied())) } 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 0b8ac9926e4..3d16f1420d9 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -20,7 +20,6 @@ use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; -use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -719,6 +718,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] + fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::Pat<'tcx>) { + intravisit::walk_pat(self, p) + } + + #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { use self::hir::TraitItemKind::*; match trait_item.kind { @@ -867,31 +871,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }) => { self.visit_lifetime(lifetime); walk_list!(self, visit_param_bound, bounds); - - if lifetime.res != hir::LifetimeName::Static { - for bound in bounds { - let hir::GenericBound::Outlives(lt) = bound else { - continue; - }; - if lt.res != hir::LifetimeName::Static { - continue; - } - self.insert_lifetime(lt, ResolvedArg::StaticLifetime); - self.tcx.node_span_lint( - lint::builtin::UNUSED_LIFETIMES, - lifetime.hir_id, - lifetime.ident.span, - format!("unnecessary lifetime parameter `{}`", lifetime.ident), - |lint| { - let help = format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime.ident, - ); - lint.help(help); - }, - ); - } - } } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { self.visit_ty(lhs_ty); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2d4742fa1dc..d129614e0e1 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -7,6 +7,8 @@ use rustc_errors::{ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{symbol::Ident, Span, Symbol}; +mod pattern_types; +pub use pattern_types::*; #[derive(Diagnostic)] #[diag(hir_analysis_ambiguous_assoc_item)] @@ -1629,3 +1631,10 @@ pub struct OpaqueCapturesHigherRankedLifetime { pub decl_span: Span, pub bad_place: &'static str, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_pattern_type_non_const_range)] +pub struct NonConstRange { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs new file mode 100644 index 00000000000..008d2698989 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs @@ -0,0 +1,9 @@ +use rustc_macros::Diagnostic; +use rustc_span::Span; + +#[derive(Diagnostic)] +#[diag(hir_analysis_pattern_type_wild_pat)] +pub struct WildPatTy { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 70f09dd6175..822bf95305f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1134,7 +1134,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for (what, span) in types_and_spans { err.span_label(span, format!("not allowed on {what}")); } - generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend); + generics_args_err_extend(self.tcx(), segments, &mut err, err_extend); let reported = err.emit(); self.set_tainted_by_errors(reported); reported diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f726f2a7b89..b15bf54234d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -21,7 +21,7 @@ mod object_safety; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::AmbiguousLifetimeBound; +use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -39,6 +39,7 @@ use rustc_hir::{GenericArg, GenericArgs}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, TypeVisitableExt, @@ -1878,6 +1879,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.set_tainted_by_errors(e); Ty::new_error(self.tcx(), e) } + Res::Def(..) => { + assert_eq!( + path.segments.get(0).map(|seg| seg.ident.name), + Some(kw::SelfUpper), + "only expected incorrect resolution for `Self`" + ); + Ty::new_error( + self.tcx(), + self.tcx().dcx().span_delayed_bug(span, "incorrect resolution for `Self`"), + ) + } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } } @@ -2195,6 +2207,82 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // handled specially and will not descend into this routine. self.ty_infer(None, hir_ty.span) } + hir::TyKind::Pat(ty, pat) => { + let ty = self.lower_ty(ty); + let pat_ty = match pat.kind { + hir::PatKind::Wild => { + let err = tcx.dcx().emit_err(WildPatTy { span: pat.span }); + Ty::new_error(tcx, err) + } + hir::PatKind::Range(start, end, include_end) => { + let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> { + let (expr, neg) = match expr.kind { + hir::ExprKind::Unary(hir::UnOp::Neg, negated) => { + (negated, Some((expr.hir_id, expr.span))) + } + _ => (expr, None), + }; + let c = match &expr.kind { + hir::ExprKind::Lit(lit) => { + let lit_input = + LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; + match tcx.lit_to_const(lit_input) { + Ok(c) => c, + Err(LitToConstError::Reported(err)) => { + ty::Const::new_error(tcx, err, ty) + } + Err(LitToConstError::TypeError) => todo!(), + } + } + + hir::ExprKind::Path(hir::QPath::Resolved( + _, + &hir::Path { + res: Res::Def(DefKind::ConstParam, def_id), .. + }, + )) => { + let ty = tcx + .type_of(def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"); + self.lower_const_param(expr.hir_id, ty) + } + + _ => { + let err = tcx + .dcx() + .emit_err(crate::errors::NonConstRange { span: expr.span }); + ty::Const::new_error(tcx, err, ty) + } + }; + self.record_ty(expr.hir_id, c.ty(), expr.span); + if let Some((id, span)) = neg { + self.record_ty(id, c.ty(), span); + } + c + }; + + let start = start.map(expr_to_const); + let end = end.map(expr_to_const); + + let include_end = match include_end { + hir::RangeEnd::Included => true, + hir::RangeEnd::Excluded => false, + }; + + let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end }); + Ty::new_pat(tcx, ty, pat) + } + hir::PatKind::Err(e) => Ty::new_error(tcx, e), + _ => Ty::new_error_with_message( + tcx, + pat.span, + format!("unsupported pattern for pattern type: {pat:#?}"), + ), + }; + self.record_ty(pat.hir_id, ty, pat.span); + pat_ty + } hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index b7786ec219c..c374f9762d6 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -97,14 +97,12 @@ mod outlives; pub mod structured_errors; mod variance; -use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::util; use rustc_session::parse::feature_err; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; @@ -153,11 +151,11 @@ pub fn provide(providers: &mut Providers) { hir_wf_check::provide(providers); } -pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { +pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); if tcx.features().rustc_attrs { - tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?; + let _ = tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); } tcx.sess.time("coherence_checking", || { @@ -174,11 +172,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { }); if tcx.features().rustc_attrs { - tcx.sess.time("variance_testing", || variance::test::test_variance(tcx))?; + let _ = tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); } if tcx.features().rustc_attrs { - collect::test_opaque_hidden_types(tcx)?; + let _ = collect::test_opaque_hidden_types(tcx); } // Make sure we evaluate all static and (non-associated) const items, even if unused. @@ -213,8 +211,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { }); tcx.ensure().check_unused_traits(()); - - Ok(()) } /// Lower a [`hir::Ty`] to a [`Ty`]. diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 28c86d8019e..eeb8b028505 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -236,7 +236,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => { - bug!("Unexpected coroutine/closure type in variance computation"); + bug!("Unexpected unnameable type in variance computation: {ty}"); } ty::Ref(region, ty, mutbl) => { @@ -249,6 +249,20 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_ty(current, typ, variance); } + ty::Pat(typ, pat) => { + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + if let Some(start) = start { + self.add_constraints_from_const(current, start, variance); + } + if let Some(end) = end { + self.add_constraints_from_const(current, end, variance); + } + } + } + self.add_constraints_from_ty(current, typ, variance); + } + ty::Slice(typ) => { self.add_constraints_from_ty(current, typ, variance); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bd528432e70..39312614c1b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -330,6 +330,11 @@ impl<'a> State<'a> { self.word("_"); } hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"), + hir::TyKind::Pat(ty, pat) => { + self.print_type(ty); + self.word(" is "); + self.print_pat(pat); + } } self.end() } @@ -1137,7 +1142,7 @@ impl<'a> State<'a> { } fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) { - let assoc_op = bin_op_to_assoc_op(op.node); + let assoc_op = AssocOp::from_ast_binop(op.node); let prec = assoc_op.precedence() as i8; let fixity = assoc_op.fixity(); @@ -2323,33 +2328,6 @@ fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool { } } -fn bin_op_to_assoc_op(op: hir::BinOpKind) -> AssocOp { - use crate::hir::BinOpKind::*; - match op { - Add => AssocOp::Add, - Sub => AssocOp::Subtract, - Mul => AssocOp::Multiply, - Div => AssocOp::Divide, - Rem => AssocOp::Modulus, - - And => AssocOp::LAnd, - Or => AssocOp::LOr, - - BitXor => AssocOp::BitXor, - BitAnd => AssocOp::BitAnd, - BitOr => AssocOp::BitOr, - Shl => AssocOp::ShiftLeft, - Shr => AssocOp::ShiftRight, - - Eq => AssocOp::Equal, - Lt => AssocOp::Less, - Le => AssocOp::LessEqual, - Ne => AssocOp::NotEqual, - Ge => AssocOp::GreaterEqual, - Gt => AssocOp::Greater, - } -} - /// Expressions that syntactically contain an "exterior" struct literal, i.e., not surrounded by any /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not. diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 1d51101c940..18d9d739dd6 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -93,9 +93,6 @@ hir_typeck_lossy_provenance_ptr2int = .suggestion = use `.addr()` to obtain the address of a pointer .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead -hir_typeck_method_call_on_unknown_raw_pointee = - cannot call a method on a raw pointer with an unknown pointee type - 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 -> diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c948b6343b7..92f74281ab9 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -40,17 +40,19 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef}; use rustc_session::lint; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtExt; /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] -pub struct CastCheck<'tcx> { +pub(crate) struct CastCheck<'tcx> { /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, /// The source type for the cast expression @@ -60,8 +62,6 @@ pub struct CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - /// whether the cast is made in a const context or not. - pub constness: hir::Constness, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::CoroutineWitness(..) | ty::RawPtr(_, _) | ty::Ref(..) + | ty::Pat(..) | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) @@ -194,18 +195,45 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +/// If a cast from `from_ty` to `to_ty` is valid, returns a `Some` containing the kind +/// of the cast. +/// +/// This is a helper used from clippy. +pub fn check_cast<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + e: &'tcx hir::Expr<'tcx>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option<CastKind> { + let hir_id = e.hir_id; + let local_def_id = hir_id.owner.def_id; + + let root_ctxt = crate::TypeckRootCtxt::new(tcx, local_def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, local_def_id); + + if let Ok(check) = CastCheck::new( + &fn_ctxt, e, from_ty, to_ty, + // We won't show any errors to the user, so the span is irrelevant here. + DUMMY_SP, DUMMY_SP, + ) { + check.do_check(&fn_ctxt).ok() + } else { + None + } +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + pub(crate) fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - constness: hir::Constness, ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> { let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); - let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness }; + let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once @@ -644,7 +672,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. - pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> { + fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> { use rustc_middle::ty::cast::CastTy::*; use rustc_middle::ty::cast::IntTy::*; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 44b19318d5d..079cca82408 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -63,6 +63,7 @@ use rustc_span::DesugaringKind; use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::TraitEngineExt as _; @@ -1318,6 +1319,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +/// Check whether `ty` can be coerced to `output_ty`. +/// Used from clippy. +pub fn can_coerce<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: LocalDefId, + ty: Ty<'tcx>, + output_ty: Ty<'tcx>, +) -> bool { + let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id); + fn_ctxt.can_coerce(ty, output_ty) +} + /// CoerceMany encapsulates the pattern you should use when you have /// many expressions that are all getting coerced to a common /// type. This arises, for example, when you have a match (the result @@ -1602,6 +1617,15 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { E0069, "`return;` in a function whose return type is not `()`" ); + if let Some(value) = fcx.err_ctxt().ty_kind_suggestion(fcx.param_env, found) + { + err.span_suggestion_verbose( + cause.span.shrink_to_hi(), + "give the `return` a value of the expected type", + format!(" {value}"), + Applicability::HasPlaceholders, + ); + } err.span_label(cause.span, "return type is not `()`"); } ObligationCauseCode::BlockTailExpression(blk_id, ..) => { @@ -1990,16 +2014,17 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } - let parent_id = fcx.tcx.hir().get_parent_item(id); - let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id); + let mut parent_id = fcx.tcx.hir().get_parent_item(id).def_id; + let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id); // When suggesting return, we need to account for closures and async blocks, not just items. for (_, node) in fcx.tcx.hir().parent_iter(id) { match node { hir::Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { .. }), + kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }), .. }) => { parent_item = node; + parent_id = *def_id; break; } hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break, @@ -2009,13 +2034,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) { fcx.suggest_missing_break_or_return_expr( - &mut err, - expr, - fn_decl, - expected, - found, - id, - parent_id.into(), + &mut err, expr, fn_decl, expected, found, id, parent_id, ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index f9b2ec69730..d399730bf3d 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -77,13 +77,6 @@ pub struct StructExprNonExhaustive { } #[derive(Diagnostic)] -#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = E0699)] -pub struct MethodCallOnUnknownRawPointee { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(hir_typeck_functional_record_update_on_non_struct, code = E0436)] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d8f62f7a2b6..64590ca542d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -35,7 +35,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; -use rustc_hir_analysis::check::ty_kind_suggestion; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -57,6 +56,7 @@ use rustc_span::Span; use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -544,13 +544,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { - let from = fn_sig.inputs().skip_binder()[0]; + let Some(from) = fn_sig.inputs().skip_binder().get(0) else { + let e = self.dcx().span_delayed_bug( + tcx.def_span(did), + "intrinsic fn `transmute` defined with no parameters", + ); + self.set_tainted_by_errors(e); + return Ty::new_error(tcx, e); + }; let to = fn_sig.output().skip_binder(); // We defer the transmute to the end of typeck, once all inference vars have // been resolved or we errored. This is important as we can only check transmute // on concrete types, but the output type may not be known yet (it would only // be known if explicitly specified via turbofish). - self.deferred_transmute_checks.borrow_mut().push((from, to, expr.hir_id)); + self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } if !tcx.features().unsized_fn_params { // We want to remove some Sized bounds from std functions, @@ -687,10 +694,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); - if let Some(val) = ty_kind_suggestion(ty) { + if let Some(val) = + self.err_ctxt().ty_kind_suggestion(self.param_env, ty) + { err.span_suggestion_verbose( expr.span.shrink_to_hi(), - "give it a value of the expected type", + "give the `break` a value of the expected type", format!(" {val}"), Applicability::HasPlaceholders, ); @@ -1383,15 +1392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new( - self, - e, - t_expr, - t_cast, - t.span, - expr.span, - hir::Constness::NotConst, - ) { + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", @@ -2024,8 +2025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .sess .source_map() - .span_extend_while(range_start.span, |c| c.is_whitespace()) - .unwrap_or(range_start.span) + .span_extend_while_whitespace(range_start.span) .shrink_to_hi() .to(range_end.span); diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index fe1e4e74973..69399b50695 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -1,7 +1,6 @@ use crate::FnCtxt; use rustc_data_structures::{ - graph::WithSuccessors, - graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + graph::{self, iterate::DepthFirstSearch, vec_graph::VecGraph}, unord::{UnordBag, UnordMap, UnordSet}, }; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; @@ -300,7 +299,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { debug!( "calculate_diverging_fallback: root_vid={:?} reaches {:?}", root_vid, - coercion_graph.depth_first_search(root_vid).collect::<Vec<_>>() + graph::depth_first_search(&coercion_graph, root_vid).collect::<Vec<_>>() ); // drain the iterator to visit all nodes reachable from this node @@ -342,8 +341,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { for &diverging_vid in &diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); - let can_reach_non_diverging = coercion_graph - .depth_first_search(root_vid) + let can_reach_non_diverging = graph::depth_first_search(&coercion_graph, root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); let infer_var_infos: UnordBag<_> = self diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 85d04f7d1c4..2d5ba447e4e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -561,9 +561,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Unify `interior` with `witness` and collect all the resulting obligations. let span = self.tcx.hir().body(body_id).value.span; + let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else { + span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind()) + }; let ok = self .at(&self.misc(span), self.param_env) - .eq(DefineOpaqueTypes::No, interior, witness) + // Will never define opaque types, as all we do is instantiate a type variable. + .eq(DefineOpaqueTypes::Yes, interior, witness) .expect("Failed to unify coroutine interior type"); let mut obligations = ok.obligations; @@ -711,33 +715,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let formal_ret = self.resolve_vars_with_obligations(formal_ret); let ret_ty = expected_ret.only_has_type(self)?; - // HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour. - // Without it, the inference - // variable will get instantiated with the opaque type. The inference variable often - // has various helpful obligations registered for it that help closures figure out their - // signature. If we infer the inference var to the opaque type, the closure won't be able - // to find those obligations anymore, and it can't necessarily find them from the opaque - // type itself. We could be more powerful with inference if we *combined* the obligations - // so that we got both the obligations from the opaque type and the ones from the inference - // variable. That will accept more code than we do right now, so we need to carefully consider - // the implications. - // Note: this check is pessimistic, as the inference type could be matched with something other - // than the opaque type, but then we need a new `TypeRelation` just for this specific case and - // can't re-use `sup` below. - // See tests/ui/impl-trait/hidden-type-is-opaque.rs and - // tests/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path. - if formal_ret.has_infer_types() { - for ty in ret_ty.walk() { - if let ty::GenericArgKind::Type(ty) = ty.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() - && let Some(def_id) = def_id.as_local() - && self.opaque_type_origin(def_id).is_some() - { - return None; - } - } - } - let expect_args = self .fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); @@ -943,7 +920,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn get_node_fn_decl( &self, node: Node<'tcx>, - ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> { + ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> { match node { Node::Item(&hir::Item { ident, @@ -954,25 +931,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is less than ideal, it will not suggest a return type span on any // method called `main`, regardless of whether it is actually the entry point, // but it will still present it as the reason for the expected type. - Some(( - hir::HirId::make_owner(owner_id.def_id), - &sig.decl, - ident, - ident.name != sym::main, - )) + Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main)) } Node::TraitItem(&hir::TraitItem { ident, kind: hir::TraitItemKind::Fn(ref sig, ..), owner_id, .. - }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)), + }) => Some((owner_id.def_id, &sig.decl, ident, true)), Node::ImplItem(&hir::ImplItem { ident, kind: hir::ImplItemKind::Fn(ref sig, ..), owner_id, .. - }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)), + }) => Some((owner_id.def_id, &sig.decl, ident, false)), Node::Expr(&hir::Expr { hir_id, kind: @@ -1002,12 +974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) => (ident, sig, owner_id), _ => return None, }; - Some(( - hir::HirId::make_owner(owner_id.def_id), - &sig.decl, - ident, - ident.name != sym::main, - )) + Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main)) } _ => None, } @@ -1018,7 +985,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn get_fn_decl( &self, blk_id: hir::HirId, - ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> { + ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index a9a5a89a413..789cc52169b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), ) = error.code && let ty::Closure(def_id, _) | ty::Coroutine(def_id, ..) = - expected_trait_ref.skip_binder().self_ty().kind() + expected_trait_ref.self_ty().kind() && span.overlaps(self.tcx.def_span(*def_id)) { true diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 64b816553df..13226d304c8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -297,22 +297,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 3. Check if the formal type is a supertype of the checked one // and register any such obligations for future type checks let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty, ); - let subtyping_error = match supertype_error { + + // If neither check failed, the types are compatible + match supertype_error { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); - None + Compatibility::Compatible } - Err(err) => Some(err), - }; - - // If neither check failed, the types are compatible - match subtyping_error { - None => Compatibility::Compatible, - Some(_) => Compatibility::Incompatible(subtyping_error), + Err(err) => Compatibility::Incompatible(Some(err)), } }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 05e7c5b2b41..0b69c7a2431 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -38,7 +38,7 @@ use std::ops::Deref; /// /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt /// [`InferCtxt`]: infer::InferCtxt -pub struct FnCtxt<'a, 'tcx> { +pub(crate) struct FnCtxt<'a, 'tcx> { pub(super) body_id: LocalDefId, /// The parameter environment used for proving trait obligations diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 442bfd75746..ce203eae95f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -9,6 +9,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use crate::rustc_middle::ty::Article; use core::cmp::min; use core::iter; +use hir::def_id::LocalDefId; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_data_structures::packed::Pu128; use rustc_errors::{Applicability, Diag, MultiSpan}; @@ -20,6 +21,7 @@ use rustc_hir::{ CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; +use rustc_hir_analysis::collect::suggest_impl_trait; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{self}; use rustc_middle::lint::in_external_macro; @@ -795,7 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, can_suggest: bool, - fn_id: hir::HirId, + fn_id: LocalDefId, ) -> bool { let found = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); @@ -814,17 +816,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }, ); return true; - } else if let ty::Closure(_, args) = found.kind() - // FIXME(compiler-errors): Get better at printing binders... - && let closure = args.as_closure() - && closure.sig().is_suggestable(self.tcx, false) - { + } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) { err.subdiagnostic( self.dcx(), - errors::AddReturnTypeSuggestion::Add { - span, - found: closure.print_as_impl_trait().to_string(), - }, + errors::AddReturnTypeSuggestion::Add { span, found: sugg }, ); return true; } else { @@ -929,7 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut Diag<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, - fn_id: hir::HirId, + fn_id: LocalDefId, ) { // Only apply the suggestion if: // - the return type is a generic parameter @@ -943,7 +938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Param(expected_ty_as_param) = expected.kind() else { return }; - let fn_node = self.tcx.hir_node(fn_id); + let fn_node = self.tcx.hir_node_by_def_id(fn_id); let hir::Node::Item(hir::Item { kind: @@ -1037,7 +1032,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, id: hir::HirId, - fn_id: hir::HirId, + fn_id: LocalDefId, ) { if !expected.is_unit() { return; @@ -1089,11 +1084,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let can_return = match fn_decl.output { hir::FnRetTy::Return(ty) => { let ty = self.lowerer().lower_ty(ty); - let bound_vars = self.tcx.late_bound_vars(fn_id); + let bound_vars = self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id)); let ty = self .tcx .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); - let ty = match self.tcx.asyncness(fn_id.owner) { + let ty = match self.tcx.asyncness(fn_id) { ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { span_bug!( fn_decl.output.span(), @@ -1114,8 +1109,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => false, }; if can_return - && let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner() - && let Some(span) = expr.span.find_ancestor_inside(*owner_node.span()) + && let Some(span) = expr.span.find_ancestor_inside( + self.tcx.hir().span_with_body(self.tcx.local_def_id_to_hir_id(fn_id)), + ) { err.multipart_suggestion( "you might have meant to return this value", @@ -1291,12 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]), )) { - let mut span = expr.span; - while expr.span.eq_ctxt(span) - && let Some(parent_callsite) = span.parent_callsite() - { - span = parent_callsite; - } + let span = expr.span.find_oldest_ancestor_in_same_ctxt(); let mut sugg = if expr.precedence().order() >= PREC_POSTFIX { vec![(span.shrink_to_hi(), ".into()".to_owned())] @@ -1901,12 +1892,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => sugg.to_string(), }; - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - msg, - sugg, - Applicability::HasPlaceholders, - ); + let span = expr.span.find_oldest_ancestor_in_same_ctxt(); + err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders); return true; } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 80fd4be53e1..476df9ae793 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -42,8 +42,9 @@ mod typeck_root_ctxt; mod upvar; mod writeback; -pub use fn_ctxt::FnCtxt; -pub use typeck_root_ctxt::TypeckRootCtxt; +pub use coercion::can_coerce; +use fn_ctxt::FnCtxt; +use typeck_root_ctxt::TypeckRootCtxt; use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; @@ -55,7 +56,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::Visitor; +use rustc_hir::intravisit::{Map, Visitor}; use rustc_hir::{HirIdMap, Node}; use rustc_hir_analysis::check::check_abi; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; @@ -435,6 +436,28 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! { diag.emit() } +pub fn lookup_method_for_diagnostic<'tcx>( + tcx: TyCtxt<'tcx>, + (def_id, hir_id): (LocalDefId, hir::HirId), +) -> Option<DefId> { + let root_ctxt = TypeckRootCtxt::new(tcx, def_id); + let param_env = tcx.param_env(def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, def_id); + let hir::Node::Expr(expr) = tcx.hir().hir_node(hir_id) else { + return None; + }; + let hir::ExprKind::MethodCall(segment, rcvr, _, _) = expr.kind else { + return None; + }; + let tables = tcx.typeck(def_id); + // The found `Self` type of the method call. + let possible_rcvr_ty = tables.node_type_opt(rcvr.hir_id)?; + fn_ctxt + .lookup_method_for_diagnostic(possible_rcvr_ty, segment, expr.span, expr, rcvr) + .ok() + .map(|method| method.def_id) +} + pub fn provide(providers: &mut Providers) { method::provide(providers); *providers = Providers { @@ -442,6 +465,7 @@ pub fn provide(providers: &mut Providers) { diagnostic_only_typeck, has_typeck_results, used_trait_imports, + lookup_method_for_diagnostic: lookup_method_for_diagnostic, ..*providers }; } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4e63600dbdf..28e17e1de36 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,7 +3,6 @@ use super::CandidateSource; use super::MethodError; use super::NoMatchData; -use crate::errors::MethodCallOnUnknownRawPointee; use crate::FnCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -430,21 +429,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_suggestion.0 { // Ambiguity was encountered during a suggestion. Just keep going. debug!("ProbeContext: encountered ambiguity in suggestion"); - } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types { + } else if bad_ty.reached_raw_pointer + && !self.tcx.features().arbitrary_self_types + && !self.tcx.sess.at_least_rust_2018() + { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) - if self.tcx.sess.at_least_rust_2018() { - self.dcx().emit_err(MethodCallOnUnknownRawPointee { span }); - } else { - self.tcx.node_span_lint( - lint::builtin::TYVAR_BEHIND_RAW_POINTER, - scope_expr_id, - span, - "type annotations needed", - |_| {}, - ); - } + self.tcx.node_span_lint( + lint::builtin::TYVAR_BEHIND_RAW_POINTER, + scope_expr_id, + span, + "type annotations needed", + |_| {}, + ); } else { // Ended up encountering a type variable when doing autoderef, // but it may not be a type variable after processing obligations @@ -455,10 +453,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.resolve_vars_if_possible(ty.value); let guar = match *ty.kind() { - ty::Infer(ty::TyVar(_)) => self - .err_ctxt() - .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true) - .emit(), + ty::Infer(ty::TyVar(_)) => { + let raw_ptr_call = + bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types; + let mut err = self.err_ctxt().emit_inference_failure_err( + self.body_id, + span, + ty.into(), + E0282, + !raw_ptr_call, + ); + if raw_ptr_call { + err.span_label(span, "cannot call a method on a raw pointer with an unknown pointee type"); + } + err.emit() + } ty::Error(guar) => guar, _ => bug!("unexpected bad final type in method autoderef"), }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a199f57aad9..754866c85c4 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -529,16 +529,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } - if let ty::RawPtr(_, _) = &rcvr_ty.kind() { - err.note( - "try using `<*const T>::as_ref()` to get a reference to the \ - type behind the pointer: https://doc.rust-lang.org/std/\ - primitive.pointer.html#method.as_ref", - ); - err.note( - "using `<*const T>::as_ref()` on a pointer which is unaligned or points \ - to invalid or uninitialized memory is undefined behavior", + + // on pointers, check if the method would exist on a reference + if let SelfSource::MethodCall(rcvr_expr) = source + && let ty::RawPtr(ty, ptr_mutbl) = *rcvr_ty.kind() + && let Ok(pick) = self.lookup_probe_for_diagnostic( + item_name, + Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl), + self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)), + ProbeScope::TraitsInScope, + None, + ) + && let ty::Ref(_, _, sugg_mutbl) = *pick.self_ty.kind() + && (sugg_mutbl.is_not() || ptr_mutbl.is_mut()) + { + let (method, method_anchor) = match sugg_mutbl { + Mutability::Not => { + let method_anchor = match ptr_mutbl { + Mutability::Not => "as_ref", + Mutability::Mut => "as_ref-1", + }; + ("as_ref", method_anchor) + } + Mutability::Mut => ("as_mut", "as_mut"), + }; + err.span_note( + tcx.def_span(pick.item.def_id), + format!("the method `{item_name}` exists on the type `{ty}`", ty = pick.self_ty), ); + let mut_str = ptr_mutbl.ptr_str(); + err.note(format!( + "you might want to use the unsafe method `<*{mut_str} T>::{method}` to get \ + an optional reference to the value behind the pointer" + )); + err.note(format!( + "read the documentation for `<*{mut_str} T>::{method}` and ensure you satisfy its \ + safety preconditions before calling it to avoid undefined behavior: \ + https://doc.rust-lang.org/std/primitive.pointer.html#method.{method_anchor}" + )); } let mut ty_span = match rcvr_ty.kind() { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index b17b312a797..94b723f694e 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -382,11 +382,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, output_def_id) } }; - if self.check_for_missing_semi(expr, &mut err) - && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id) - && let hir::ExprKind::Assign(..) = expr.kind + + // Try to suggest a semicolon if it's `A \n *B` where `B` is a place expr + let maybe_missing_semi = self.check_for_missing_semi(expr, &mut err); + + // We defer to the later error produced by `check_lhs_assignable`. + // We only downgrade this if it's the LHS, though. + if maybe_missing_semi + && let hir::Node::Expr(parent) = self.tcx.parent_hir_node(expr.hir_id) + && let hir::ExprKind::Assign(lhs, _, _) = parent.kind + && lhs.hir_id == expr.hir_id { - // We defer to the later error produced by `check_lhs_assignable`. err.downgrade_to_delayed_bug(); } diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index e493e6a0a7e..694ddd0e3e8 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -5,7 +5,6 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; @@ -27,7 +26,7 @@ use std::ops::Deref; /// `bar()` will each have their own `FnCtxt`, but they will /// share the inference context, will process obligations together, /// can access each other's local types (scoping permitted), etc. -pub struct TypeckRootCtxt<'tcx> { +pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) infcx: InferCtxt<'tcx>, pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>, @@ -78,11 +77,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = tcx - .infer_ctxt() - .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::bind(tcx, def_id)) - .build(); + let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build(); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index c987bfb9a0e..86f36eedd90 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -43,7 +43,8 @@ use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, Pro use rustc_middle::mir::FakeReadCause; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{ - self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture, + self, ClosureSizeProfileData, Ty, TyCtxt, TypeVisitableExt as _, TypeckResults, UpvarArgs, + UpvarCapture, }; use rustc_session::lint; use rustc_span::sym; @@ -191,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } }; + let args = self.resolve_vars_if_possible(args); let closure_def_id = closure_def_id.expect_local(); assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id); @@ -361,43 +363,56 @@ 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 { + if let UpvarArgs::CoroutineClosure(args) = args + && !args.references_error() + { let closure_env_region: ty::Region<'_> = ty::Region::new_bound( self.tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv }, ); + + let num_args = args + .as_coroutine_closure() + .coroutine_closure_sig() + .skip_binder() + .tupled_inputs_ty + .tuple_fields() + .len(); + let typeck_results = self.typeck_results.borrow(); + 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; + ty::analyze_coroutine_closure_captures( + typeck_results.closure_min_captures_flattened(closure_def_id), + typeck_results + .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(num_args), + |(_, parent_capture), (_, child_capture)| { + // This is subtle. See documentation on function. + let needs_ref = should_reborrow_from_env_of_parent_coroutine_closure( + parent_capture, + child_capture, + ); + + let upvar_ty = child_capture.place.ty(); + let capture = child_capture.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( + return apply_capture_kind_on_capture_ty( self.tcx, upvar_ty, capture, - Some(closure_env_region), - ) - }), + if needs_ref { Some(closure_env_region) } else { child_capture.region }, + ); + }, + ), ); let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( self.tcx, @@ -1761,6 +1776,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +/// Determines whether a child capture that is derived from a parent capture +/// should be borrowed with the lifetime of the parent coroutine-closure's env. +/// +/// There are two cases when this needs to happen: +/// +/// (1.) Are we borrowing data owned by the parent closure? We can determine if +/// that is the case by checking if the parent capture is by move, EXCEPT if we +/// apply a deref projection, which means we're reborrowing a reference that we +/// captured by move. +/// +/// ```rust +/// #![feature(async_closure)] +/// let x = &1i32; // Let's call this lifetime `'1`. +/// let c = async move || { +/// println!("{:?}", *x); +/// // Even though the inner coroutine borrows by ref, we're only capturing `*x`, +/// // not `x`, so the inner closure is allowed to reborrow the data for `'1`. +/// }; +/// ``` +/// +/// (2.) If a coroutine is mutably borrowing from a parent capture, then that +/// mutable borrow cannot live for longer than either the parent *or* the borrow +/// that we have on the original upvar. Therefore we always need to borrow the +/// child capture with the lifetime of the parent coroutine-closure's env. +/// +/// ```rust +/// #![feature(async_closure)] +/// let mut x = 1i32; +/// let c = async || { +/// x = 1; +/// // The parent borrows `x` for some `&'1 mut i32`. +/// // However, when we call `c()`, we implicitly autoref for the signature of +/// // `AsyncFnMut::async_call_mut`. Let's call that lifetime `'call`. Since +/// // the maximum that `&'call mut &'1 mut i32` can be reborrowed is `&'call mut i32`, +/// // the inner coroutine should capture w/ the lifetime of the coroutine-closure. +/// }; +/// ``` +/// +/// If either of these cases apply, then we should capture the borrow with the +/// lifetime of the parent coroutine-closure's env. Luckily, if this function is +/// not correct, then the program is not unsound, since we still borrowck and validate +/// the choices made from this function -- the only side-effect is that the user +/// may receive unnecessary borrowck errors. +fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>( + parent_capture: &ty::CapturedPlace<'tcx>, + child_capture: &ty::CapturedPlace<'tcx>, +) -> bool { + // (1.) + (!parent_capture.is_by_ref() + && !matches!( + child_capture.place.projections.get(parent_capture.place.projections.len()), + Some(Projection { kind: ProjectionKind::Deref, .. }) + )) + // (2.) + || matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::MutBorrow)) +} + /// Truncate the capture so that the place being borrowed is in accordance with RFC 1240, /// which states that it's unsafe to take a reference into a struct marked `repr(packed)`. fn restrict_repr_packed_field_ref_capture<'tcx>( diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index fdb6ab8f59b..64f52ea7ac1 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -144,6 +144,9 @@ infer_fps_items_are_distinct = fn items are distinct from fn pointers infer_fps_remove_ref = consider removing the reference infer_fps_use_ref = consider using a reference infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime + +infer_full_type_written = the full type name has been written to '{$path}' + infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement infer_label_bad = {$bad_kind -> diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 6192eaf3c3a..4593108edac 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -18,6 +18,8 @@ use crate::infer::error_reporting::{ ObligationCauseAsDiagArg, }; +use std::path::PathBuf; + pub mod note_and_explain; #[derive(Diagnostic)] @@ -47,6 +49,9 @@ pub struct AnnotationRequired<'a> { pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, + #[note(infer_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, } // Copy of `AnnotationRequired` for E0283 @@ -65,6 +70,9 @@ pub struct AmbiguousImpl<'a> { pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, + #[note(infer_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, } // Copy of `AnnotationRequired` for E0284 @@ -83,6 +91,9 @@ pub struct AmbiguousReturn<'a> { pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, + #[note(infer_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, } // Used when a better one isn't available diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 94088216c02..f14bbe74890 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -75,7 +75,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn fork_with_intercrate(&self, intercrate: bool) -> Self { Self { tcx: self.tcx, - defining_use_anchor: self.defining_use_anchor, + defining_opaque_types: self.defining_opaque_types, considering_regions: self.considering_regions, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), @@ -424,25 +424,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolyTraitRefs(ExpectedFound::new( - a_is_expected, - ty::Binder::dummy(a), - ty::Binder::dummy(b), - )), - } - } -} - -impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { - TypeTrace { - cause: cause.clone(), - values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9f70fee993d..825c3bf82fc 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -42,7 +42,7 @@ impl<'tcx> InferCtxt<'tcx> { V: TypeFoldable<TyCtxt<'tcx>>, { let (param_env, value) = value.into_parts(); - let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + let mut param_env = self.tcx.canonical_param_env_cache.get_or_insert( self.tcx, param_env, query_state, @@ -59,6 +59,8 @@ impl<'tcx> InferCtxt<'tcx> { }, ); + param_env.defining_opaque_types = self.defining_opaque_types; + Canonicalizer::canonicalize_with_base( param_env, value, @@ -440,6 +442,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { | ty::Tuple(..) | ty::Alias(..) | ty::Foreign(..) + | ty::Pat(..) | ty::Param(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) @@ -540,6 +543,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), value: (), + defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(), }; Canonicalizer::canonicalize_with_base( base, @@ -609,7 +613,15 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .max() .unwrap_or(ty::UniverseIndex::ROOT); - Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) } + assert!( + !infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types) + ); + Canonical { + max_universe, + variables: canonical_variables, + value: (base.value, out_value), + defining_opaque_types: base.defining_opaque_types, + } } /// Creates a canonical variable replacing `kind` from the input, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 9d2e065afa3..b948067e750 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -505,12 +505,9 @@ impl<'tcx> InferCtxt<'tcx> { let b = instantiate_value(self.tcx, &result_args, b); debug!(?a, ?b, "constrain opaque type"); // We use equate here instead of, for example, just registering the - // opaque type's hidden value directly, because we may be instantiating - // a query response that was canonicalized in an InferCtxt that had - // a different defining anchor. In that case, we may have inferred - // `NonLocalOpaque := LocalOpaque` but can only instantiate it in - // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq - // here allows us to try both directions (in `InferCtxt::handle_opaque_type`). + // opaque type's hidden value directly, because the hidden type may have been an inference + // variable that got constrained to the opaque type itself. In that case we want to equate + // the generic args of the opaque with the generic params of its hidden type version. obligations.extend( self.at(cause, param_env) .eq( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 0911e4f5063..29c9f08a166 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1653,7 +1653,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .report(diag); (false, Mismatch::Fixed("signature")) } - ValuePairs::PolyTraitRefs(_) => (false, Mismatch::Fixed("trait")), + ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")), ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => { (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id))) } @@ -1969,8 +1969,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id()); } - if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values - && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() + if let Some(ValuePairs::TraitRefs(exp_found)) = values + && let ty::Closure(def_id, _) = exp_found.expected.self_ty().kind() && let Some(def_id) = def_id.as_local() && terr.involves_regions() { @@ -2188,7 +2188,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Aliases(exp_found) => self.expected_found_str(exp_found), infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), - infer::PolyTraitRefs(exp_found) => { + infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_trait_sugared(), found: exp_found.found.print_trait_sugared(), 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 f89ed256a08..3b5658ed0ee 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 @@ -18,13 +18,15 @@ use rustc_middle::infer::unify_key::{ }; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; -use rustc_middle::ty::{self, InferConst}; -use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; -use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; +use rustc_middle::ty::{ + self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Ty, TyCtxt, + TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, +}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use std::borrow::Cow; use std::iter; +use std::path::PathBuf; pub enum TypeAnnotationNeeded { /// ```compile_fail,E0282 @@ -153,6 +155,29 @@ impl UnderspecifiedArgKind { } } +struct ClosureEraser<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind() { + ty::Closure(_, args) => { + let closure_sig = args.as_closure().sig(); + Ty::new_fn_ptr( + self.tcx, + self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal), + ) + } + _ => ty.super_fold_with(self), + } + } +} + fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { let mut printer = FmtPrinter::new(infcx.tcx, ns); let ty_getter = move |ty_vid| { @@ -209,6 +234,10 @@ fn ty_to_string<'tcx>( ) -> String { let mut printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); + // We use `fn` ptr syntax for closures, but this only works when the closure + // does not capture anything. + let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx }); + match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. @@ -223,11 +252,6 @@ fn ty_to_string<'tcx>( "Vec<_>".to_string() } _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(), - // FIXME: The same thing for closures, but this only works when the closure - // does not capture anything. - // - // We do have to hide the `extern "rust-call"` ABI in that case though, - // which is too much of a bother for now. _ => { ty.print(&mut printer).unwrap(); printer.into_buffer() @@ -387,6 +411,8 @@ impl<'tcx> InferCtxt<'tcx> { infer_subdiags, multi_suggestions, bad_label, + was_written: None, + path: Default::default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { span, @@ -396,6 +422,8 @@ impl<'tcx> InferCtxt<'tcx> { infer_subdiags, multi_suggestions, bad_label, + was_written: None, + path: Default::default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { span, @@ -405,6 +433,8 @@ impl<'tcx> InferCtxt<'tcx> { infer_subdiags, multi_suggestions, bad_label, + was_written: None, + path: Default::default(), }), } } @@ -442,7 +472,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; - let (source_kind, name) = kind.ty_localized_msg(self); + let (source_kind, name, path) = kind.ty_localized_msg(self); let failure_span = if should_label_span && !failure_span.overlaps(span) { Some(failure_span) } else { @@ -518,7 +548,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), GenericArgKind::Type(_) => self .next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, + span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, }) .into(), @@ -526,7 +556,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .next_const_var( arg.ty(), ConstVariableOrigin { - span: rustc_span::DUMMY_SP, + span: DUMMY_SP, kind: ConstVariableOriginKind::MiscVariable, }, ) @@ -547,7 +577,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => { let placeholder = Some(self.next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, + span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, })); if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) { @@ -584,7 +614,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { let placeholder = Some(self.next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, + span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, })); if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) { @@ -606,6 +636,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, + was_written: path.as_ref().map(|_| ()), + path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { span, @@ -615,6 +647,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, + was_written: path.as_ref().map(|_| ()), + path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { span, @@ -624,6 +658,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, + was_written: path.as_ref().map(|_| ()), + path: path.unwrap_or_default(), }), } } @@ -688,22 +724,23 @@ impl<'tcx> InferSource<'tcx> { } impl<'tcx> InferSourceKind<'tcx> { - fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) { + fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Option<PathBuf>) { + let mut path = None; match *self { InferSourceKind::LetBinding { ty, .. } | InferSourceKind::ClosureArg { ty, .. } | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { - ("closure", closure_as_fn_str(infcx, ty)) + ("closure", closure_as_fn_str(infcx, ty), path) } else if !ty.is_ty_or_numeric_infer() { - ("normal", ty_to_string(infcx, ty, None)) + ("normal", infcx.tcx.short_ty_string(ty, &mut path), path) } else { - ("other", String::new()) + ("other", String::new(), path) } } // FIXME: We should be able to add some additional info here. InferSourceKind::GenericArg { .. } - | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()), + | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new(), path), } } } 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 98719e240bd..01e75d59f4d 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 @@ -195,13 +195,13 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { value_pairs: &ValuePairs<'tcx>, ) -> Option<Diag<'tcx>> { let (expected_args, found_args, trait_def_id) = match value_pairs { - ValuePairs::PolyTraitRefs(ExpectedFound { expected, found }) - if expected.def_id() == found.def_id() => + ValuePairs::TraitRefs(ExpectedFound { expected, found }) + if expected.def_id == found.def_id => { // It's possible that the placeholders come from a binder // outside of this value pair. Use `no_bound_vars` as a // simple heuristic for that. - (expected.no_bound_vars()?.args, found.no_bound_vars()?.args, expected.def_id()) + (expected.args, found.args, expected.def_id) } _ => return None, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 9a05fb1c30f..bf470bb1e3f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -15,7 +15,7 @@ use rustc_middle::traits::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, @@ -599,7 +599,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, span: Span, hir: hir::Node<'_>, - exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>, + exp_found: &ty::error::ExpectedFound<ty::TraitRef<'tcx>>, diag: &mut Diag<'_>, ) { // 0. Extract fn_decl from hir @@ -614,10 +614,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // 1. Get the args of the closure. // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1]. - let Some(expected) = exp_found.expected.skip_binder().args.get(1) else { + let Some(expected) = exp_found.expected.args.get(1) else { return; }; - let Some(found) = exp_found.found.skip_binder().args.get(1) else { + let Some(found) = exp_found.found.args.get(1) else { return; }; let expected = expected.unpack(); @@ -763,8 +763,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span); self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? } else { - last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) + self.tcx + .sess + .source_map() + .span_extend_while_whitespace(last_expr.span) + .shrink_to_hi() + .with_hi(last_stmt.span.hi()) }; + Some((span, needs_box)) } @@ -867,10 +873,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!(" {ident} ") }; let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); - ( - sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), - sugg, - ) + (sm.span_extend_while_whitespace(left_span), sugg) }; Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6e5ed0a31cb..f2fd50a47d5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -34,7 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::{select, DefiningAnchor}; +use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -243,18 +243,8 @@ impl<'tcx> InferCtxtInner<'tcx> { pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - /// The `DefId` of the item in whose context we are performing inference or typeck. - /// It is used to check whether an opaque type use is a defining use. - /// - /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up - /// the obligation. This frequently happens for - /// short lived InferCtxt within queries. The opaque type obligations are forwarded - /// to the outside until the end up in an `InferCtxt` for typeck or borrowck. - /// - /// Its default value is `DefiningAnchor::Bind(&[])`, which means no opaque types may be defined. - /// This way it is easier to catch errors that - /// might come up during inference or typeck. - pub defining_use_anchor: DefiningAnchor<'tcx>, + /// The `DefIds` of the opaque types that may have their hidden types constrained. + defining_opaque_types: &'tcx ty::List<LocalDefId>, /// Whether this inference context should care about region obligations in /// the root universe. Most notably, this is used during hir typeck as region @@ -401,6 +391,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> { self.probe_const_var(vid).ok() } + + fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { + self.defining_opaque_types + } } /// See the `error_reporting` module for more details. @@ -409,7 +403,7 @@ pub enum ValuePairs<'tcx> { Regions(ExpectedFound<ty::Region<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>), Aliases(ExpectedFound<ty::AliasTy<'tcx>>), - PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), + TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>), ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>), ExistentialProjection(ExpectedFound<ty::PolyExistentialProjection<'tcx>>), @@ -615,7 +609,7 @@ impl fmt::Display for FixupError { /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_use_anchor: DefiningAnchor<'tcx>, + defining_opaque_types: &'tcx ty::List<LocalDefId>, considering_regions: bool, skip_leak_check: bool, /// Whether we are in coherence mode. @@ -630,7 +624,7 @@ impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, - defining_use_anchor: DefiningAnchor::Bind(ty::List::empty()), + defining_opaque_types: ty::List::empty(), considering_regions: true, skip_leak_check: false, intercrate: false, @@ -646,8 +640,16 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// It is only meant to be called in two places, for typeck /// (via `Inherited::build`) and for the inference context used /// in mir borrowck. - pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor<'tcx>) -> Self { - self.defining_use_anchor = defining_use_anchor; + pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self { + self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor); + self + } + + pub fn with_defining_opaque_types( + mut self, + defining_opaque_types: &'tcx ty::List<LocalDefId>, + ) -> Self { + self.defining_opaque_types = defining_opaque_types; self } @@ -679,14 +681,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). pub fn build_with_canonical<T>( - &mut self, + self, span: Span, canonical: &Canonical<'tcx, T>, ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) where T: TypeFoldable<TyCtxt<'tcx>>, { - let infcx = self.build(); + let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build(); let (value, args) = infcx.instantiate_canonical(span, canonical); (infcx, value, args) } @@ -694,7 +696,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { pub fn build(&mut self) -> InferCtxt<'tcx> { let InferCtxtBuilder { tcx, - defining_use_anchor, + defining_opaque_types, considering_regions, skip_leak_check, intercrate, @@ -702,7 +704,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } = *self; InferCtxt { tcx, - defining_use_anchor, + defining_opaque_types, considering_regions, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), @@ -1230,6 +1232,12 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow().opaque_type_storage.opaque_types.clone() } + #[inline(always)] + pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool { + let Some(id) = id.into().as_local() else { return false }; + self.defining_opaque_types.contains(&id) + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } @@ -1874,15 +1882,15 @@ impl<'tcx> TypeTrace<'tcx> { } } - pub fn poly_trait_refs( + pub fn trait_refs( cause: &ObligationCause<'tcx>, a_is_expected: bool, - a: ty::PolyTraitRef<'tcx>, - b: ty::PolyTraitRef<'tcx>, + a: ty::TraitRef<'tcx>, + b: ty::TraitRef<'tcx>, ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 01430e830e5..d32515425c4 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -4,11 +4,10 @@ use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{InferCtxt, InferOk}; use crate::traits::{self, PredicateObligation}; use hir::def_id::{DefId, LocalDefId}; -use hir::OpaqueTyOrigin; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; -use rustc_middle::traits::{DefiningAnchor, ObligationCause}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::GenericArgKind; @@ -54,16 +53,13 @@ impl<'tcx> InferCtxt<'tcx> { } let mut obligations = vec![]; - let replace_opaque_type = |def_id: DefId| { - def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some()) - }; let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, ct_op: |ct| ct, ty_op: |ty| match *ty.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) - if replace_opaque_type(def_id) && !ty.has_escaping_bound_vars() => + if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() => { let def_span = self.tcx.def_span(def_id); let span = if span.contains(def_span) { def_span } else { span }; @@ -106,56 +102,52 @@ impl<'tcx> InferCtxt<'tcx> { b, )); } - match self.defining_use_anchor { - DefiningAnchor::Bind(_) => { - // Check that this is `impl Trait` type is - // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is - // always true during the first phase of - // type-check, but not always true later on during - // NLL. Once we support named opaque types more fully, - // this same scenario will be able to arise during all phases. - // - // Here is an example using type alias `impl Trait` - // that indicates the distinction we are checking for: - // - // ```rust - // mod a { - // pub type Foo = impl Iterator; - // pub fn make_foo() -> Foo { .. } - // } - // - // mod b { - // fn foo() -> a::Foo { a::make_foo() } - // } - // ``` - // - // Here, the return type of `foo` references an - // `Opaque` indeed, but not one whose value is - // presently being inferred. You can get into a - // similar situation with closure return types - // today: - // - // ```rust - // fn foo() -> impl Iterator { .. } - // fn bar() { - // let x = || foo(); // returns the Opaque assoc with `foo` - // } - // ``` - if self.opaque_type_origin(def_id).is_none() { - return None; - } - } - DefiningAnchor::Bubble => {} + // Check that this is `impl Trait` type is + // declared by `parent_def_id` -- i.e., one whose + // value we are inferring. At present, this is + // always true during the first phase of + // type-check, but not always true later on during + // NLL. Once we support named opaque types more fully, + // this same scenario will be able to arise during all phases. + // + // Here is an example using type alias `impl Trait` + // that indicates the distinction we are checking for: + // + // ```rust + // mod a { + // pub type Foo = impl Iterator; + // pub fn make_foo() -> Foo { .. } + // } + // + // mod b { + // fn foo() -> a::Foo { a::make_foo() } + // } + // ``` + // + // Here, the return type of `foo` references an + // `Opaque` indeed, but not one whose value is + // presently being inferred. You can get into a + // similar situation with closure return types + // today: + // + // ```rust + // fn foo() -> impl Iterator { .. } + // fn bar() { + // let x = || foo(); // returns the Opaque assoc with `foo` + // } + // ``` + if !self.can_define_opaque_ty(def_id) { + return None; } + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { // We could accept this, but there are various ways to handle this situation, and we don't // want to make a decision on it right now. Likely this case is so super rare anyway, that // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias { .. }) = - b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id)) + if self.can_define_opaque_ty(b_def_id) + && self.tcx.is_type_alias_impl_trait(b_def_id) { self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag { span: cause.span, @@ -367,20 +359,6 @@ impl<'tcx> InferCtxt<'tcx> { op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions), }); } - - /// Returns the origin of the opaque type `def_id` if we're currently - /// in its defining scope. - #[instrument(skip(self), level = "trace", ret)] - pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> { - let defined_opaque_types = match self.defining_use_anchor { - DefiningAnchor::Bubble => return None, - DefiningAnchor::Bind(bind) => bind, - }; - - let origin = self.tcx.opaque_type_origin(def_id); - - defined_opaque_types.contains(&def_id).then_some(origin) - } } /// Visitor that requires that (almost) all regions in the type visited outlive diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 7dd1ec32542..6bab3ad6ba3 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -93,6 +93,7 @@ fn compute_components<'tcx>( } } + ty::Pat(element, _) | ty::Array(element, _) => { // Don't look into the len const as it doesn't affect regions compute_components(tcx, element, out, visited); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 1f92cc4d763..91cef02c7d1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -170,7 +170,9 @@ fn configure_and_expand( let mut old_path = OsString::new(); if cfg!(windows) { old_path = env::var_os("PATH").unwrap_or(old_path); - let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs(); + let mut new_path = Vec::from_iter( + sess.host_filesearch(PathKind::All).search_paths().map(|p| p.dir.clone()), + ); for path in env::split_paths(&old_path) { if !new_path.contains(&path) { new_path.push(path); @@ -686,18 +688,15 @@ pub fn create_global_ctxt<'tcx>( }) } -/// Runs the type-checking, region checking and other miscellaneous analysis -/// passes on the crate. -fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { +/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. +/// This function never fails. +fn run_required_analyses(tcx: TyCtxt<'_>) { if tcx.sess.opts.unstable_opts.hir_stats { rustc_passes::hir_stats::print_hir_stats(tcx); } - #[cfg(debug_assertions)] rustc_passes::hir_id_validator::check_crate(tcx); - let sess = tcx.sess; - sess.time("misc_checking_1", || { parallel!( { @@ -733,10 +732,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } ); }); - - // passes are timed inside typeck - rustc_hir_analysis::check_crate(tcx)?; - + rustc_hir_analysis::check_crate(tcx); sess.time("MIR_borrow_checking", || { tcx.hir().par_body_owners(|def_id| { // Run unsafety check because it's responsible for stealing and @@ -745,7 +741,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { tcx.ensure().mir_borrowck(def_id) }); }); - sess.time("MIR_effect_checking", || { for def_id in tcx.hir().body_owners() { tcx.ensure().has_ffi_unwind_calls(def_id); @@ -761,16 +756,22 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } } }); - tcx.hir().par_body_owners(|def_id| { if tcx.is_coroutine(def_id.to_def_id()) { tcx.ensure().mir_coroutine_witnesses(def_id); tcx.ensure().check_coroutine_obligations(def_id); } }); - sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx)); +} + +/// Runs the type-checking, region checking and other miscellaneous analysis +/// passes on the crate. +fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { + run_required_analyses(tcx); + + let sess = tcx.sess; // Avoid overwhelming user with errors if borrow checking failed. // I'm not sure how helpful this is, to be honest, but it avoids a diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index b9025917d13..d2fb65b5d4f 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -846,6 +846,7 @@ fn test_unstable_options_tracking_hash() { tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, NonZero::new(1)); tracked!(tune_cpu, Some(String::from("abc"))); + tracked!(ub_checks, Some(false)); tracked!(uninit_const_chunk_threshold, 123); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 797c0df4d73..82b90e1660a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -299,6 +299,9 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` lint_improper_ctypes_opaque = opaque types have no C equivalent +lint_improper_ctypes_pat_help = consider using the base type instead + +lint_improper_ctypes_pat_reason = pattern types have no C equivalent lint_improper_ctypes_slice_help = consider using a raw pointer instead lint_improper_ctypes_slice_reason = slices have no C equivalent diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 70c7aff3f20..8b974a461d4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1337,8 +1337,9 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { } declare_lint! { - /// The `unreachable_pub` lint triggers for `pub` items not reachable from - /// the crate root. + /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that + /// means neither directly accessible, nor reexported, nor leaked through things like return + /// types. /// /// ### Example /// diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index e2010ab3830..b2403836397 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -105,7 +105,7 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di BuiltinLintDiag::RedundantImport(spans, ident) => { for (span, is_imported) in spans { let introduced = if is_imported { "imported" } else { "defined" }; - let span_msg = if span.is_dummy() { "by prelude" } else { "here" }; + let span_msg = if span.is_dummy() { "by the extern prelude" } else { "here" }; diag.span_label( span, format!("the item `{ident}` is already {introduced} {span_msg}"), @@ -215,10 +215,7 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di if let Some(deletion_span) = deletion_span { let msg = "elide the single-use lifetime"; let (use_span, replace_lt) = if elide { - let use_span = sess - .source_map() - .span_extend_while(use_span, char::is_whitespace) - .unwrap_or(use_span); + let use_span = sess.source_map().span_extend_while_whitespace(use_span); (use_span, String::new()) } else { (use_span, "'_".to_owned()) diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 1e9c60a540d..870e198d70a 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -157,6 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { | TyKind::Never | TyKind::Tup(_) | TyKind::Path(_) + | TyKind::Pat(..) | TyKind::AnonAdt(_) | TyKind::OpaqueDef(_, _, _) | TyKind::Typeof(_) diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index cf825be7a55..ec7954536be 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -20,7 +20,7 @@ declare_lint! { /// This functionality was removed in #97346, but then rolled back in #99860 /// because it caused regressions. /// - /// We plan on reintroducing this as a hard error, but in the mean time, + /// We plan on reintroducing this as a hard error, but in the meantime, /// this lint serves to warn and suggest fixes for any use-cases which rely /// on this behavior. /// diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 534eb60eeb0..e982842f536 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1379,6 +1379,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_char_help), }, + ty::Pat(..) => FfiUnsafe { + ty, + reason: fluent::lint_improper_ctypes_pat_reason, + help: Some(fluent::lint_improper_ctypes_pat_help), + }, + ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 111a4fdcea1..503caa35358 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1074,10 +1074,14 @@ impl UnusedParens { // Otherwise proceed with linting. _ => {} } - let spans = inner - .span - .find_ancestor_inside(value.span) - .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))); + let spans = if !value.span.from_expansion() { + inner + .span + .find_ancestor_inside(value.span) + .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))) + } else { + None + }; self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false); } } @@ -1233,11 +1237,13 @@ impl EarlyLintPass for UnusedParens { if self.with_self_ty_parens && b.generic_params.len() > 0 => {} ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} _ => { - let spans = r - .span - .find_ancestor_inside(ty.span) - .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))); - + let spans = if !ty.span.from_expansion() { + r.span + .find_ancestor_inside(ty.span) + .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) + } else { + None + }; self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 30522628f46..2713690f812 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -79,6 +79,7 @@ declare_lint_pass! { PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + REDUNDANT_LIFETIMES, REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE, RENAMED_AND_REMOVED_LINTS, @@ -1708,6 +1709,33 @@ declare_lint! { } declare_lint! { + /// The `redundant_lifetimes` lint detects lifetime parameters that are + /// redundant because they are equal to another named lifetime. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[deny(redundant_lifetimes)] + /// + /// // `'a = 'static`, so all usages of `'a` can be replaced with `'static` + /// pub fn bar<'a: 'static>() {} + /// + /// // `'a = 'b`, so all usages of `'b` can be replaced with `'a` + /// pub fn bar<'a: 'b, 'b: 'a>() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused lifetime parameters may signal a mistake or unfinished code. + /// Consider removing the parameter. + pub REDUNDANT_LIFETIMES, + Allow, + "detects lifetime parameters that are redundant because they are equal to some other named lifetime" +} + +declare_lint! { /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an /// inference variable. /// @@ -4311,7 +4339,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// # #![feature(type_privacy_lints)] /// # #![allow(unused)] /// #![deny(unnameable_types)] /// mod m { @@ -4328,10 +4355,14 @@ declare_lint! { /// /// It is often expected that if you can obtain an object of type `T`, then /// you can name the type `T` as well, this lint attempts to enforce this rule. + /// The recommended action is to either reexport the type properly to make it nameable, + /// or document that users are not supposed to be able to name it for one reason or another. + /// + /// Besides types, this lint applies to traits because traits can also leak through signatures, + /// and you may obtain objects of their `dyn Trait` or `impl Trait` types. pub UNNAMEABLE_TYPES, Allow, "effective visibility of a type is larger than the area in which it can be named", - @feature_gate = sym::type_privacy_lints; } declare_lint! { diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index e2c0ec90c7c..66ca94d1d9c 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -112,28 +112,10 @@ fn main() { restore_library_path(); - let target = env::var("TARGET").expect("TARGET was not set"); let llvm_config = - tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| { - if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) { - let to_test = dir - .parent() - .unwrap() - .parent() - .unwrap() - .join(&target) - .join("llvm/bin/llvm-config"); - if Command::new(&to_test).output().is_ok() { - return Some(to_test); - } - } - None - }); + PathBuf::from(tracked_env_var_os("LLVM_CONFIG").expect("LLVM_CONFIG was not set")); - if let Some(llvm_config) = &llvm_config { - println!("cargo:rerun-if-changed={}", llvm_config.display()); - } - let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config")); + println!("cargo:rerun-if-changed={}", llvm_config.display()); // Test whether we're cross-compiling LLVM. This is a pretty rare case // currently where we're producing an LLVM for a different platform than diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 40723ff9f5e..64e6c18092f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -147,7 +147,7 @@ LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) { Expected<StringRef> NameOrErr = Child->getName(); if (!NameOrErr) { // rustc_codegen_llvm currently doesn't use this error string, but it might be - // useful in the future, and in the mean time this tells LLVM that the + // useful in the future, and in the meantime this tells LLVM that the // error was not ignored and that it shouldn't abort the process. LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str()); return nullptr; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 8ec1f5a99e7..6e11fd629e4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -817,7 +817,7 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } -extern "C" void LLVMRustAddModuleFlag( +extern "C" void LLVMRustAddModuleFlagU32( LLVMModuleRef M, Module::ModFlagBehavior MergeBehavior, const char *Name, @@ -825,6 +825,16 @@ extern "C" void LLVMRustAddModuleFlag( unwrap(M)->addModuleFlag(MergeBehavior, Name, Value); } +extern "C" void LLVMRustAddModuleFlagString( + LLVMModuleRef M, + Module::ModFlagBehavior MergeBehavior, + const char *Name, + const char *Value, + size_t ValueLen) { + unwrap(M)->addModuleFlag(MergeBehavior, Name, + MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen))); +} + extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, size_t Len) { return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr; @@ -1514,18 +1524,26 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundles, + OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap<FunctionType>(Ty); + + // FIXME: Is there a way around this? + SmallVector<OperandBundleDef> OpBundles; + OpBundles.reserve(NumOpBundles); + for (unsigned i = 0; i < NumOpBundles; ++i) { + OpBundles.push_back(*OpBundlesIndirect[i]); + } + return wrap(unwrap(B)->CreateCall( FTy, Callee, ArrayRef<Value*>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles))); + ArrayRef<OperandBundleDef>(OpBundles))); } extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { - return wrap(llvm::Intrinsic::getDeclaration(unwrap(M), - (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment)); + return wrap(llvm::Intrinsic::getDeclaration( + unwrap(M), llvm::Intrinsic::instrprof_increment)); } extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, @@ -1560,13 +1578,21 @@ extern "C" LLVMValueRef LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, - OperandBundleDef **OpBundles, unsigned NumOpBundles, + OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap<FunctionType>(Ty); + + // FIXME: Is there a way around this? + SmallVector<OperandBundleDef> OpBundles; + OpBundles.reserve(NumOpBundles); + for (unsigned i = 0; i < NumOpBundles; ++i) { + OpBundles.push_back(*OpBundlesIndirect[i]); + } + return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), ArrayRef<Value*>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles), + ArrayRef<OperandBundleDef>(OpBundles), Name)); } @@ -1575,7 +1601,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundles, unsigned NumOpBundles, + OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap<FunctionType>(Ty); @@ -1587,11 +1613,18 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i])); } + // FIXME: Is there a way around this? + SmallVector<OperandBundleDef> OpBundles; + OpBundles.reserve(NumOpBundles); + for (unsigned i = 0; i < NumOpBundles; ++i) { + OpBundles.push_back(*OpBundlesIndirect[i]); + } + return wrap(unwrap(B)->CreateCallBr( FTy, Callee, unwrap(DefaultDest), ArrayRef<BasicBlock*>(IndirectDestsUnwrapped), ArrayRef<Value*>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles), + ArrayRef<OperandBundleDef>(OpBundles), Name)); } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index baa2e1ff602..58760be921a 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -19,12 +19,7 @@ use crate::errors; use std::path::PathBuf; -pub fn find_native_static_library( - name: &str, - verbatim: bool, - search_paths: &[PathBuf], - sess: &Session, -) -> PathBuf { +pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf { let formats = if verbatim { vec![("".into(), "".into())] } else { @@ -35,9 +30,9 @@ pub fn find_native_static_library( if os == unix { vec![os] } else { vec![os, unix] } }; - for path in search_paths { + for path in sess.target_filesearch(PathKind::Native).search_paths() { for (prefix, suffix) in &formats { - let test = path.join(format!("{prefix}{name}{suffix}")); + let test = path.dir.join(format!("{prefix}{name}{suffix}")); if test.exists() { return test; } @@ -60,8 +55,7 @@ fn find_bundled_library( && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true)) { let verbatim = verbatim.unwrap_or(false); - let search_paths = &sess.target_filesearch(PathKind::Native).search_path_dirs(); - return find_native_static_library(name.as_str(), verbatim, search_paths, sess) + return find_native_static_library(name.as_str(), verbatim, sess) .file_name() .and_then(|s| s.to_str()) .map(Symbol::intern); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index b69a295f010..2935d5b8f63 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_session::cstore::{CrateStore, ExternCrate}; use rustc_session::{Session, StableCrateId}; -use rustc_span::hygiene::{ExpnHash, ExpnId}; +use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; @@ -378,6 +378,7 @@ provide! { tcx, def_id, other, cdata, } pub(in crate::rmeta) fn provide(providers: &mut Providers) { + provide_cstore_hooks(providers); // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about @@ -649,26 +650,27 @@ impl CrateStore for CStore { fn def_path_hash(&self, def: DefId) -> DefPathHash { self.get_crate_data(def.krate).def_path_hash(def.index) } +} - fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId { - let def_index = self.get_crate_data(cnum).def_path_hash_to_def_index(hash); +fn provide_cstore_hooks(providers: &mut Providers) { + providers.hooks.def_path_hash_to_def_id_extern = |tcx, hash, stable_crate_id| { + // If this is a DefPathHash from an upstream crate, let the CrateStore map + // it to a DefId. + let cstore = CStore::from_tcx(tcx.tcx); + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash); DefId { krate: cnum, index: def_index } - } - - fn expn_hash_to_expn_id( - &self, - sess: &Session, - cnum: CrateNum, - index_guess: u32, - hash: ExpnHash, - ) -> ExpnId { - self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash) - } + }; - fn import_source_files(&self, sess: &Session, cnum: CrateNum) { - let cdata = self.get_crate_data(cnum); + providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| { + let cstore = CStore::from_tcx(tcx.tcx); + cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx.sess, index_guess, hash) + }; + providers.hooks.import_source_files = |tcx, cnum| { + let cstore = CStore::from_tcx(tcx.tcx); + let cdata = cstore.get_crate_data(cnum); for file_index in 0..cdata.root.source_map.size() { - cdata.imported_source_file(file_index as u32, sess); + cdata.imported_source_file(file_index as u32, tcx.sess); } - } + }; } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7b10ea53524..c057f7e921e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2009,7 +2009,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); let trait_def = tcx.trait_def(trait_ref.def_id); - if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() { + if let Ok(mut an) = trait_def.ancestors(tcx, def_id) { if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { self.tables.impl_parent.set_some(def_id.index, parent.into()); } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 9e8ee92b5d9..6c3ff237d59 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -10,7 +10,6 @@ derivative = "2.2.0" either = "1.5.0" field-offset = "0.3.5" gsgdt = "0.1.2" -measureme = "11" polonius-engine = "0.13.0" rustc-rayon = { version = "0.5.0", optional = true } rustc-rayon-core = { version = "0.5.0", optional = true } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index bd11b3eb04c..13719268737 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -90,6 +90,7 @@ macro_rules! arena_types { [decode] attribute: rustc_ast::Attribute, [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>, + [] pats: rustc_middle::ty::PatternKind<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index aa2cddad093..f7ce15d0a8d 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -6,8 +6,10 @@ use crate::mir; use crate::query::TyCtxtAt; use crate::ty::{Ty, TyCtxt}; -use rustc_span::def_id::LocalDefId; -use rustc_span::DUMMY_SP; +use rustc_hir::def_id::{DefId, DefPathHash}; +use rustc_session::StableCrateId; +use rustc_span::def_id::{CrateNum, LocalDefId}; +use rustc_span::{ExpnHash, ExpnId, DUMMY_SP}; macro_rules! declare_hooks { ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => { @@ -16,7 +18,6 @@ macro_rules! declare_hooks { $( $(#[$attr])* #[inline(always)] - #[must_use] pub fn $name(self, $($arg: $K,)*) -> $V { self.at(DUMMY_SP).$name($($arg,)*) @@ -28,7 +29,6 @@ macro_rules! declare_hooks { $( $(#[$attr])* #[inline(always)] - #[must_use] #[instrument(level = "debug", skip(self), ret)] pub fn $name(self, $($arg: $K,)*) -> $V { @@ -83,4 +83,23 @@ declare_hooks! { /// You do not want to call this yourself, instead use the cached version /// via `mir_built` hook build_mir(key: LocalDefId) -> mir::Body<'tcx>; + + + /// Imports all `SourceFile`s from the given crate into the current session. + /// This normally happens automatically when we decode a `Span` from + /// that crate's metadata - however, the incr comp cache needs + /// to trigger this manually when decoding a foreign `Span` + hook import_source_files(key: CrateNum) -> (); + + hook expn_hash_to_expn_id( + cnum: CrateNum, + index_guess: u32, + hash: ExpnHash + ) -> ExpnId; + + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + /// Will fetch a DefId from a DefPathHash for a foreign crate. + hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId; } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index acea89e4aab..62d7b7c28d1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -153,11 +153,6 @@ pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>, pub certainty: Certainty, - /// List of opaque types which we tried to compare to another type. - /// Inside the query we don't know yet whether the opaque type actually - /// should get its hidden type inferred. So we bubble the opaque type - /// and the type it was compared against upwards and let the query caller - /// handle it. pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, pub value: R, } @@ -330,6 +325,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), value: key, + defining_opaque_types: ty::List::empty(), }; } @@ -340,6 +336,14 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { match self.map.borrow().entry(key) { Entry::Occupied(e) => { let (canonical, var_values) = e.get(); + if cfg!(debug_assertions) { + let mut state = state.clone(); + let rerun_canonical = canonicalize_op(tcx, key, &mut state); + assert_eq!(rerun_canonical, *canonical); + let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state; + assert_eq!(universe_map.len(), 1); + assert_eq!(**var_values, *rerun_var_values); + } state.var_values.extend_from_slice(var_values); *canonical } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 3ecd5b9cd34..1086d647721 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -1,5 +1,5 @@ use crate::mir::traversal::Postorder; -use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK}; +use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph; @@ -141,42 +141,30 @@ impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> { impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> { type Node = BasicBlock; -} -impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> { #[inline] fn num_nodes(&self) -> usize { self.basic_blocks.len() } } -impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> { +impl<'tcx> graph::StartNode for BasicBlocks<'tcx> { #[inline] fn start_node(&self) -> Self::Node { START_BLOCK } } -impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> { +impl<'tcx> graph::Successors for BasicBlocks<'tcx> { #[inline] - fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter { + fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { self.basic_blocks[node].terminator().successors() } } -impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> { - type Item = BasicBlock; - type Iter = Successors<'b>; -} - -impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> { - type Item = BasicBlock; - type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>; -} - -impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { +impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> { #[inline] - fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { + fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { self.predecessors()[node].iter().copied() } } diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index 299b50525cb..809d4cdce8d 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -5,7 +5,7 @@ use std::io::{self, Write}; pub struct GraphvizWriter< 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, + G: graph::DirectedGraph + graph::Successors + graph::StartNode, NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, > { @@ -19,7 +19,7 @@ pub struct GraphvizWriter< impl< 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, + G: graph::DirectedGraph + graph::Successors + graph::StartNode, NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ad166620bcc..601bfc770f4 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -30,7 +30,6 @@ pub use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Encodable}; @@ -687,57 +686,6 @@ impl<'tcx> Body<'tcx> { self.injection_phase.is_some() } - /// Finds which basic blocks are actually reachable for a specific - /// monomorphization of this body. - /// - /// This is allowed to have false positives; just because this says a block - /// is reachable doesn't mean that's necessarily true. It's thus always - /// legal for this to return a filled set. - /// - /// Regardless, the [`BitSet::domain_size`] of the returned set will always - /// exactly match the number of blocks in the body so that `contains` - /// checks can be done without worrying about panicking. - /// - /// This is mostly useful because it lets us skip lowering the `false` side - /// of `if <T as Trait>::CONST`, as well as `intrinsics::debug_assertions`. - pub fn reachable_blocks_in_mono( - &self, - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - ) -> BitSet<BasicBlock> { - let mut set = BitSet::new_empty(self.basic_blocks.len()); - self.reachable_blocks_in_mono_from(tcx, instance, &mut set, START_BLOCK); - set - } - - fn reachable_blocks_in_mono_from( - &self, - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - set: &mut BitSet<BasicBlock>, - bb: BasicBlock, - ) { - if !set.insert(bb) { - return; - } - - let data = &self.basic_blocks[bb]; - - if let Some((bits, targets)) = Self::try_const_mono_switchint(tcx, instance, data) { - let target = targets.target_for_value(bits); - ensure_sufficient_stack(|| { - self.reachable_blocks_in_mono_from(tcx, instance, set, target) - }); - return; - } - - for target in data.terminator().successors() { - ensure_sufficient_stack(|| { - self.reachable_blocks_in_mono_from(tcx, instance, set, target) - }); - } - } - /// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the /// dimscriminant in monomorphization, we return the discriminant bits and the /// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator. @@ -777,8 +725,8 @@ impl<'tcx> Body<'tcx> { // _1 = const _ // SwitchInt(_1) // - // And MIR for if intrinsics::debug_assertions() looks like this: - // _1 = cfg!(debug_assertions) + // And MIR for if intrinsics::ub_checks() looks like this: + // _1 = UbChecks() // SwitchInt(_1) // // So we're going to try to recognize this pattern. @@ -799,9 +747,7 @@ impl<'tcx> Body<'tcx> { } match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, _) => { - Some((tcx.sess.opts.debug_assertions as u128, targets)) - } + Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), Rvalue::Use(Operand::Constant(constant)) => { let bits = eval_mono_const(constant); Some((bits, targets)) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 41df2e3b587..15bd5c08965 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -978,12 +978,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { CopyForDeref(ref place) => write!(fmt, "deref_copy {place:#?}"), AddressOf(mutability, ref place) => { - let kind_str = match mutability { - Mutability::Mut => "mut", - Mutability::Not => "const", - }; - - write!(fmt, "&raw {kind_str} {place:?}") + write!(fmt, "&raw {mut_str} {place:?}", mut_str = mutability.ptr_str()) } Aggregate(ref kind, ref places) => { diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index f116347cc2b..58a27c1f9ef 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -85,6 +85,12 @@ impl SwitchTargets { self.values.push(value); self.targets.insert(self.targets.len() - 1, bb); } + + /// Returns true if all targets (including the fallback target) are distinct. + #[inline] + pub fn is_distinct(&self) -> bool { + self.targets.iter().collect::<FxHashSet<_>>().len() == self.targets.len() + } } pub struct SwitchTargetsIter<'a> { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 0a938bcd315..245e9096bad 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -245,7 +245,7 @@ pub fn reachable<'a, 'tcx>( /// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`. pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> { let mut iter = preorder(body); - iter.by_ref().for_each(drop); + while let Some(_) = iter.next() {} iter.visited } @@ -279,3 +279,97 @@ pub fn reverse_postorder<'a, 'tcx>( { body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb])) } + +/// Traversal of a [`Body`] that tries to avoid unreachable blocks in a monomorphized [`Instance`]. +/// +/// This is allowed to have false positives; blocks may be visited even if they are not actually +/// reachable. +/// +/// Such a traversal is mostly useful because it lets us skip lowering the `false` side +/// of `if <T as Trait>::CONST`, as well as [`NullOp::UbChecks`]. +/// +/// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks +pub fn mono_reachable<'a, 'tcx>( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> MonoReachable<'a, 'tcx> { + MonoReachable::new(body, tcx, instance) +} + +/// [`MonoReachable`] internally accumulates a [`BitSet`] of visited blocks. This is just a +/// convenience function to run that traversal then extract its set of reached blocks. +pub fn mono_reachable_as_bitset<'a, 'tcx>( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> BitSet<BasicBlock> { + let mut iter = mono_reachable(body, tcx, instance); + while let Some(_) = iter.next() {} + iter.visited +} + +pub struct MonoReachable<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + visited: BitSet<BasicBlock>, + // Other traversers track their worklist in a Vec. But we don't care about order, so we can + // store ours in a BitSet and thus save allocations because BitSet has a small size + // optimization. + worklist: BitSet<BasicBlock>, +} + +impl<'a, 'tcx> MonoReachable<'a, 'tcx> { + pub fn new( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + ) -> MonoReachable<'a, 'tcx> { + let mut worklist = BitSet::new_empty(body.basic_blocks.len()); + worklist.insert(START_BLOCK); + MonoReachable { + body, + tcx, + instance, + visited: BitSet::new_empty(body.basic_blocks.len()), + worklist, + } + } + + fn add_work(&mut self, blocks: impl IntoIterator<Item = BasicBlock>) { + for block in blocks.into_iter() { + if !self.visited.contains(block) { + self.worklist.insert(block); + } + } + } +} + +impl<'a, 'tcx> Iterator for MonoReachable<'a, 'tcx> { + type Item = (BasicBlock, &'a BasicBlockData<'tcx>); + + fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { + while let Some(idx) = self.worklist.iter().next() { + self.worklist.remove(idx); + if !self.visited.insert(idx) { + continue; + } + + let data = &self.body[idx]; + + if let Some((bits, targets)) = + Body::try_const_mono_switchint(self.tcx, self.instance, data) + { + let target = targets.target_for_value(bits); + self.add_work([target]); + } else { + self.add_work(data.terminator().successors()); + } + + return Some((idx, data)); + } + + None + } +} diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index d3da49c26a2..320d49ea646 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -67,6 +67,10 @@ impl<T> EraseType for &'_ ty::List<T> { type Result = [u8; size_of::<&'static ty::List<()>>()]; } +impl<T> EraseType for &'_ ty::ListWithCachedTypeInfo<T> { + type Result = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()]; +} + impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> { type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()]; } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 9cbc4d10146..faa137019cb 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -432,7 +432,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { } } -impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> { +impl<'tcx> Key for ty::Clauses<'tcx> { type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { @@ -555,6 +555,19 @@ impl Key for HirId { } } +impl Key for (LocalDefId, HirId) { + type Cache<V> = DefaultCache<Self, V>; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.hir().span(self.1) + } + + #[inline(always)] + fn key_as_def_id(&self) -> Option<DefId> { + Some(self.0.into()) + } +} + impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { type Cache<V> = DefaultCache<Self, V>; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 62a60a650ec..394515f091f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -398,15 +398,15 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + query item_bounds(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } - query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + query item_super_predicates(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> { desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } } - query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> { desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } } @@ -983,6 +983,9 @@ rustc_queries! { query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) } } + query lookup_method_for_diagnostic((def_id, hir_id): (LocalDefId, hir::HirId)) -> Option<DefId> { + desc { |tcx| "lookup_method_for_diagnostics `{}`", tcx.def_path_str(def_id) } + } query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> { desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key) } @@ -2156,7 +2159,7 @@ rustc_queries! { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } } - query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> { + query reveal_opaque_types_in_bounds(key: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { desc { "revealing opaque types in `{:?}`", key } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 8f02b3121ac..db1b5a74f0a 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -492,9 +492,7 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { // expansion, so we use `import_source_files` to ensure that the foreign // source files are actually imported before we call `source_file_by_stable_id`. if source_file_cnum != LOCAL_CRATE { - self.tcx - .cstore_untracked() - .import_source_files(self.tcx.sess, source_file_cnum); + self.tcx.import_source_files(source_file_cnum); } source_map @@ -634,12 +632,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { expn_id } else { let index_guess = self.foreign_expn_data[&hash]; - self.tcx.cstore_untracked().expn_hash_to_expn_id( - self.tcx.sess, - krate, - index_guess, - hash, - ) + self.tcx.expn_hash_to_expn_id(krate, index_guess, hash) }; debug_assert_eq!(expn_id.krate, krate); diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 8cb4ee7bd41..4ce6f7747a5 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -8,8 +8,6 @@ use crate::query::{ }; use crate::ty::TyCtxt; use field_offset::FieldOffset; -use measureme::StringId; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::AtomicU64; use rustc_data_structures::sync::WorkerLocal; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -22,16 +20,6 @@ use rustc_query_system::HandleCycleError; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; use std::ops::Deref; -pub struct QueryKeyStringCache { - pub def_id_cache: FxHashMap<DefId, StringId>, -} - -impl QueryKeyStringCache { - pub fn new() -> QueryKeyStringCache { - QueryKeyStringCache { def_id_cache: Default::default() } - } -} - pub struct DynamicQuery<'tcx, C: QueryCache> { pub name: &'static str, pub eval_always: bool, @@ -338,10 +326,11 @@ macro_rules! define_callbacks { pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>; - // Ensure that keys grow no larger than 64 bytes + // Ensure that keys grow no larger than 72 bytes by accident. + // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))] const _: () = { - if mem::size_of::<Key<'static>>() > 64 { + if mem::size_of::<Key<'static>>() > 72 { panic!("{}", concat!( "the query `", stringify!($name), @@ -352,7 +341,8 @@ macro_rules! define_callbacks { } }; - // Ensure that values grow no larger than 64 bytes + // Ensure that values grow no larger than 64 bytes by accident. + // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))] const _: () = { if mem::size_of::<Value<'static>>() > 64 { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ee816791919..790e11b8e4b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -12,8 +12,8 @@ pub mod util; use crate::infer::canonical::Canonical; use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; +use crate::ty::GenericArgsRef; use crate::ty::{self, AdtKind, Ty}; -use crate::ty::{GenericArgsRef, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; @@ -620,11 +620,10 @@ pub enum SelectionError<'tcx> { OpaqueTypeAutoTraitLeakageUnknown(DefId), } -// FIXME(@lcnr): The `Binder` here should be unnecessary. Just use `TraitRef` instead. #[derive(Clone, Debug, TypeVisitable)] pub struct SignatureMismatchData<'tcx> { - pub found_trait_ref: ty::PolyTraitRef<'tcx>, - pub expected_trait_ref: ty::PolyTraitRef<'tcx>, + pub found_trait_ref: ty::TraitRef<'tcx>, + pub expected_trait_ref: ty::TraitRef<'tcx>, pub terr: ty::error::TypeError<'tcx>, } @@ -997,33 +996,3 @@ pub enum CodegenObligationError { Unimplemented, FulfillmentError, } - -/// Defines the treatment of opaque types in a given inference context. -/// -/// This affects both what opaques are allowed to be defined, but also whether -/// opaques are replaced with inference vars eagerly in the old solver (e.g. -/// in projection, and in the signature during function type-checking). -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum DefiningAnchor<'tcx> { - /// Define opaques which are in-scope of the current item being analyzed. - /// Also, eagerly replace these opaque types in `replace_opaque_types_with_inference_vars`. - /// - /// If the list is empty, do not allow any opaques to be defined. This is used to catch type mismatch - /// errors when handling opaque types, and also should be used when we would - /// otherwise reveal opaques (such as [`Reveal::All`] reveal mode). - Bind(&'tcx ty::List<LocalDefId>), - /// In contexts where we don't currently know what opaques are allowed to be - /// defined, such as (old solver) canonical queries, we will simply allow - /// opaques to be defined, but "bubble" them up in the canonical response or - /// otherwise treat them to be handled later. - /// - /// We do not eagerly replace opaque types in `replace_opaque_types_with_inference_vars`, - /// which may affect what predicates pass and fail in the old trait solver. - Bubble, -} - -impl<'tcx> DefiningAnchor<'tcx> { - pub fn bind(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { - Self::Bind(tcx.opaque_types_defined_by(item)) - } -} diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 6dcea2aaff1..13504c6ae93 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -4,7 +4,7 @@ use rustc_span::def_id::DefId; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; use crate::traits::query::NoSolution; -use crate::traits::{Canonical, DefiningAnchor}; +use crate::traits::Canonical; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, @@ -114,7 +114,6 @@ impl MaybeCause { #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct QueryInput<'tcx, T> { pub goal: Goal<'tcx, T>, - pub anchor: DefiningAnchor<'tcx>, pub predefined_opaques_in_body: PredefinedOpaques<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 7db64504f85..211d403998f 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -6,6 +6,7 @@ use crate::{mir, ty}; use std::fmt::Write; use crate::query::Providers; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -45,7 +46,7 @@ impl UpvarId { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub enum UpvarCapture { /// Upvar is captured by value. This is always true when the @@ -73,7 +74,7 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureLis pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>; /// A composite describing a `Place` that is captured by a closure. -#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Eq, PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub struct CapturedPlace<'tcx> { /// Name and span where the binding happens. @@ -192,7 +193,7 @@ impl<'tcx> CapturedPlace<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct ClosureTypeInfo<'tcx> { user_provided_sig: ty::CanonicalPolyFnSig<'tcx>, - captures: &'tcx [&'tcx ty::CapturedPlace<'tcx>], + captures: &'tcx ty::List<&'tcx ty::CapturedPlace<'tcx>>, kind_origin: Option<&'tcx (Span, HirPlace<'tcx>)>, } @@ -201,7 +202,7 @@ fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo let typeck_results = tcx.typeck(def); let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); - let captures = tcx.arena.alloc_from_iter(captures); + let captures = tcx.mk_captures_from_iter(captures); let hir_id = tcx.local_def_id_to_hir_id(def); let kind_origin = typeck_results.closure_kind_origins().get(hir_id); ClosureTypeInfo { user_provided_sig, captures, kind_origin } @@ -253,7 +254,7 @@ pub fn is_ancestor_or_same_capture( /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub struct CaptureInfo { /// Expr Id pointing to use that resulted in selecting the current capture kind @@ -332,7 +333,7 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc curr_string } -#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] +#[derive(Eq, Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. @@ -415,6 +416,72 @@ impl BorrowKind { } } +pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( + parent_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>, + child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>, + mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, +) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> { + std::iter::from_coroutine(move || { + let mut child_captures = child_captures.into_iter().enumerate().peekable(); + + // One parent capture may correspond to several child captures if we end up + // refining the set of captures via edition-2021 precise captures. We want to + // match up any number of child captures with one parent capture, so we keep + // peeking off this `Peekable` until the child doesn't match anymore. + for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { + // Make sure we use every field at least once, b/c why are we capturing something + // if it's not used in the inner coroutine. + let mut field_used_at_least_once = false; + + // A parent matches a child if they share the same prefix of projections. + // The child may have more, if it is capturing sub-fields out of + // something that is captured by-move in the parent closure. + while child_captures.peek().map_or(false, |(_, child_capture)| { + child_prefix_matches_parent_projections(parent_capture, child_capture) + }) { + let (child_field_idx, child_capture) = child_captures.next().unwrap(); + // This analysis only makes sense if the parent capture is a + // prefix of the child capture. + assert!( + child_capture.place.projections.len() >= parent_capture.place.projections.len(), + "parent capture ({parent_capture:#?}) expected to be prefix of \ + child capture ({child_capture:#?})" + ); + + yield for_each( + (parent_field_idx, parent_capture), + (child_field_idx, child_capture), + ); + + field_used_at_least_once = true; + } + + // Make sure the field was used at least once. + assert!( + field_used_at_least_once, + "we captured {parent_capture:#?} but it was not used in the child coroutine?" + ); + } + assert_eq!(child_captures.next(), None, "leftover child captures?"); + }) +} + +fn child_prefix_matches_parent_projections( + parent_capture: &ty::CapturedPlace<'_>, + child_capture: &ty::CapturedPlace<'_>, +) -> bool { + let HirPlaceBase::Upvar(parent_base) = parent_capture.place.base else { + bug!("expected capture to be an upvar"); + }; + let HirPlaceBase::Upvar(child_base) = child_capture.place.base else { + bug!("expected capture to be an upvar"); + }; + + parent_base.var_path.hir_id == child_base.var_path.hir_id + && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections) + .all(|(child, parent)| child.kind == parent.kind) +} + pub fn provide(providers: &mut Providers) { *providers = Providers { closure_typeinfo, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e7a1679b151..c0effe9804c 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -148,6 +148,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> { } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Pattern<'tcx> { + fn encode(&self, e: &mut E) { + self.0.0.encode(e); + } +} + impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> { fn encode(&self, e: &mut E) { self.inner().encode(e) @@ -364,6 +370,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Pattern<'tcx> { + fn decode(decoder: &mut D) -> Self { + decoder.interner().mk_pat(Decodable::decode(decoder)) + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { fn decode(decoder: &mut D) -> &'tcx Self { decoder @@ -414,7 +426,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty } } -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> { +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> + for ty::ListWithCachedTypeInfo<ty::Clause<'tcx>> +{ fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder.interner().mk_clauses_from_iter( @@ -441,6 +455,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Lo } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for &'tcx ty::List<LocalDefId> { + fn decode(d: &mut D) -> Self { + RefDecodable::decode(d) + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<(VariantIdx, FieldIdx)> { @@ -461,7 +481,7 @@ impl_decodable_via_ref! { &'tcx mir::BorrowCheckResult<'tcx>, &'tcx mir::coverage::CodeRegion, &'tcx ty::List<ty::BoundVariableKind>, - &'tcx ty::List<ty::Clause<'tcx>>, + &'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>, &'tcx ty::List<FieldIdx>, &'tcx ty::List<(VariantIdx, FieldIdx)>, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 75deffe6957..6275c5d2a11 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,11 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, - ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, - PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, - TyKind, TyVid, TypeVisitable, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData, + GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, + PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, + Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, + Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -84,6 +85,7 @@ use std::ops::{Bound, Deref}; #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; + type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArg = ty::GenericArg<'tcx>; @@ -95,6 +97,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; + type Pat = Pattern<'tcx>; type Tys = &'tcx List<Ty<'tcx>>; type AliasTy = ty::AliasTy<'tcx>; type ParamTy = ParamTy; @@ -130,6 +133,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type SubtypePredicate = ty::SubtypePredicate<'tcx>; type CoercePredicate = ty::CoercePredicate<'tcx>; type ClosureKind = ty::ClosureKind; + type Clauses = ty::Clauses<'tcx>; fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) @@ -152,10 +156,11 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, - clauses: InternedSet<'tcx, List<Clause<'tcx>>>, + clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>, + pat: InternedSet<'tcx, PatternKind<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>, @@ -164,6 +169,7 @@ pub struct CtxtInterners<'tcx> { predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List<FieldIdx>>, local_def_ids: InternedSet<'tcx, List<LocalDefId>>, + captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, } @@ -183,6 +189,7 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), + pat: Default::default(), const_allocation: Default::default(), bound_variable_kinds: Default::default(), layout: Default::default(), @@ -191,6 +198,7 @@ impl<'tcx> CtxtInterners<'tcx> { predefined_opaques_in_body: Default::default(), fields: Default::default(), local_def_ids: Default::default(), + captures: Default::default(), offset_of: Default::default(), } } @@ -286,6 +294,24 @@ impl<'tcx> CtxtInterners<'tcx> { .0, )) } + + fn intern_clauses(&self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> { + if clauses.is_empty() { + ListWithCachedTypeInfo::empty() + } else { + self.clauses + .intern_ref(clauses, || { + let flags = super::flags::FlagComputation::for_clauses(clauses); + + InternedInSet(ListWithCachedTypeInfo::from_arena( + &*self.arena, + flags.into(), + clauses, + )) + }) + .0 + } + } } // For these preinterned values, an alternative would be to have @@ -731,7 +757,7 @@ pub struct GlobalCtxt<'tcx> { impl<'tcx> GlobalCtxt<'tcx> { /// Installs `self` in a `TyCtxt` and `ImplicitCtxt` for the duration of /// `f`. - pub fn enter<'a: 'tcx, F, R>(&'a self, f: F) -> R + pub fn enter<F, R>(&'tcx self, f: F) -> R where F: FnOnce(TyCtxt<'tcx>) -> R, { @@ -1139,11 +1165,7 @@ impl<'tcx> TyCtxt<'tcx> { .local_def_path_hash_to_def_id(hash, err_msg) .to_def_id() } else { - // If this is a DefPathHash from an upstream crate, let the CrateStore map - // it to a DefId. - let cstore = &*self.cstore_untracked(); - let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); - cstore.def_path_hash_to_def_id(cnum, hash) + self.def_path_hash_to_def_id_extern(hash, stable_crate_id) } } @@ -1559,6 +1581,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; Const<'a> => Const<'tcx>} +nop_lift! {pat; Pattern<'a> => Pattern<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} nop_lift! {predicate; Clause<'a> => Clause<'tcx>} @@ -1696,6 +1719,7 @@ impl<'tcx> TyCtxt<'tcx> { Param, Infer, Alias, + Pat, Foreign )?; @@ -1783,6 +1807,29 @@ impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> { } } +impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> { + fn borrow(&self) -> &[T] { + &self.0[..] + } +} + +impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> { + fn eq(&self, other: &InternedInSet<'tcx, ListWithCachedTypeInfo<T>>) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals + // `x == y`. + self.0[..] == other.0[..] + } +} + +impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {} + +impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> { + fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. + self.0[..].hash(s) + } +} + macro_rules! direct_interners { ($($name:ident: $vis:vis $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => { $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> { @@ -1824,6 +1871,7 @@ macro_rules! direct_interners { // crate only, and have a corresponding `mk_` function. direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, + pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, @@ -1841,7 +1889,7 @@ macro_rules! slice_interners { List::empty() } else { self.interners.$field.intern_ref(v, || { - InternedInSet(List::from_arena(&*self.arena, v)) + InternedInSet(List::from_arena(&*self.arena, (), v)) }).0 } })+ @@ -1858,12 +1906,12 @@ slice_interners!( type_lists: pub mk_type_list(Ty<'tcx>), canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), - clauses: intern_clauses(Clause<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), fields: pub mk_fields(FieldIdx), local_def_ids: intern_local_def_ids(LocalDefId), + captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), ); @@ -2163,11 +2211,11 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_poly_existential_predicates(eps) } - pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> { + pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> { // FIXME consider asking the input slice to be sorted to avoid // re-interning permutations, in which case that would be asserted // here. - self.intern_clauses(clauses) + self.interners.intern_clauses(clauses) } pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> { @@ -2185,6 +2233,17 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_local_def_ids(xs)) } + pub fn mk_captures_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply< + &'tcx ty::CapturedPlace<'tcx>, + &'tcx List<&'tcx ty::CapturedPlace<'tcx>>, + >, + { + T::collect_and_apply(iter, |xs| self.intern_captures(xs)) + } + pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, @@ -2231,7 +2290,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, - T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>, + T: CollectAndApply<Clause<'tcx>, Clauses<'tcx>>, { T::collect_and_apply(iter, |xs| self.mk_clauses(xs)) } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index ee18647cdd8..cc1d6e50f6d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -5,13 +5,13 @@ use std::fmt::Write; use std::ops::ControlFlow; use crate::ty::{ - AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, PolyTraitPredicate, - Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitor, + self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, + PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diag, DiagArgValue, IntoDiagArg}; +use rustc_errors::{into_diag_arg_using_display, Applicability, Diag, DiagArgValue, IntoDiagArg}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -19,10 +19,9 @@ use rustc_hir::{PredicateOrigin, WherePredicate}; use rustc_span::{BytePos, Span}; use rustc_type_ir::TyKind::*; -impl<'tcx> IntoDiagArg for Ty<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } +into_diag_arg_using_display! { + Ty<'_>, + ty::Region<'_>, } impl<'tcx> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 09586a95f1c..ce85c28ece8 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -285,6 +285,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(def, _) => def.descr().into(), ty::Foreign(_) => "extern type".into(), ty::Array(..) => "array".into(), + ty::Pat(..) => "pattern type".into(), ty::Slice(_) => "slice".into(), ty::RawPtr(_, _) => "raw pointer".into(), ty::Ref(.., mutbl) => match mutbl { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 5b257cdfd86..7c925d5fbb6 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -120,6 +120,7 @@ pub fn simplify_type<'tcx>( ty::Str => Some(SimplifiedType::Str), ty::Array(..) => Some(SimplifiedType::Array), ty::Slice(..) => Some(SimplifiedType::Slice), + ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params), ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { @@ -231,6 +232,7 @@ impl DeepRejectCtxt { | ty::Slice(..) | ty::RawPtr(..) | ty::Dynamic(..) + | ty::Pat(..) | ty::Ref(..) | ty::Never | ty::Tuple(..) @@ -269,6 +271,10 @@ impl DeepRejectCtxt { } _ => false, }, + ty::Pat(obl_ty, _) => { + // FIXME(pattern_types): take pattern into account + matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty)) + } ty::Slice(obl_ty) => { matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index ca9c762611e..0dc835671d5 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -35,6 +35,15 @@ impl FlagComputation { result } + pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation { + let mut result = FlagComputation::new(); + for c in clauses { + result.add_flags(c.as_predicate().flags()); + result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); + } + result + } + fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -209,6 +218,20 @@ impl FlagComputation { self.add_const(len); } + &ty::Pat(ty, pat) => { + self.add_ty(ty); + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + if let Some(start) = start { + self.add_const(start) + } + if let Some(end) = end { + self.add_const(end) + } + } + } + } + &ty::Slice(tt) => self.add_ty(tt), &ty::RawPtr(ty, _) => { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 2630b96869b..e984f543701 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -316,11 +316,11 @@ impl<'tcx> Generics { /// of this item, excluding `Self`. /// /// **This should only be used for diagnostics purposes.** - pub fn own_args_no_defaults( + pub fn own_args_no_defaults<'a>( &'tcx self, tcx: TyCtxt<'tcx>, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> &'tcx [ty::GenericArg<'tcx>] { + args: &'a [ty::GenericArg<'tcx>], + ) -> &'a [ty::GenericArg<'tcx>] { let mut own_params = self.parent_count..self.count(); if self.has_self && self.parent.is_none() { own_params.start = 1; diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 129d947697e..ef7a7a99ff7 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -11,19 +11,20 @@ use rustc_data_structures::stable_hasher::HashingControls; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_query_system::ich::StableHashingContext; use std::cell::RefCell; +use std::ptr; -impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T> +impl<'a, 'tcx, H, T> HashStable<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T> where T: HashStable<StableHashingContext<'a>>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { thread_local! { - static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> = + static CACHE: RefCell<FxHashMap<(*const (), HashingControls), Fingerprint>> = RefCell::new(Default::default()); } let hash = CACHE.with(|cache| { - let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls()); + let key = (ptr::from_ref(*self).cast::<()>(), hcx.hashing_controls()); if let Some(&hash) = cache.borrow().get(&key) { return hash; } @@ -40,7 +41,7 @@ where } } -impl<'a, 'tcx, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::List<T> +impl<'a, 'tcx, H, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T> where T: HashStable<StableHashingContext<'a>>, { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4a7720b38f8..f8f59fbeab4 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -520,7 +520,10 @@ impl<'tcx> Instance<'tcx> { // Reify `Trait::method` implementations if KCFI is enabled // FIXME(maurer) only reify it if it is a vtable-safe function _ if tcx.sess.is_sanitizer_kcfi_enabled() - && tcx.associated_item(def_id).trait_item_def_id.is_some() => + && tcx + .opt_associated_item(def_id) + .and_then(|assoc| assoc.trait_item_def_id) + .is_some() => { // If this function could also go in a vtable, we need to `ReifyShim` it with // KCFI because it can only attach one type per function. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 66078663098..50e68bfdbe7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -742,6 +742,7 @@ where | ty::FnDef(..) | ty::CoroutineWitness(..) | ty::Foreign(..) + | ty::Pat(_, _) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 336c2dce114..0db541899d2 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,7 +1,8 @@ +use super::flags::FlagComputation; +use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx}; use crate::arena::Arena; use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_serialize::{Encodable, Encoder}; -use rustc_type_ir::{InferCtxtLike, WithInfcx}; use std::alloc::Layout; use std::cmp::Ordering; use std::fmt; @@ -12,6 +13,9 @@ use std::ops::Deref; use std::ptr; use std::slice; +#[cfg(parallel_compiler)] +use rustc_data_structures::sync::DynSync; + /// `List<T>` is a bit like `&[T]`, but with some critical differences. /// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The /// type's correctness relies on this, *but it does not enforce it*. @@ -28,15 +32,33 @@ use std::slice; /// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and /// iterators return a `T` rather than a `&T`. /// - `T` must not be zero-sized. +pub type List<T> = RawList<(), T>; + +/// A generic type that can be used to prepend a [`List`] with some header. +/// +/// The header will be ignored for value-based operations like [`PartialEq`], +/// [`Hash`] and [`Encodable`]. #[repr(C)] -pub struct List<T> { - len: usize, +pub struct RawList<H, T> { + skel: ListSkeleton<H, T>, + opaque: OpaqueListContents, +} +/// A [`RawList`] without the unsized tail. This type is used for layout computation +/// and constructing empty lists. +#[repr(C)] +struct ListSkeleton<H, T> { + header: H, + len: usize, /// Although this claims to be a zero-length array, in practice `len` /// elements are actually present. data: [T; 0], +} - opaque: OpaqueListContents, +impl<T> Default for &List<T> { + fn default() -> Self { + List::empty() + } } extern "C" { @@ -45,35 +67,17 @@ extern "C" { type OpaqueListContents; } -impl<T> List<T> { - /// Returns a reference to the (unique, static) empty list. +impl<H, T> RawList<H, T> { #[inline(always)] - pub fn empty<'a>() -> &'a List<T> { - #[repr(align(64))] - struct MaxAlign; - - assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>()); - - #[repr(C)] - struct InOrder<T, U>(T, U); - - // The empty slice is static and contains a single `0` usize (for the - // length) that is 64-byte aligned, thus featuring the necessary - // trailing padding for elements with up to 64-byte alignment. - static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign); - unsafe { &*(std::ptr::addr_of!(EMPTY_SLICE) as *const List<T>) } - } - pub fn len(&self) -> usize { - self.len + self.skel.len } + #[inline(always)] pub fn as_slice(&self) -> &[T] { self } -} -impl<T: Copy> List<T> { /// Allocates a list from `arena` and copies the contents of `slice` into it. /// /// WARNING: the contents *must be unique*, such that no list with these @@ -84,20 +88,31 @@ impl<T: Copy> List<T> { /// (because the empty list exists statically, and is available via /// `empty()`). #[inline] - pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> { + pub(super) fn from_arena<'tcx>( + arena: &'tcx Arena<'tcx>, + header: H, + slice: &[T], + ) -> &'tcx RawList<H, T> + where + T: Copy, + { assert!(!mem::needs_drop::<T>()); assert!(mem::size_of::<T>() != 0); assert!(!slice.is_empty()); let (layout, _offset) = - Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap(); - let mem = arena.dropless.alloc_raw(layout) as *mut List<T>; + Layout::new::<ListSkeleton<H, T>>().extend(Layout::for_value::<[T]>(slice)).unwrap(); + + let mem = arena.dropless.alloc_raw(layout) as *mut RawList<H, T>; unsafe { + // Write the header + ptr::addr_of_mut!((*mem).skel.header).write(header); + // Write the length - ptr::addr_of_mut!((*mem).len).write(slice.len()); + ptr::addr_of_mut!((*mem).skel.len).write(slice.len()); // Write the elements - ptr::addr_of_mut!((*mem).data) + ptr::addr_of_mut!((*mem).skel.data) .cast::<T>() .copy_from_nonoverlapping(slice.as_ptr(), slice.len()); @@ -110,17 +125,44 @@ impl<T: Copy> List<T> { // // This would be weird, as `self.into_iter` iterates over `T` directly. #[inline(always)] - pub fn iter(&self) -> <&'_ List<T> as IntoIterator>::IntoIter { + pub fn iter(&self) -> <&'_ RawList<H, T> as IntoIterator>::IntoIter + where + T: Copy, + { self.into_iter() } } -impl<T: fmt::Debug> fmt::Debug for List<T> { +macro_rules! impl_list_empty { + ($header_ty:ty, $header_init:expr) => { + impl<T> RawList<$header_ty, T> { + /// Returns a reference to the (per header unique, static) empty list. + #[inline(always)] + pub fn empty<'a>() -> &'a RawList<$header_ty, T> { + #[repr(align(64))] + struct MaxAlign; + + static EMPTY: ListSkeleton<$header_ty, MaxAlign> = + ListSkeleton { header: $header_init, len: 0, data: [] }; + + assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>()); + + // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all + // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above. + unsafe { &*(std::ptr::addr_of!(EMPTY) as *const RawList<$header_ty, T>) } + } + } + }; +} + +impl_list_empty!((), ()); + +impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } -impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> { +impl<'tcx, H, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for RawList<H, T> { fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, @@ -129,40 +171,40 @@ impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt< } } -impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> { +impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> { #[inline] fn encode(&self, s: &mut S) { (**self).encode(s); } } -impl<T: PartialEq> PartialEq for List<T> { +impl<H, T: PartialEq> PartialEq for RawList<H, T> { #[inline] - fn eq(&self, other: &List<T>) -> bool { + fn eq(&self, other: &RawList<H, T>) -> bool { // Pointer equality implies list equality (due to the unique contents // assumption). ptr::eq(self, other) } } -impl<T: Eq> Eq for List<T> {} +impl<H, T: Eq> Eq for RawList<H, T> {} -impl<T> Ord for List<T> +impl<H, T> Ord for RawList<H, T> where T: Ord, { - fn cmp(&self, other: &List<T>) -> Ordering { + fn cmp(&self, other: &RawList<H, T>) -> Ordering { // Pointer equality implies list equality (due to the unique contents // assumption), but the contents must be compared otherwise. if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) } } } -impl<T> PartialOrd for List<T> +impl<H, T> PartialOrd for RawList<H, T> where T: PartialOrd, { - fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> { + fn partial_cmp(&self, other: &RawList<H, T>) -> Option<Ordering> { // Pointer equality implies list equality (due to the unique contents // assumption), but the contents must be compared otherwise. if self == other { @@ -173,16 +215,16 @@ where } } -impl<T> Hash for List<T> { +impl<Hdr, T> Hash for RawList<Hdr, T> { #[inline] fn hash<H: Hasher>(&self, s: &mut H) { // Pointer hashing is sufficient (due to the unique contents // assumption). - (self as *const List<T>).hash(s) + ptr::from_ref(self).hash(s) } } -impl<T> Deref for List<T> { +impl<H, T> Deref for RawList<H, T> { type Target = [T]; #[inline(always)] fn deref(&self) -> &[T] { @@ -190,14 +232,19 @@ impl<T> Deref for List<T> { } } -impl<T> AsRef<[T]> for List<T> { +impl<H, T> AsRef<[T]> for RawList<H, T> { #[inline(always)] fn as_ref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } + let data_ptr = ptr::addr_of!(self.skel.data).cast::<T>(); + // SAFETY: `data_ptr` has the same provenance as `self` and can therefore + // access the `self.skel.len` elements stored at `self.skel.data`. + // Note that we specifically don't reborrow `&self.skel.data`, because that + // would give us a pointer with provenance over 0 bytes. + unsafe { slice::from_raw_parts(data_ptr, self.skel.len) } } } -impl<'a, T: Copy> IntoIterator for &'a List<T> { +impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> { type Item = T; type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>; #[inline(always)] @@ -206,27 +253,56 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> { } } -unsafe impl<T: Sync> Sync for List<T> {} +unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {} // We need this since `List` uses extern type `OpaqueListContents`. #[cfg(parallel_compiler)] -use rustc_data_structures::sync::DynSync; - -use super::TyCtxt; -#[cfg(parallel_compiler)] -unsafe impl<T: DynSync> DynSync for List<T> {} +unsafe impl<H: DynSync, T: DynSync> DynSync for RawList<H, T> {} // Safety: -// Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail, -// thus aligns of `Equivalent<T>` and `List<T>` must be the same. -unsafe impl<T> Aligned for List<T> { - const ALIGN: ptr::Alignment = { - #[repr(C)] - struct Equivalent<T> { - _len: usize, - _data: [T; 0], - } +// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo opaque tail, +// thus aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same. +unsafe impl<H, T> Aligned for RawList<H, T> { + const ALIGN: ptr::Alignment = align_of::<ListSkeleton<H, T>>(); +} - align_of::<Equivalent<T>>() - }; +/// A [`List`] that additionally stores type information inline to speed up +/// [`TypeVisitableExt`](super::TypeVisitableExt) operations. +pub type ListWithCachedTypeInfo<T> = RawList<TypeInfo, T>; + +impl<T> ListWithCachedTypeInfo<T> { + #[inline(always)] + pub fn flags(&self) -> TypeFlags { + self.skel.header.flags + } + + #[inline(always)] + pub fn outer_exclusive_binder(&self) -> DebruijnIndex { + self.skel.header.outer_exclusive_binder + } +} + +impl_list_empty!(TypeInfo, TypeInfo::empty()); + +/// The additional info that is stored in [`ListWithCachedTypeInfo`]. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TypeInfo { + flags: TypeFlags, + outer_exclusive_binder: DebruijnIndex, +} + +impl TypeInfo { + const fn empty() -> Self { + Self { flags: TypeFlags::empty(), outer_exclusive_binder: super::INNERMOST } + } +} + +impl From<FlagComputation> for TypeInfo { + fn from(computation: FlagComputation) -> TypeInfo { + TypeInfo { + flags: computation.flags, + outer_exclusive_binder: computation.outer_exclusive_binder, + } + } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fb56c71c517..e6b773ae512 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -77,9 +77,10 @@ pub use rustc_type_ir::ConstKind::{ pub use rustc_type_ir::*; pub use self::closure::{ - is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo, - CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList, - RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, CAPTURE_STRUCT_LOCAL, + analyze_coroutine_closure_captures, is_ancestor_or_same_capture, place_to_string_for_capture, + BorrowKind, CaptureInfo, CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, + MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, + CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree, @@ -89,8 +90,9 @@ pub use self::context::{ TyCtxt, TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; -pub use self::list::List; +pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::parameterized::ParameterizedOverTcx; +pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, @@ -130,6 +132,7 @@ pub mod fold; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; +pub mod pattern; pub mod print; pub mod relate; pub mod trait_def; @@ -1034,6 +1037,18 @@ impl PlaceholderLike for PlaceholderConst { } } +pub type Clauses<'tcx> = &'tcx ListWithCachedTypeInfo<Clause<'tcx>>; + +impl<'tcx> rustc_type_ir::visit::Flags for Clauses<'tcx> { + fn flags(&self) -> TypeFlags { + (**self).flags() + } + + fn outer_exclusive_binder(&self) -> DebruijnIndex { + (**self).outer_exclusive_binder() + } +} + /// When interacting with the type system we must provide information about the /// environment. `ParamEnv` is the type that represents this information. See the /// [dev guide chapter][param_env_guide] for more information. @@ -1053,7 +1068,7 @@ pub struct ParamEnv<'tcx> { /// want `Reveal::All`. /// /// Note: This is packed, use the reveal() method to access it. - packed: CopyTaggedPtr<&'tcx List<Clause<'tcx>>, ParamTag, true>, + packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>, } #[derive(Copy, Clone)] @@ -1112,11 +1127,11 @@ impl<'tcx> ParamEnv<'tcx> { /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing) + Self::new(ListWithCachedTypeInfo::empty(), Reveal::UserFacing) } #[inline] - pub fn caller_bounds(self) -> &'tcx List<Clause<'tcx>> { + pub fn caller_bounds(self) -> Clauses<'tcx> { self.packed.pointer() } @@ -1134,12 +1149,12 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All) + Self::new(ListWithCachedTypeInfo::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. #[inline] - pub fn new(caller_bounds: &'tcx List<Clause<'tcx>>, reveal: Reveal) -> Self { + pub fn new(caller_bounds: Clauses<'tcx>, reveal: Reveal) -> Self { ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) } } @@ -1168,7 +1183,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Returns this same environment but with no caller bounds. #[inline] pub fn without_caller_bounds(self) -> Self { - Self::new(List::empty(), self.reveal()) + Self::new(ListWithCachedTypeInfo::empty(), self.reveal()) } /// Creates a pair of param-env and value for use in queries. diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs new file mode 100644 index 00000000000..8a41ba257ec --- /dev/null +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -0,0 +1,48 @@ +use std::fmt; + +use crate::ty; +use rustc_data_structures::intern::Interned; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>); + +impl<'tcx> std::ops::Deref for Pattern<'tcx> { + type Target = PatternKind<'tcx>; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +impl<'tcx> fmt::Debug for Pattern<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", **self) + } +} + +impl<'tcx> fmt::Debug for PatternKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + PatternKind::Range { start, end, include_end } => { + if let Some(start) = start { + write!(f, "{start}")?; + } + write!(f, "..")?; + if include_end { + write!(f, "=")?; + } + if let Some(end) = end { + write!(f, "{end}")?; + } + Ok(()) + } + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] +pub enum PatternKind<'tcx> { + Range { start: Option<ty::Const<'tcx>>, end: Option<ty::Const<'tcx>>, include_end: bool }, +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index d9aa7f9e5c4..9d0e1123e43 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -259,7 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty::Dynamic(data, ..) => data.principal_def_id(), - ty::Array(subty, _) | ty::Slice(subty) => { + ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => { characteristic_def_id_of_type_cached(subty, visited) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2a898430ce9..0bd009cd51d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -667,14 +667,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Int(t) => p!(write("{}", t.name_str())), ty::Uint(t) => p!(write("{}", t.name_str())), ty::Float(t) => p!(write("{}", t.name_str())), + ty::Pat(ty, pat) => { + p!("(", print(ty), ") is ", write("{pat:?}")) + } ty::RawPtr(ty, mutbl) => { - p!(write( - "*{} ", - match mutbl { - hir::Mutability::Mut => "mut", - hir::Mutability::Not => "const", - } - )); + p!(write("*{} ", mutbl.ptr_str())); p!(print(ty)) } ty::Ref(r, ty, mutbl) => { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index cf7caafcebb..3c1dea1d9f2 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -13,6 +13,8 @@ use rustc_hir::def_id::DefId; use rustc_target::spec::abi; use std::iter; +use super::Pattern; + pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>; pub trait TypeRelation<'tcx>: Sized { @@ -351,6 +353,36 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } +impl<'tcx> Relate<'tcx> for Pattern<'tcx> { + #[inline] + fn relate<R: TypeRelation<'tcx>>( + relation: &mut R, + a: Self, + b: Self, + ) -> RelateResult<'tcx, Self> { + match (&*a, &*b) { + ( + &ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a }, + &ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b }, + ) => { + // FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`). + let mut relate_opt_const = |a, b| match (a, b) { + (None, None) => Ok(None), + (Some(a), Some(b)) => relation.relate(a, b).map(Some), + // FIXME(pattern_types): report a better error + _ => Err(TypeError::Mismatch), + }; + let start = relate_opt_const(start_a, start_b)?; + let end = relate_opt_const(end_a, end_b)?; + if inc_a != inc_b { + todo!() + } + Ok(relation.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) + } + } + } +} + /// Relates `a` and `b` structurally, calling the relation for all nested values. /// Any semantic equality, e.g. of projections, and inference variables have to be /// handled by the caller. @@ -533,6 +565,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_alias(tcx, a_kind, alias_ty)) } + (&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => { + let ty = relation.relate(a_ty, b_ty)?; + let pat = relation.relate(a_pat, b_pat)?; + Ok(Ty::new_pat(tcx, ty, pat)) + } + _ => Err(TypeError::Sorts(expected_found(a, b))), } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 0e7010e67d7..90c68e7ddfc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -20,6 +20,8 @@ use std::fmt::{self, Debug}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Region}; +use super::Pattern; + impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { @@ -210,6 +212,22 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { } } +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> { + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match &**this.data { + ty::PatternKind::Range { start, end, include_end } => f + .debug_struct("Pattern::Range") + .field("start", start) + .field("end", end) + .field("include_end", include_end) + .finish(), + } + } +} + impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { WithInfcx::with_no_infcx(self).fmt(f) @@ -541,6 +559,22 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> { } } +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + let pat = (*self).clone().try_fold_with(folder)?; + Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) }) + } +} + +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Pattern<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + (**self).visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, @@ -586,6 +620,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> { ty::CoroutineClosure(did, args.try_fold_with(folder)?) } ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), + ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?), ty::Bool | ty::Char @@ -633,6 +668,11 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> { ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor), + ty::Pat(ty, pat) => { + try_visit!(ty.visit_with(visitor)); + pat.visit_with(visitor) + } + ty::Bool | ty::Char | ty::Str @@ -712,7 +752,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { } } -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> { +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + visitor.visit_clauses(self) + } +} + +impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> { + fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + self.as_slice().visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clauses<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, folder: &mut F, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2ab63f01e7c..ad64745d579 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -771,7 +771,7 @@ impl<'tcx> CoroutineArgs<'tcx> { } } -#[derive(Debug, Copy, Clone, HashStable)] +#[derive(Debug, Copy, Clone, HashStable, TypeFoldable, TypeVisitable)] pub enum UpvarArgs<'tcx> { Closure(GenericArgsRef<'tcx>), Coroutine(GenericArgsRef<'tcx>), @@ -1523,6 +1523,11 @@ impl<'tcx> Ty<'tcx> { } #[inline] + pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Pat(base, pat)) + } + + #[inline] pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { Ty::new_alias(tcx, ty::Opaque, AliasTy::new(tcx, def_id, args)) } @@ -2226,7 +2231,7 @@ impl<'tcx> Ty<'tcx> { pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> { match self.kind() { Tuple(args) => args, - _ => bug!("tuple_fields called on non-tuple"), + _ => bug!("tuple_fields called on non-tuple: {self:?}"), } } @@ -2278,6 +2283,8 @@ impl<'tcx> Ty<'tcx> { Ty::new_projection(tcx, assoc_items[0], tcx.mk_args(&[self.into()])) } + ty::Pat(ty, _) => ty.discriminant_ty(tcx), + ty::Bool | ty::Char | ty::Int(_) @@ -2359,6 +2366,7 @@ impl<'tcx> Ty<'tcx> { ty::Param(_) | ty::Alias(..) => Err(tail), ty::Infer(ty::TyVar(_)) + | ty::Pat(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!( @@ -2495,6 +2503,7 @@ impl<'tcx> Ty<'tcx> { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Array(..) + | ty::Pat(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -2549,6 +2558,8 @@ impl<'tcx> Ty<'tcx> { field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy) } + ty::Pat(ty, _) => ty.is_trivially_pure_clone_copy(), + // Sometimes traits aren't implemented for every ABI or arity, // because we can't be generic over everything yet. ty::FnPtr(..) => false, @@ -2630,6 +2641,7 @@ impl<'tcx> Ty<'tcx> { | Foreign(_) | Str | Array(_, _) + | Pat(_, _) | Slice(_) | RawPtr(_, _) | Ref(_, _, _) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f74bba134ab..e422fb0d020 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -245,6 +245,11 @@ impl<'tcx> TyCtxt<'tcx> { ty::Tuple(_) => break, + ty::Pat(inner, _) => { + f(); + ty = inner; + } + ty::Alias(..) => { let normalized = normalize(ty); if ty == normalized { @@ -1242,7 +1247,7 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) | ty::FnPtr(_) => true, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_freeze), - ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), + ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_freeze(), ty::Adt(..) | ty::Bound(..) | ty::Closure(..) @@ -1282,7 +1287,7 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) | ty::FnPtr(_) => true, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_unpin), - ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(), + ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_unpin(), ty::Adt(..) | ty::Bound(..) | ty::Closure(..) @@ -1398,7 +1403,7 @@ impl<'tcx> Ty<'tcx> { // // Because this function is "shallow", we return `true` for these composites regardless // of the type(s) contained within. - ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true, + ty::Pat(..) | ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true, // Raw pointers use bitwise comparison. ty::RawPtr(_, _) | ty::FnPtr(_) => true, @@ -1528,7 +1533,7 @@ pub fn needs_drop_components<'tcx>( ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop), - ty::Slice(ty) => needs_drop_components(tcx, ty), + ty::Pat(ty, _) | ty::Slice(ty) => needs_drop_components(tcx, ty), ty::Array(elem_ty, size) => { match needs_drop_components(tcx, elem_ty) { Ok(v) if v.is_empty() => Ok(v), @@ -1597,7 +1602,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { | ty::CoroutineWitness(..) | ty::Adt(..) => false, - ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), + ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty), ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)), } @@ -1608,16 +1613,18 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { /// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); /// folder.tcx().intern_*(&v) /// ``` -pub fn fold_list<'tcx, F, T>( - list: &'tcx ty::List<T>, +pub fn fold_list<'tcx, F, L, T>( + list: L, folder: &mut F, - intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>, -) -> Result<&'tcx ty::List<T>, F::Error> + intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L, +) -> Result<L, F::Error> where F: FallibleTypeFolder<TyCtxt<'tcx>>, + L: AsRef<[T]>, T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy, { - let mut iter = list.iter(); + let slice = list.as_ref(); + let mut iter = slice.iter().copied(); // Look for the first element that changed match iter.by_ref().enumerate().find_map(|(i, t)| match t.try_fold_with(folder) { Ok(new_t) if new_t == t => None, @@ -1625,8 +1632,8 @@ where }) { Some((i, Ok(new_t))) => { // An element changed, prepare to intern the resulting list - let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); - new_list.extend_from_slice(&list[..i]); + let mut new_list = SmallVec::<[_; 8]>::with_capacity(slice.len()); + new_list.extend_from_slice(&slice[..i]); new_list.push(new_t); for t in iter { new_list.push(t.try_fold_with(folder)?) @@ -1647,8 +1654,8 @@ pub struct AlwaysRequiresDrop; /// with their underlying types. pub fn reveal_opaque_types_in_bounds<'tcx>( tcx: TyCtxt<'tcx>, - val: &'tcx ty::List<ty::Clause<'tcx>>, -) -> &'tcx ty::List<ty::Clause<'tcx>> { + val: ty::Clauses<'tcx>, +) -> ty::Clauses<'tcx> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), expanded_cache: FxHashMap::default(), diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 9e7bf980237..7069bdcbcb9 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -151,6 +151,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Bound(..) | ty::Foreign(..) => {} + ty::Pat(ty, pat) => { + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + stack.extend(end.map(Into::into)); + stack.extend(start.map(Into::into)); + } + } + stack.push(ty.into()); + } ty::Array(ty, len) => { stack.push(len.into()); stack.push(ty.into()); diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs index dd3a36c7bf8..2038d3f8448 100644 --- a/compiler/rustc_middle/src/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -1,8 +1,3 @@ -use rustc_data_structures::sync::Lock; - -use std::fmt::Debug; -use std::time::{Duration, Instant}; - #[cfg(test)] mod tests; @@ -26,46 +21,6 @@ pub fn to_readable_str(mut val: usize) -> String { groups.join("_") } -pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T -where - F: FnOnce() -> T, -{ - let start = Instant::now(); - let rv = f(); - let duration = start.elapsed(); - let mut accu = accu.lock(); - *accu += duration; - rv -} - -pub fn indent<R, F>(op: F) -> R -where - R: Debug, - F: FnOnce() -> R, -{ - // Use in conjunction with the log post-processor like `src/etc/indenter` - // to make debug output more readable. - debug!(">>"); - let r = op(); - debug!("<< (Result = {:?})", r); - r -} - -pub struct Indenter { - _cannot_construct_outside_of_this_module: (), -} - -impl Drop for Indenter { - fn drop(&mut self) { - debug!("<<"); - } -} - -pub fn indenter() -> Indenter { - debug!(">>"); - Indenter { _cannot_construct_outside_of_this_module: () } -} - // const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }` pub const fn c_name(name: &'static str) -> &'static str { // FIXME Simplify the implementation once more `str` methods get const-stable. 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 a3e6c2abc51..03195a122b4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -674,6 +674,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) && interpreted_as_const.is_none() + && scrut.is_some() { let mut bindings = vec![]; pat.each_binding(|name, _, _, _| bindings.push(name)); 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 ce39aff69cb..65c53be8ddd 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 @@ -457,7 +457,7 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } } } - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { + ty::Pat(..) | 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. PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index e73d945e0bb..d7477309400 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -153,6 +153,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(_) @@ -193,6 +194,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index b71c5894ff7..0af88729887 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -16,7 +16,7 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { if sess.target.llvm_target == "i686-pc-windows-msvc" { return false; } - sess.opts.debug_assertions + sess.ub_checks() } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index de43f9faff9..3d6c1a95204 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -58,16 +58,24 @@ //! borrowing from the outer closure, and we simply peel off a `deref` projection //! from them. This second body is stored alongside the first body, and optimized //! with it in lockstep. When we need to resolve a body for `FnOnce` or `AsyncFnOnce`, -//! we use this "by move" body instead. - -use itertools::Itertools; +//! we use this "by-move" body instead. +//! +//! ## How does this work? +//! +//! This pass essentially remaps the body of the (child) closure of the coroutine-closure +//! to take the set of upvars of the parent closure by value. This at least requires +//! changing a by-ref upvar to be by-value in the case that the outer coroutine-closure +//! captures something by value; however, it may also require renumbering field indices +//! in case precise captures (edition 2021 closure capture rules) caused the inner coroutine +//! to split one field capture into two. -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; +use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir, MirPass}; use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt}; -use rustc_target::abi::FieldIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; pub struct ByMoveBody; @@ -116,32 +124,56 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { .tuple_fields() .len(); - let mut by_ref_fields = UnordSet::default(); - for (idx, (coroutine_capture, parent_capture)) in tcx - .closure_captures(coroutine_def_id) - .iter() - // By construction we capture all the args first. - .skip(num_args) - .zip_eq(tcx.closure_captures(parent_def_id)) - .enumerate() - { - // This upvar is captured by-move from the parent closure, but by-ref - // from the inner async block. That means that it's being borrowed from - // the outer closure body -- we need to change the coroutine to take the - // upvar by value. - if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() { - assert_ne!( - coroutine_kind, - ty::ClosureKind::FnOnce, - "`FnOnce` coroutine-closures return coroutines that capture from \ - their body; it will always result in a borrowck error!" - ); - by_ref_fields.insert(FieldIdx::from_usize(num_args + idx)); - } - - // Make sure we're actually talking about the same capture. - // FIXME(async_closures): We could look at the `hir::Upvar` instead? - assert_eq!(coroutine_capture.place.ty(), parent_capture.place.ty()); + let field_remapping: UnordMap<_, _> = ty::analyze_coroutine_closure_captures( + tcx.closure_captures(parent_def_id).iter().copied(), + tcx.closure_captures(coroutine_def_id).iter().skip(num_args).copied(), + |(parent_field_idx, parent_capture), (child_field_idx, child_capture)| { + // Store this set of additional projections (fields and derefs). + // We need to re-apply them later. + let child_precise_captures = + &child_capture.place.projections[parent_capture.place.projections.len()..]; + + // If the parent captures by-move, and the child captures by-ref, then we + // need to peel an additional `deref` off of the body of the child. + let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref(); + if needs_deref { + assert_ne!( + coroutine_kind, + ty::ClosureKind::FnOnce, + "`FnOnce` coroutine-closures return coroutines that capture from \ + their body; it will always result in a borrowck error!" + ); + } + + // Finally, store the type of the parent's captured place. We need + // this when building the field projection in the MIR body later on. + let mut parent_capture_ty = parent_capture.place.ty(); + parent_capture_ty = match parent_capture.info.capture_kind { + ty::UpvarCapture::ByValue => parent_capture_ty, + ty::UpvarCapture::ByRef(kind) => Ty::new_ref( + tcx, + tcx.lifetimes.re_erased, + parent_capture_ty, + kind.to_mutbl_lossy(), + ), + }; + + ( + FieldIdx::from_usize(child_field_idx + num_args), + ( + FieldIdx::from_usize(parent_field_idx + num_args), + parent_capture_ty, + needs_deref, + child_precise_captures, + ), + ) + }, + ) + .collect(); + + if coroutine_kind == ty::ClosureKind::FnOnce { + assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len()); + return; } let by_move_coroutine_ty = tcx @@ -157,8 +189,9 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { ); let mut by_move_body = body.clone(); - MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body); + MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); + // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body. by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim { coroutine_def_id: coroutine_def_id.to_def_id(), }); @@ -168,7 +201,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { struct MakeByMoveBody<'tcx> { tcx: TyCtxt<'tcx>, - by_ref_fields: UnordSet<FieldIdx>, + field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>, by_move_coroutine_ty: Ty<'tcx>, } @@ -183,24 +216,57 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { context: mir::visit::PlaceContext, location: mir::Location, ) { + // Initializing an upvar local always starts with `CAPTURE_STRUCT_LOCAL` and a + // field projection. If this is in `field_remapping`, then it must not be an + // arg from calling the closure, but instead an upvar. if place.local == ty::CAPTURE_STRUCT_LOCAL - && let Some((&mir::ProjectionElem::Field(idx, ty), projection)) = + && let Some((&mir::ProjectionElem::Field(idx, _), projection)) = place.projection.split_first() - && self.by_ref_fields.contains(&idx) + && let Some(&(remapped_idx, remapped_ty, needs_deref, bridging_projections)) = + self.field_remapping.get(&idx) { - let (begin, end) = projection.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; + // As noted before, if the parent closure captures a field by value, and + // the child captures a field by ref, then for the by-move body we're + // generating, we also are taking that field by value. Peel off a deref, + // since a layer of ref'ing has now become redundant. + let final_projections = if needs_deref { + let Some((mir::ProjectionElem::Deref, projection)) = projection.split_first() + else { + bug!( + "There should be at least a single deref for an upvar local initialization, found {projection:#?}" + ); + }; + // There may be more derefs, since we may also implicitly reborrow + // a captured mut pointer. + projection + } else { + projection + }; + + // These projections are applied in order to "bridge" the local that we are + // currently transforming *from* the old upvar that the by-ref coroutine used + // to capture *to* the upvar of the parent coroutine-closure. For example, if + // the parent captures `&s` but the child captures `&(s.field)`, then we will + // apply a field projection. + let bridging_projections = bridging_projections.iter().map(|elem| match elem.kind { + ProjectionKind::Deref => mir::ProjectionElem::Deref, + ProjectionKind::Field(idx, VariantIdx::ZERO) => { + mir::ProjectionElem::Field(idx, elem.ty) + } + _ => unreachable!("precise captures only through fields and derefs"), + }); + + // We start out with an adjusted field index (and ty), representing the + // upvar that we get from our parent closure. We apply any of the additional + // projections to make sure that to the rest of the body of the closure, the + // place looks the same, and then apply that final deref if necessary. *place = mir::Place { local: place.local, projection: self.tcx.mk_place_elems_from_iter( - [mir::ProjectionElem::Field(idx, peeled_ty)] + [mir::ProjectionElem::Field(remapped_idx, remapped_ty)] .into_iter() - .chain(end.iter().copied()), + .chain(bridging_projections) + .chain(final_projections.iter().copied()), ), }; } diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 69dc4f2ddea..6e73a476421 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Debug}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index ed8c4d8283d..1895735ab35 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,7 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{self, Dominators}; -use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; +use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; @@ -193,16 +193,14 @@ impl IndexMut<BasicCoverageBlock> for CoverageGraph { impl graph::DirectedGraph for CoverageGraph { type Node = BasicCoverageBlock; -} -impl graph::WithNumNodes for CoverageGraph { #[inline] fn num_nodes(&self) -> usize { self.bcbs.len() } } -impl graph::WithStartNode for CoverageGraph { +impl graph::StartNode for CoverageGraph { #[inline] fn start_node(&self) -> Self::Node { self.bcb_from_bb(mir::START_BLOCK) @@ -210,28 +208,16 @@ impl graph::WithStartNode for CoverageGraph { } } -type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>; - -impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph { - type Item = BasicCoverageBlock; - type Iter = std::iter::Cloned<BcbSuccessors<'graph>>; -} - -impl graph::WithSuccessors for CoverageGraph { +impl graph::Successors for CoverageGraph { #[inline] - fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { + fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { self.successors[node].iter().cloned() } } -impl<'graph> graph::GraphPredecessors<'graph> for CoverageGraph { - type Item = BasicCoverageBlock; - type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicCoverageBlock>>; -} - -impl graph::WithPredecessors for CoverageGraph { +impl graph::Predecessors for CoverageGraph { #[inline] - fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { + fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { self.predecessors[node].iter().copied() } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 672de1fbe60..03ede886688 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::graph::DirectedGraph; use rustc_index::bit_set::BitSet; use rustc_middle::mir; use rustc_span::{BytePos, Span}; diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 569998de35e..cf1a2b399f9 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -28,8 +28,7 @@ use super::counters; use super::graph::{self, BasicCoverageBlock}; use itertools::Itertools; -use rustc_data_structures::graph::WithNumNodes; -use rustc_data_structures::graph::WithSuccessors; +use rustc_data_structures::graph::{DirectedGraph, Successors}; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::ty; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 3e9c1459f1c..d0f6ec8f21f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -684,6 +684,7 @@ fn try_write_constant<'tcx>( // Unsupported for now. ty::Array(_, _) + | ty::Pat(_, _) // Do not attempt to support indirection in constants. | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_) diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 0d600f0f937..9edb8bcee6e 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use std::fmt::Debug; use super::simplify::simplify_cfg; @@ -11,6 +11,7 @@ use super::simplify::simplify_cfg; /// let y: Option<()>; /// match (x,y) { /// (Some(_), Some(_)) => {0}, +/// (None, None) => {2}, /// _ => {1} /// } /// ``` @@ -23,10 +24,10 @@ use super::simplify::simplify_cfg; /// if discriminant_x == discriminant_y { /// match x { /// Some(_) => 0, -/// _ => 1, // <---- -/// } // | Actually the same bb -/// } else { // | -/// 1 // <-------------- +/// None => 2, +/// } +/// } else { +/// 1 /// } /// ``` /// @@ -47,18 +48,18 @@ use super::simplify::simplify_cfg; /// | | | /// ================= | | | /// | BBU | <-| | | ============================ -/// |---------------| | \-------> | BBD | -/// |---------------| | | |--------------------------| -/// | unreachable | | | | _dl = discriminant(P) | -/// ================= | | |--------------------------| -/// | | | switchInt(_dl) | -/// ================= | | | d | ---> BBD.2 +/// |---------------| \-------> | BBD | +/// |---------------| | |--------------------------| +/// | unreachable | | | _dl = discriminant(P) | +/// ================= | |--------------------------| +/// | | switchInt(_dl) | +/// ================= | | d | ---> BBD.2 /// | BB9 | <--------------- | otherwise | /// |---------------| ============================ /// | ... | /// ================= /// ``` -/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the +/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU`. In the /// code: /// - `BB1` is `parent` and `BBC, BBD` are children /// - `P` is `child_place` @@ -78,7 +79,7 @@ use super::simplify::simplify_cfg; /// |---------------------| | | switchInt(Q) | /// | switchInt(_t) | | | c | ---> BBC.2 /// | false | --------/ | d | ---> BBD.2 -/// | otherwise | ---------------- | otherwise | +/// | otherwise | /--------- | otherwise | /// ======================= | ============================ /// | /// ================= | @@ -87,16 +88,11 @@ use super::simplify::simplify_cfg; /// | ... | /// ================= /// ``` -/// -/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`. -/// The filter on which `P` are allowed (together with discussion of its correctness) is found in -/// `may_hoist`. pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // unsound: https://github.com/rust-lang/rust/issues/95162 - sess.mir_opt_level() >= 3 && sess.opts.unstable_opts.unsound_mir_opts + sess.mir_opt_level() >= 2 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -172,7 +168,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { }; (value, targets.target_for_value(value)) }); - let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination); + // The otherwise either is the same target branch or an unreachable. + let eq_targets = SwitchTargets::new(eq_new_targets, parent_targets.otherwise()); // Create `bbEq` in example above let eq_switch = BasicBlockData::new(Some(Terminator { @@ -217,85 +214,6 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { } } -/// Returns true if computing the discriminant of `place` may be hoisted out of the branch -fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool { - // FIXME(JakobDegen): This is unsound. Someone could write code like this: - // ```rust - // let Q = val; - // if discriminant(P) == otherwise { - // let ptr = &mut Q as *mut _ as *mut u8; - // unsafe { *ptr = 10; } // Any invalid value for the type - // } - // - // match P { - // A => match Q { - // A => { - // // code - // } - // _ => { - // // don't use Q - // } - // } - // _ => { - // // don't use Q - // } - // }; - // ``` - // - // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an - // invalid value, which is UB. - // - // In order to fix this, we would either need to show that the discriminant computation of - // `place` is computed in all branches, including the `otherwise` branch, or we would need - // another analysis pass to determine that the place is fully initialized. It might even be best - // to have the hoisting be performed in a different pass and just do the CFG changing in this - // pass. - for (place, proj) in place.iter_projections() { - match proj { - // Dereferencing in the computation of `place` might cause issues from one of two - // categories. First, the referent might be invalid. We protect against this by - // dereferencing references only (not pointers). Second, the use of a reference may - // invalidate other references that are used later (for aliasing reasons). Consider - // where such an invalidated reference may appear: - // - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so - // cannot contain referenced data. - // - In `BBU`: Not possible since that block contains only the `unreachable` terminator - // - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to - // reaching that block in the input to our transformation, and so any data - // invalidated by that computation could not have been used there. - // - In `BB9`: Not possible since control flow might have reached `BB9` via the - // `otherwise` branch in `BBC, BBD` in the input to our transformation, which would - // have invalidated the data when computing `discriminant(P)` - // So dereferencing here is correct. - ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() { - ty::Ref(..) => {} - _ => return false, - }, - // Field projections are always valid - ProjectionElem::Field(..) => {} - // We cannot allow - // downcasts either, since the correctness of the downcast may depend on the parent - // branch being taken. An easy example of this is - // ``` - // Q = discriminant(_3) - // P = (_3 as Variant) - // ``` - // However, checking if the child and parent place are the same and only erroring then - // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may - // be replaced by another optimization pass with any other condition that can be proven - // equivalent. - ProjectionElem::Downcast(..) => { - return false; - } - // We cannot allow indexing since the index may be out of bounds. - _ => { - return false; - } - } - } - true -} - #[derive(Debug)] struct OptimizationData<'tcx> { destination: BasicBlock, @@ -315,18 +233,40 @@ fn evaluate_candidate<'tcx>( return None; }; let parent_ty = parent_discr.ty(body.local_decls(), tcx); - let parent_dest = { - let poss = targets.otherwise(); - // If the fallthrough on the parent is trivially unreachable, we can let the - // children choose the destination - if bbs[poss].statements.len() == 0 - && bbs[poss].terminator().kind == TerminatorKind::Unreachable - { - None - } else { - Some(poss) - } - }; + if !bbs[targets.otherwise()].is_empty_unreachable() { + // Someone could write code like this: + // ```rust + // let Q = val; + // if discriminant(P) == otherwise { + // let ptr = &mut Q as *mut _ as *mut u8; + // // It may be difficult for us to effectively determine whether values are valid. + // // Invalid values can come from all sorts of corners. + // unsafe { *ptr = 10; } + // } + // + // match P { + // A => match Q { + // A => { + // // code + // } + // _ => { + // // don't use Q + // } + // } + // _ => { + // // don't use Q + // } + // }; + // ``` + // + // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an + // invalid value, which is UB. + // In order to fix this, **we would either need to show that the discriminant computation of + // `place` is computed in all branches**. + // FIXME(#95162) For the moment, we adopt a conservative approach and + // consider only the `otherwise` branch has no statements and an unreachable terminator. + return None; + } let (_, child) = targets.iter().next()?; let child_terminator = &bbs[child].terminator(); let TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr } = @@ -344,13 +284,7 @@ fn evaluate_candidate<'tcx>( let (_, Rvalue::Discriminant(child_place)) = &**boxed else { return None; }; - let destination = parent_dest.unwrap_or(child_targets.otherwise()); - - // Verify that the optimization is legal in general - // We can hoist evaluating the child discriminant out of the branch - if !may_hoist(tcx, body, *child_place) { - return None; - } + let destination = child_targets.otherwise(); // Verify that the optimization is legal for each branch for (value, child) in targets.iter() { @@ -411,5 +345,5 @@ fn verify_candidate_branch<'tcx>( if let Some(_) = iter.next() { return false; } - return true; + true } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 1b38eeccfad..ff786d44d6a 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -149,7 +149,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { fn simplify_ub_check(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue { - let const_ = Const::from_bool(self.tcx, self.tcx.sess.opts.debug_assertions); + let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); let constant = ConstOperand { span: source_info.span, const_, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 6d4332793af..4d9a198eeb2 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -1,11 +1,125 @@ +use rustc_index::IndexSlice; +use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; +use rustc_target::abi::Size; use std::iter; use super::simplify::simplify_cfg; pub struct MatchBranchSimplification; +impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 1 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let def_id = body.source.def_id(); + let param_env = tcx.param_env_reveal_all_normalized(def_id); + + let mut should_cleanup = false; + for i in 0..body.basic_blocks.len() { + let bbs = &*body.basic_blocks; + let bb_idx = BasicBlock::from_usize(i); + if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) { + continue; + } + + match bbs[bb_idx].terminator().kind { + TerminatorKind::SwitchInt { + discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)), + ref targets, + .. + // We require that the possible target blocks don't contain this block. + } if !targets.all_targets().contains(&bb_idx) => {} + // Only optimize switch int statements + _ => continue, + }; + + if SimplifyToIf.simplify(tcx, body, bb_idx, param_env).is_some() { + should_cleanup = true; + continue; + } + if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() { + should_cleanup = true; + continue; + } + } + + if should_cleanup { + simplify_cfg(body); + } + } +} + +trait SimplifyMatch<'tcx> { + /// Simplifies a match statement, returning true if the simplification succeeds, false otherwise. + /// Generic code is written here, and we generally don't need a custom implementation. + fn simplify( + &mut self, + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + switch_bb_idx: BasicBlock, + param_env: ParamEnv<'tcx>, + ) -> Option<()> { + let bbs = &body.basic_blocks; + let (discr, targets) = match bbs[switch_bb_idx].terminator().kind { + TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets), + _ => unreachable!(), + }; + + let discr_ty = discr.ty(body.local_decls(), tcx); + self.can_simplify(tcx, targets, param_env, bbs, discr_ty)?; + + let mut patch = MirPatch::new(body); + + // Take ownership of items now that we know we can optimize. + let discr = discr.clone(); + + // Introduce a temporary for the discriminant value. + let source_info = bbs[switch_bb_idx].terminator().source_info; + let discr_local = patch.new_temp(discr_ty, source_info.span); + + let (_, first) = targets.iter().next().unwrap(); + let statement_index = bbs[switch_bb_idx].statements.len(); + let parent_end = Location { block: switch_bb_idx, statement_index }; + patch.add_statement(parent_end, StatementKind::StorageLive(discr_local)); + patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr)); + self.new_stmts(tcx, targets, param_env, &mut patch, parent_end, bbs, discr_local, discr_ty); + patch.add_statement(parent_end, StatementKind::StorageDead(discr_local)); + patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone()); + patch.apply(body); + Some(()) + } + + /// Check that the BBs to be simplified satisfies all distinct and + /// that the terminator are the same. + /// There are also conditions for different ways of simplification. + fn can_simplify( + &mut self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_ty: Ty<'tcx>, + ) -> Option<()>; + + fn new_stmts( + &self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + patch: &mut MirPatch<'tcx>, + parent_end: Location, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_local: Local, + discr_ty: Ty<'tcx>, + ); +} + +struct SimplifyToIf; + /// If a source block is found that switches between two blocks that are exactly /// the same modulo const bool assignments (e.g., one assigns true another false /// to the same place), merge a target block statements into the source block, @@ -37,144 +151,350 @@ pub struct MatchBranchSimplification; /// goto -> bb3; /// } /// ``` +impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { + fn can_simplify( + &mut self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + _discr_ty: Ty<'tcx>, + ) -> Option<()> { + if targets.iter().len() != 1 { + return None; + } + // We require that the possible target blocks all be distinct. + let (_, first) = targets.iter().next().unwrap(); + let second = targets.otherwise(); + if first == second { + return None; + } + // Check that destinations are identical, and if not, then don't optimize this block + if bbs[first].terminator().kind != bbs[second].terminator().kind { + return None; + } -impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { - fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 1 - } + // Check that blocks are assignments of consts to the same place or same statement, + // and match up 1-1, if not don't optimize this block. + let first_stmts = &bbs[first].statements; + let second_stmts = &bbs[second].statements; + if first_stmts.len() != second_stmts.len() { + return None; + } + for (f, s) in iter::zip(first_stmts, second_stmts) { + match (&f.kind, &s.kind) { + // If two statements are exactly the same, we can optimize. + (f_s, s_s) if f_s == s_s => {} - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); + // If two statements are const bool assignments to the same place, we can optimize. + ( + StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s + && f_c.const_.ty().is_bool() + && s_c.const_.ty().is_bool() + && f_c.const_.try_eval_bool(tcx, param_env).is_some() + && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} - let bbs = body.basic_blocks.as_mut(); - let mut should_cleanup = false; - 'outer: for bb_idx in bbs.indices() { - if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) { - continue; + // Otherwise we cannot optimize. Try another block. + _ => return None, } + } + Some(()) + } - let (discr, val, first, second) = match bbs[bb_idx].terminator().kind { - TerminatorKind::SwitchInt { - discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)), - ref targets, - .. - } if targets.iter().len() == 1 => { - let (value, target) = targets.iter().next().unwrap(); - // We require that this block and the two possible target blocks all be - // distinct. - if target == targets.otherwise() - || bb_idx == target - || bb_idx == targets.otherwise() - { - continue; + fn new_stmts( + &self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + patch: &mut MirPatch<'tcx>, + parent_end: Location, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_local: Local, + discr_ty: Ty<'tcx>, + ) { + let (val, first) = targets.iter().next().unwrap(); + let second = targets.otherwise(); + // We already checked that first and second are different blocks, + // and bb_idx has a different terminator from both of them. + let first = &bbs[first]; + let second = &bbs[second]; + for (f, s) in iter::zip(&first.statements, &second.statements) { + match (&f.kind, &s.kind) { + (f_s, s_s) if f_s == s_s => { + patch.add_statement(parent_end, f.kind.clone()); + } + + ( + StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), + ) => { + // From earlier loop we know that we are dealing with bool constants only: + let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); + let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); + if f_b == s_b { + // Same value in both blocks. Use statement as is. + patch.add_statement(parent_end, f.kind.clone()); + } else { + // Different value between blocks. Make value conditional on switch condition. + let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; + let const_cmp = Operand::const_from_scalar( + tcx, + discr_ty, + rustc_const_eval::interpret::Scalar::from_uint(val, size), + rustc_span::DUMMY_SP, + ); + let op = if f_b { BinOp::Eq } else { BinOp::Ne }; + let rhs = Rvalue::BinaryOp( + op, + Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)), + ); + patch.add_assign(parent_end, *lhs, rhs); } - (discr, value, target, targets.otherwise()) } - // Only optimize switch int statements - _ => continue, - }; - // Check that destinations are identical, and if not, then don't optimize this block - if bbs[first].terminator().kind != bbs[second].terminator().kind { - continue; + _ => unreachable!(), } + } + } +} - // Check that blocks are assignments of consts to the same place or same statement, - // and match up 1-1, if not don't optimize this block. - let first_stmts = &bbs[first].statements; - let scnd_stmts = &bbs[second].statements; - if first_stmts.len() != scnd_stmts.len() { - continue; - } - for (f, s) in iter::zip(first_stmts, scnd_stmts) { - match (&f.kind, &s.kind) { - // If two statements are exactly the same, we can optimize. - (f_s, s_s) if f_s == s_s => {} +#[derive(Default)] +struct SimplifyToExp { + transfrom_types: Vec<TransfromType>, +} - // If two statements are const bool assignments to the same place, we can optimize. - ( - StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), - StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), - ) if lhs_f == lhs_s - && f_c.const_.ty().is_bool() - && s_c.const_.ty().is_bool() - && f_c.const_.try_eval_bool(tcx, param_env).is_some() - && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} +#[derive(Clone, Copy)] +enum CompareType<'tcx, 'a> { + /// Identical statements. + Same(&'a StatementKind<'tcx>), + /// Assignment statements have the same value. + Eq(&'a Place<'tcx>, Ty<'tcx>, ScalarInt), + /// Enum variant comparison type. + Discr { place: &'a Place<'tcx>, ty: Ty<'tcx>, is_signed: bool }, +} - // Otherwise we cannot optimize. Try another block. - _ => continue 'outer, - } - } - // Take ownership of items now that we know we can optimize. - let discr = discr.clone(); - let discr_ty = discr.ty(&body.local_decls, tcx); +enum TransfromType { + Same, + Eq, + Discr, +} + +impl From<CompareType<'_, '_>> for TransfromType { + fn from(compare_type: CompareType<'_, '_>) -> Self { + match compare_type { + CompareType::Same(_) => TransfromType::Same, + CompareType::Eq(_, _, _) => TransfromType::Eq, + CompareType::Discr { .. } => TransfromType::Discr, + } + } +} + +/// If we find that the value of match is the same as the assignment, +/// merge a target block statements into the source block, +/// using cast to transform different integer types. +/// +/// For example: +/// +/// ```ignore (MIR) +/// bb0: { +/// switchInt(_1) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1]; +/// } +/// +/// bb1: { +/// unreachable; +/// } +/// +/// bb2: { +/// _0 = const 1_i16; +/// goto -> bb5; +/// } +/// +/// bb3: { +/// _0 = const 2_i16; +/// goto -> bb5; +/// } +/// +/// bb4: { +/// _0 = const 3_i16; +/// goto -> bb5; +/// } +/// ``` +/// +/// into: +/// +/// ```ignore (MIR) +/// bb0: { +/// _0 = _3 as i16 (IntToInt); +/// goto -> bb5; +/// } +/// ``` +impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { + fn can_simplify( + &mut self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_ty: Ty<'tcx>, + ) -> Option<()> { + if targets.iter().len() < 2 || targets.iter().len() > 64 { + return None; + } + // We require that the possible target blocks all be distinct. + if !targets.is_distinct() { + return None; + } + if !bbs[targets.otherwise()].is_empty_unreachable() { + return None; + } + let mut target_iter = targets.iter(); + let (first_val, first_target) = target_iter.next().unwrap(); + let first_terminator_kind = &bbs[first_target].terminator().kind; + // Check that destinations are identical, and if not, then don't optimize this block + if !targets + .iter() + .all(|(_, other_target)| first_terminator_kind == &bbs[other_target].terminator().kind) + { + return None; + } - // Introduce a temporary for the discriminant value. - let source_info = bbs[bb_idx].terminator().source_info; - let discr_local = body.local_decls.push(LocalDecl::new(discr_ty, source_info.span)); + let discr_size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; + let first_stmts = &bbs[first_target].statements; + let (second_val, second_target) = target_iter.next().unwrap(); + let second_stmts = &bbs[second_target].statements; + if first_stmts.len() != second_stmts.len() { + return None; + } - // We already checked that first and second are different blocks, - // and bb_idx has a different terminator from both of them. - let (from, first, second) = bbs.pick3_mut(bb_idx, first, second); + fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool { + l.try_to_int(l.size()).unwrap() + == ScalarInt::try_from_uint(r, size).unwrap().try_to_int(size).unwrap() + } - let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| { - match (&f.kind, &s.kind) { - (f_s, s_s) if f_s == s_s => (*f).clone(), + // We first compare the two branches, and then the other branches need to fulfill the same conditions. + let mut compare_types = Vec::new(); + for (f, s) in iter::zip(first_stmts, second_stmts) { + let compare_type = match (&f.kind, &s.kind) { + // If two statements are exactly the same, we can optimize. + (f_s, s_s) if f_s == s_s => CompareType::Same(f_s), - ( - StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), - StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), - ) => { - // From earlier loop we know that we are dealing with bool constants only: - let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); - let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); - if f_b == s_b { - // Same value in both blocks. Use statement as is. - (*f).clone() - } else { - // Different value between blocks. Make value conditional on switch condition. - let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; - let const_cmp = Operand::const_from_scalar( - tcx, - discr_ty, - rustc_const_eval::interpret::Scalar::from_uint(val, size), - rustc_span::DUMMY_SP, - ); - let op = if f_b { BinOp::Eq } else { BinOp::Ne }; - let rhs = Rvalue::BinaryOp( - op, - Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)), - ); - Statement { - source_info: f.source_info, - kind: StatementKind::Assign(Box::new((*lhs, rhs))), + // If two statements are assignments with the match values to the same place, we can optimize. + ( + StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s + && f_c.const_.ty() == s_c.const_.ty() + && f_c.const_.ty().is_integral() => + { + match ( + f_c.const_.try_eval_scalar_int(tcx, param_env), + s_c.const_.try_eval_scalar_int(tcx, param_env), + ) { + (Some(f), Some(s)) if f == s => CompareType::Eq(lhs_f, f_c.const_.ty(), f), + // Enum variants can also be simplified to an assignment statement if their values are equal. + // We need to consider both unsigned and signed scenarios here. + (Some(f), Some(s)) + if ((f_c.const_.ty().is_signed() || discr_ty.is_signed()) + && int_equal(f, first_val, discr_size) + && int_equal(s, second_val, discr_size)) + || (Some(f) == ScalarInt::try_from_uint(first_val, f.size()) + && Some(s) + == ScalarInt::try_from_uint(second_val, s.size())) => + { + CompareType::Discr { + place: lhs_f, + ty: f_c.const_.ty(), + is_signed: f_c.const_.ty().is_signed() || discr_ty.is_signed(), } } + _ => { + return None; + } } + } + + // Otherwise we cannot optimize. Try another block. + _ => return None, + }; + compare_types.push(compare_type); + } - _ => unreachable!(), + // All remaining BBs need to fulfill the same pattern as the two BBs from the previous step. + for (other_val, other_target) in target_iter { + let other_stmts = &bbs[other_target].statements; + if compare_types.len() != other_stmts.len() { + return None; + } + for (f, s) in iter::zip(&compare_types, other_stmts) { + match (*f, &s.kind) { + (CompareType::Same(f_s), s_s) if f_s == s_s => {} + ( + CompareType::Eq(lhs_f, f_ty, val), + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s + && s_c.const_.ty() == f_ty + && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(val) => {} + ( + CompareType::Discr { place: lhs_f, ty: f_ty, is_signed }, + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty => { + let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) else { + return None; + }; + if is_signed + && s_c.const_.ty().is_signed() + && int_equal(f, other_val, discr_size) + { + continue; + } + if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) { + continue; + } + return None; + } + _ => return None, } - }); - - from.statements - .push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) }); - from.statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(discr_local), - Rvalue::Use(discr), - ))), - }); - from.statements.extend(new_stmts); - from.statements - .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) }); - from.terminator_mut().kind = first.terminator().kind.clone(); - should_cleanup = true; + } } + self.transfrom_types = compare_types.into_iter().map(|c| c.into()).collect(); + Some(()) + } - if should_cleanup { - simplify_cfg(body); + fn new_stmts( + &self, + _tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + _param_env: ParamEnv<'tcx>, + patch: &mut MirPatch<'tcx>, + parent_end: Location, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_local: Local, + discr_ty: Ty<'tcx>, + ) { + let (_, first) = targets.iter().next().unwrap(); + let first = &bbs[first]; + + for (t, s) in iter::zip(&self.transfrom_types, &first.statements) { + match (t, &s.kind) { + (TransfromType::Same, _) | (TransfromType::Eq, _) => { + patch.add_statement(parent_end, s.kind.clone()); + } + ( + TransfromType::Discr, + StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), + ) => { + let operand = Operand::Copy(Place::from(discr_local)); + let r_val = if f_c.const_.ty() == discr_ty { + Rvalue::Use(operand) + } else { + Rvalue::Cast(CastKind::IntToInt, operand, f_c.const_.ty()) + }; + patch.add_assign(parent_end, *lhs, r_val); + } + _ => unreachable!(), + } } } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 0c35f9838ed..36d623fd93e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,8 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +mod move_check; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock}; use rustc_hir as hir; @@ -214,6 +216,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::mir::traversal; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Location, MentionedItem}; use rustc_middle::query::TyCtxtAt; @@ -226,7 +229,6 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_session::config::EntryFnType; -use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Spanned}; use rustc_span::symbol::{sym, Ident}; @@ -235,9 +237,9 @@ use rustc_target::abi::Size; use std::path::PathBuf; use crate::errors::{ - self, EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit, - TypeLengthLimit, + self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit, }; +use move_check::MoveCheckState; #[derive(PartialEq)] pub enum MonoItemCollectionStrategy { @@ -666,11 +668,8 @@ struct MirUsedCollector<'a, 'tcx> { /// Note that this contains *not-monomorphized* items! used_mentioned_items: &'a mut FxHashSet<MentionedItem<'tcx>>, instance: Instance<'tcx>, - /// Spans for move size lints already emitted. Helps avoid duplicate lints. - move_size_spans: Vec<Span>, visiting_call_terminator: bool, - /// Set of functions for which it is OK to move large data into. - skip_move_check_fns: Option<Vec<DefId>>, + move_check: move_check::MoveCheckState, } impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { @@ -686,124 +685,6 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { ) } - fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - let limit = self.tcx.move_size_limit(); - if limit.0 == 0 { - return; - } - - // This function is called by visit_operand() which visits _all_ - // operands, including TerminatorKind::Call operands. But if - // check_fn_args_move_size() has been called, the operands have already - // been visited. Do not visit them again. - if self.visiting_call_terminator { - return; - } - - let source_info = self.body.source_info(location); - debug!(?source_info); - - if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { - self.lint_large_assignment(limit.0, too_large_size, location, source_info.span); - }; - } - - fn check_fn_args_move_size( - &mut self, - callee_ty: Ty<'tcx>, - args: &[Spanned<mir::Operand<'tcx>>], - fn_span: Span, - location: Location, - ) { - let limit = self.tcx.move_size_limit(); - if limit.0 == 0 { - return; - } - - if args.is_empty() { - return; - } - - // Allow large moves into container types that themselves are cheap to move - let ty::FnDef(def_id, _) = *callee_ty.kind() else { - return; - }; - if self - .skip_move_check_fns - .get_or_insert_with(|| build_skip_move_check_fns(self.tcx)) - .contains(&def_id) - { - return; - } - - debug!(?def_id, ?fn_span); - - for arg in args { - // Moving args into functions is typically implemented with pointer - // passing at the llvm-ir level and not by memcpy's. So always allow - // moving args into functions. - let operand: &mir::Operand<'tcx> = &arg.node; - if let mir::Operand::Move(_) = operand { - continue; - } - - if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { - self.lint_large_assignment(limit.0, too_large_size, location, arg.span); - }; - } - } - - fn operand_size_if_too_large( - &mut self, - limit: Limit, - operand: &mir::Operand<'tcx>, - ) -> Option<Size> { - let ty = operand.ty(self.body, self.tcx); - let ty = self.monomorphize(ty); - let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { - return None; - }; - if layout.size.bytes_usize() > limit.0 { - debug!(?layout); - Some(layout.size) - } else { - None - } - } - - fn lint_large_assignment( - &mut self, - limit: usize, - too_large_size: Size, - location: Location, - span: Span, - ) { - let source_info = self.body.source_info(location); - debug!(?source_info); - for reported_span in &self.move_size_spans { - if reported_span.overlaps(span) { - return; - } - } - let lint_root = source_info.scope.lint_root(&self.body.source_scopes); - debug!(?lint_root); - let Some(lint_root) = lint_root else { - // This happens when the issue is in a function from a foreign crate that - // we monomorphized in the current crate. We can't get a `HirId` for things - // in other crates. - // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root - // but correct span? This would make the lint at least accept crate-level lint attributes. - return; - }; - self.tcx.emit_node_span_lint( - LARGE_ASSIGNMENTS, - lint_root, - span, - LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, - ); - self.move_size_spans.push(span); - } - /// Evaluates a *not yet monomorphized* constant. fn eval_constant( &mut self, @@ -1366,19 +1247,6 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> return None; } -fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> { - let fns = [ - (tcx.lang_items().owned_box(), "new"), - (tcx.get_diagnostic_item(sym::Rc), "new"), - (tcx.get_diagnostic_item(sym::Arc), "new"), - ]; - fns.into_iter() - .filter_map(|(def_id, fn_name)| { - def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name))) - }) - .collect::<Vec<_>>() -} - /// Scans the MIR in order to find function calls, closures, and drop-glue. /// /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned. @@ -1408,21 +1276,21 @@ fn collect_items_of_instance<'tcx>( used_items, used_mentioned_items: &mut used_mentioned_items, instance, - move_size_spans: vec![], visiting_call_terminator: false, - skip_move_check_fns: None, + move_check: MoveCheckState::new(), }; if mode == CollectionMode::UsedItems { - // Visit everything. Here we rely on the visitor also visiting `required_consts`, so that we - // evaluate them and abort compilation if any of them errors. - collector.visit_body(body); - } else { - // We only need to evaluate all constants, but can ignore the rest of the MIR. - for const_op in &body.required_consts { - if let Some(val) = collector.eval_constant(const_op) { - collect_const_value(tcx, val, mentioned_items); - } + for (bb, data) in traversal::mono_reachable(body, tcx, instance) { + collector.visit_basic_block_data(bb, data) + } + } + + // Always visit all `required_consts`, so that we evaluate them and abort compilation if any of + // them errors. + for const_op in &body.required_consts { + if let Some(val) = collector.eval_constant(const_op) { + collect_const_value(tcx, val, mentioned_items); } } diff --git a/compiler/rustc_monomorphize/src/collector/move_check.rs b/compiler/rustc_monomorphize/src/collector/move_check.rs new file mode 100644 index 00000000000..4cc7275ab80 --- /dev/null +++ b/compiler/rustc_monomorphize/src/collector/move_check.rs @@ -0,0 +1,155 @@ +use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; + +use super::*; +use crate::errors::LargeAssignmentsLint; + +pub(super) struct MoveCheckState { + /// Spans for move size lints already emitted. Helps avoid duplicate lints. + move_size_spans: Vec<Span>, + /// Set of functions for which it is OK to move large data into. + skip_move_check_fns: Option<Vec<DefId>>, +} + +impl MoveCheckState { + pub(super) fn new() -> Self { + MoveCheckState { move_size_spans: vec![], skip_move_check_fns: None } + } +} + +impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { + pub(super) fn check_operand_move_size( + &mut self, + operand: &mir::Operand<'tcx>, + location: Location, + ) { + let limit = self.tcx.move_size_limit(); + if limit.0 == 0 { + return; + } + + // This function is called by visit_operand() which visits _all_ + // operands, including TerminatorKind::Call operands. But if + // check_fn_args_move_size() has been called, the operands have already + // been visited. Do not visit them again. + if self.visiting_call_terminator { + return; + } + + let source_info = self.body.source_info(location); + debug!(?source_info); + + if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { + self.lint_large_assignment(limit.0, too_large_size, location, source_info.span); + }; + } + + pub(super) fn check_fn_args_move_size( + &mut self, + callee_ty: Ty<'tcx>, + args: &[Spanned<mir::Operand<'tcx>>], + fn_span: Span, + location: Location, + ) { + let limit = self.tcx.move_size_limit(); + if limit.0 == 0 { + return; + } + + if args.is_empty() { + return; + } + + // Allow large moves into container types that themselves are cheap to move + let ty::FnDef(def_id, _) = *callee_ty.kind() else { + return; + }; + if self + .move_check + .skip_move_check_fns + .get_or_insert_with(|| build_skip_move_check_fns(self.tcx)) + .contains(&def_id) + { + return; + } + + debug!(?def_id, ?fn_span); + + for arg in args { + // Moving args into functions is typically implemented with pointer + // passing at the llvm-ir level and not by memcpy's. So always allow + // moving args into functions. + let operand: &mir::Operand<'tcx> = &arg.node; + if let mir::Operand::Move(_) = operand { + continue; + } + + if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { + self.lint_large_assignment(limit.0, too_large_size, location, arg.span); + }; + } + } + + fn operand_size_if_too_large( + &mut self, + limit: Limit, + operand: &mir::Operand<'tcx>, + ) -> Option<Size> { + let ty = operand.ty(self.body, self.tcx); + let ty = self.monomorphize(ty); + let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { + return None; + }; + if layout.size.bytes_usize() > limit.0 { + debug!(?layout); + Some(layout.size) + } else { + None + } + } + + fn lint_large_assignment( + &mut self, + limit: usize, + too_large_size: Size, + location: Location, + span: Span, + ) { + let source_info = self.body.source_info(location); + debug!(?source_info); + for reported_span in &self.move_check.move_size_spans { + if reported_span.overlaps(span) { + return; + } + } + let lint_root = source_info.scope.lint_root(&self.body.source_scopes); + debug!(?lint_root); + let Some(lint_root) = lint_root else { + // This happens when the issue is in a function from a foreign crate that + // we monomorphized in the current crate. We can't get a `HirId` for things + // in other crates. + // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root + // but correct span? This would make the lint at least accept crate-level lint attributes. + return; + }; + self.tcx.emit_node_span_lint( + LARGE_ASSIGNMENTS, + lint_root, + span, + LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, + ); + self.move_check.move_size_spans.push(span); + } +} + +fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> { + let fns = [ + (tcx.lang_items().owned_box(), "new"), + (tcx.get_diagnostic_item(sym::Rc), "new"), + (tcx.get_diagnostic_item(sym::Arc), "new"), + ]; + fns.into_iter() + .filter_map(|(def_id, fn_name)| { + def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name))) + }) + .collect::<Vec<_>>() +} diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 1899517c0e2..6600b92fb31 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -69,7 +69,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc let (max_universe, variables) = canonicalizer.finalize(); - Canonical { max_universe, variables, value } + let defining_opaque_types = infcx.defining_opaque_types(); + Canonical { defining_opaque_types, max_universe, variables, value } } fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) { @@ -349,6 +350,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) + | ty::Pat(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 69b48bf0aff..1c1ca0bac81 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -34,8 +34,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char}; rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12); #[derive(Clone, Debug)] -pub struct UnmatchedDelim { - pub expected_delim: Delimiter, +pub(crate) struct UnmatchedDelim { pub found_delim: Option<Delimiter>, pub found_span: Span, pub unclosed_span: Option<Span>, @@ -698,7 +697,6 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let expn_data = prefix_span.ctxt().outer_expn_data(); if expn_data.edition >= Edition::Edition2021 { - let mut silence = false; // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) @@ -706,25 +704,20 @@ impl<'psess, 'src> StringReader<'psess, 'src> { if self.cursor.first() == '\'' && let Some(start) = self.last_lifetime && self.cursor.third() != '\'' + && let end = self.mk_sp(self.pos, self.pos + BytePos(1)) + && !self.psess.source_map().is_multiline(start.until(end)) { - // An "unclosed `char`" error will be emitted already, silence redundant error. - silence = true; - Some(errors::UnknownPrefixSugg::MeantStr { - start, - end: self.mk_sp(self.pos, self.pos + BytePos(1)), - }) + // FIXME: An "unclosed `char`" error will be emitted already in some cases, + // but it's hard to silence this error while not also silencing important cases + // too. We should use the error stashing machinery instead. + Some(errors::UnknownPrefixSugg::MeantStr { start, end }) } else { Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) } } else { None }; - let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg }; - if silence { - self.dcx().create_err(err).delay_as_bug(); - } else { - self.dcx().emit_err(err); - } + self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg }); } else { // Before Rust 2021, only emit a lint for migration. self.psess.buffer_lint_with_diagnostic( diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index a506f98bf3a..b5a5a2a90ee 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -77,7 +77,6 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); self.diag_info.unmatched_delims.push(UnmatchedDelim { - expected_delim: Delimiter::Brace, found_delim: None, found_span: self.token.span, unclosed_span: Some(sp), @@ -163,9 +162,8 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { candidate = Some(*brace_span); } } - let (tok, _) = self.diag_info.open_braces.pop().unwrap(); + let (_, _) = self.diag_info.open_braces.pop().unwrap(); self.diag_info.unmatched_delims.push(UnmatchedDelim { - expected_delim: tok, found_delim: Some(close_delim), found_span: self.token.span, unclosed_span: unclosed_delimiter, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 012285e4644..00947a4c585 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3585,8 +3585,7 @@ impl<'a> Parser<'a> { match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { Ok(_) => { - if let Some(f) = - parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar)).ok() + if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar)) { // Only include the field if there's no parse error for the field name. fields.push(f); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 80f2078fff2..51f288b3c95 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -153,7 +153,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.insert_def_id(def.non_enum_variant().fields[index].did); } ty::Tuple(..) => {} - _ => span_bug!(lhs.span, "named field access on non-ADT"), + ty::Error(_) => {} + kind => span_bug!(lhs.span, "named field access on non-ADT: {kind:?}"), } } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index dd6c1166957..51a69809c7a 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -161,4 +161,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { let mut inner_visitor = self.new_visitor(self.tcx); inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i)); } + + fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { + self.visit_pat(p) + } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e6e52648d6f..72c6a714e4d 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -352,6 +352,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { TraitObject, Typeof, Infer, + Pat, Err ] ); @@ -611,6 +612,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { AnonStruct, AnonUnion, Path, + Pat, TraitObject, ImplTrait, Paren, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 467f09e4c29..548a7b43005 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -399,6 +399,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { | ty::RawPtr(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) + | ty::Pat(_, _) | ty::Dynamic(_, _, _) | ty::Closure(..) | ty::CoroutineClosure(..) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 41d63407418..2039e994aaa 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -276,6 +276,7 @@ where | ty::Tuple(..) | ty::RawPtr(..) | ty::Ref(..) + | ty::Pat(..) | ty::FnPtr(..) | ty::Param(..) | ty::Bound(..) diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 52767155532..3373835d813 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -13,6 +13,7 @@ extern crate rustc_middle; use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green}; +use crate::profiling_support::QueryKeyStringCache; use field_offset::offset_of; use rustc_data_structures::stable_hasher::HashStable; use rustc_data_structures::sync::AtomicU64; @@ -21,9 +22,7 @@ use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::dep_graph::{self, DepKind, DepKindStruct}; use rustc_middle::query::erase::{erase, restore, Erase}; use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; -use rustc_middle::query::plumbing::{ - DynamicQuery, QueryKeyStringCache, QuerySystem, QuerySystemFns, -}; +use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns}; use rustc_middle::query::AsLocalKey; use rustc_middle::query::{ queries, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index fbc6db93e01..e0d7a4f0451 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -1,13 +1,23 @@ use measureme::{StringComponent, StringId}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; -use rustc_middle::query::plumbing::QueryKeyStringCache; use rustc_middle::ty::TyCtxt; use rustc_query_system::query::QueryCache; use std::fmt::Debug; use std::io::Write; +pub(crate) struct QueryKeyStringCache { + def_id_cache: FxHashMap<DefId, StringId>, +} + +impl QueryKeyStringCache { + fn new() -> QueryKeyStringCache { + QueryKeyStringCache { def_id_cache: Default::default() } + } +} + struct QueryKeyStringBuilder<'p, 'tcx> { profiler: &'p SelfProfiler, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 2bc7cb99547..6042aa6a2d2 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -541,12 +541,7 @@ impl<D: Deps> EncoderState<D> { record_graph: &Option<Lock<DepGraphQuery>>, ) -> DepNodeIndex { node.encode::<D>(&mut self.encoder); - self.record( - node.node, - node.edges.len(), - |_| node.edges[..].iter().copied().collect(), - record_graph, - ) + self.record(node.node, node.edges.len(), |_| node.edges[..].to_vec(), record_graph) } /// Encodes a node that was promoted from the previous graph. It reads the information directly from diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index c3fc036aed3..acc29b67ccc 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -101,7 +101,7 @@ where } pub struct VecCache<K: Idx, V> { - cache: Sharded<IndexVec<K, Option<(V, DepNodeIndex)>>>, + cache: Lock<IndexVec<K, Option<(V, DepNodeIndex)>>>, } impl<K: Idx, V> Default for VecCache<K, V> { @@ -120,24 +120,20 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - // FIXME: lock_shard_by_hash will use high bits which are usually zero in the index() passed - // here. This makes sharding essentially useless, always selecting the zero'th shard. - let lock = self.cache.lock_shard_by_hash(key.index() as u64); + let lock = self.cache.lock(); if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None } } #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.lock_shard_by_hash(key.index() as u64); + let mut lock = self.cache.lock(); lock.insert(key, (value, index)); } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - for shard in self.cache.lock_shards() { - for (k, v) in shard.iter_enumerated() { - if let Some(v) = v { - f(&k, &v.0, v.1); - } + for (k, v) in self.cache.lock().iter_enumerated() { + if let Some(v) = v { + f(&k, &v.0, v.1); } } } @@ -149,9 +145,6 @@ pub struct DefIdCache<V> { /// /// The second element of the tuple is the set of keys actually present in the IndexVec, used /// for faster iteration in `iter()`. - // FIXME: This may want to be sharded, like VecCache. However *how* to shard an IndexVec isn't - // super clear; VecCache is effectively not sharded today (see FIXME there). For now just omit - // that complexity here. local: Lock<(IndexVec<DefIndex, Option<(V, DepNodeIndex)>>, Vec<DefIndex>)>, foreign: DefaultCache<DefId, V>, } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index a03bb6acd41..f824e4faf5d 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -11,6 +11,8 @@ resolve_added_macro_use = resolve_ancestor_only = visibilities can only be restricted to ancestor modules +resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here + resolve_associated_const_with_similar_name_exists = there is an associated constant with a similar name @@ -20,6 +22,10 @@ resolve_associated_fn_with_similar_name_exists = resolve_associated_type_with_similar_name_exists = there is an associated type with a similar name +resolve_attempt_to_define_builtin_macro_twice = + attempted to define built-in macro more than once + .note = previously defined here + resolve_attempt_to_use_non_constant_value_in_constant = attempt to use a non-constant value in a constant @@ -32,6 +38,11 @@ resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion = resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion = this would need to be a `{$suggestion}` +resolve_attributes_starting_with_rustc_are_reserved = + attributes starting with `rustc` are reserved for use by the `rustc` compiler + +resolve_bad_macro_import = bad macro import + resolve_binding_in_never_pattern = never patterns cannot contain variable bindings .suggestion = use a wildcard `_` instead @@ -62,12 +73,19 @@ resolve_cannot_determine_macro_resolution = cannot determine resolution for the {$kind} `{$path}` .note = import resolution is stuck, try simplifying macro imports +resolve_cannot_find_builtin_macro_with_name = + cannot find a built-in macro with name `{$ident}` + resolve_cannot_find_ident_in_this_scope = cannot find {$expected} `{$ident}` in this scope resolve_cannot_glob_import_possible_crates = cannot glob-import all possible crates +resolve_cannot_use_through_an_import = + cannot use {$article} {$descr} through an import + .note = the {$descr} imported here + resolve_change_import_binding = you can use `as` to change the binding name of the import @@ -80,6 +98,12 @@ resolve_consider_adding_macro_export = resolve_consider_declaring_with_pub = consider declaring type or module `{$ident}` with `pub` +resolve_consider_making_the_field_public = + { $number_of_fields -> + [one] consider making the field publicly accessible + *[other] consider making the fields publicly accessible + } + resolve_consider_marking_as_pub = consider marking `{$ident}` as `pub` in the imported module @@ -100,17 +124,44 @@ resolve_const_param_in_non_trivial_anon_const = resolve_const_param_in_ty_of_const_param = const parameters may not be used in the type of const parameters -resolve_expected_found = +resolve_constructor_private_if_any_field_private = + a constructor is private if any of the fields is private + +resolve_elided_anonymous_lifetime_report_error = + `&` without an explicit lifetime name cannot be used here + .label = explicit lifetime name needed here + +resolve_elided_anonymous_lifetime_report_error_suggestion = + consider introducing a higher-ranked lifetime here + +resolve_expected_module_found = expected module, found {$res} `{$path_str}` .label = not a module +resolve_explicit_anonymous_lifetime_report_error = + `'_` cannot be used here + .label = `'_` is a reserved lifetime name + resolve_explicit_unsafe_traits = unsafe traits like `{$ident}` should be implemented explicitly +resolve_extern_crate_loading_macro_not_at_crate_root = + an `extern crate` loading macros must be at the crate root + +resolve_extern_crate_self_requires_renaming = + `extern crate self;` requires renaming + .suggestion = rename the `self` crate to be able to import it + resolve_forward_declared_generic_param = generic parameters with a default cannot use forward declared identifiers .label = defaulted generic parameters cannot be forward declared +resolve_found_an_item_configured_out = + found an item that was configured out + +resolve_generic_arguments_in_macro_path = + generic arguments in macro path + resolve_generic_params_from_outer_item = can't use {$is_self -> [true] `Self` @@ -135,7 +186,6 @@ resolve_generic_params_from_outer_item_static = a `static` is a separate item fr resolve_generic_params_from_outer_item_ty_param = type parameter from outer item - resolve_ident_bound_more_than_once_in_parameter_list = identifier `{$identifier}` is bound more than once in this parameter list .label = used as parameter more than once @@ -144,8 +194,18 @@ resolve_ident_bound_more_than_once_in_same_pattern = identifier `{$identifier}` is bound more than once in the same pattern .label = used in a pattern more than once +resolve_ident_imported_here_but_it_is_desc = + `{$imported_ident}` is imported here, but it is {$imported_ident_desc} + +resolve_ident_in_scope_but_it_is_desc = + `{$imported_ident}` is in scope, but it is {$imported_ident_desc} + +resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here + resolve_imported_crate = `$crate` may not be imported +resolve_imported_macro_not_found = imported macro not found + resolve_imports_cannot_refer_to = imports cannot refer to {$what} @@ -161,6 +221,13 @@ resolve_is_not_directly_importable = `{$target}` is not directly importable .label = cannot be imported directly +resolve_is_private = + {$ident_descr} `{$ident}` is private + .label = private {$ident_descr} + +resolve_item_was_behind_feature = + the item is gated behind the `{$feature}` feature + resolve_items_in_traits_are_not_importable = items in traits are not importable @@ -183,11 +250,23 @@ resolve_lowercase_self = resolve_macro_defined_later = a macro with the same name exists, but it appears later at here +resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments = + macro-expanded `extern crate` items cannot shadow names passed with `--extern` + resolve_macro_expected_found = expected {$expected}, found {$found} `{$macro_path}` + .label = not {$article} {$expected} + +resolve_macro_extern_deprecated = + `#[macro_escape]` is a deprecated synonym for `#[macro_use]` + .help = try an outer attribute: `#[macro_use]` resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self` +resolve_macro_use_name_already_in_use = + `{$name}` is already in scope + .note = macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560) + resolve_method_not_member_of_trait = method `{$method}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` @@ -197,11 +276,45 @@ resolve_missing_macro_rules_name = maybe you have forgotten to define a name for resolve_module_only = visibility must resolve to a module +resolve_name_defined_multiple_time = + the name `{$name}` is defined multiple times + .note = `{$name}` must be defined only once in the {$descr} namespace of this {$container} + +resolve_name_defined_multiple_time_old_binding_definition = + previous definition of the {$old_kind} `{$name}` here + +resolve_name_defined_multiple_time_old_binding_import = + previous import of the {$old_kind} `{$name}` here + +resolve_name_defined_multiple_time_redefined = + `{$name}` redefined here + +resolve_name_defined_multiple_time_reimported = + `{$name}` reimported here + resolve_name_is_already_used_as_generic_parameter = the name `{$name}` is already used for a generic parameter in this item's generic parameters .label = already used .first_use_of_name = first use of `{$name}` +resolve_name_reserved_in_attribute_namespace = + name `{$ident}` is reserved in attribute namespace + +resolve_note_and_refers_to_the_item_defined_here = + {$first -> + [true] {$dots -> + [true] the {$binding_descr} `{$binding_name}` is defined here... + *[false] the {$binding_descr} `{$binding_name}` is defined here + } + *[false] {$dots -> + [true] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here... + *[false] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here + } + } + +resolve_outer_ident_is_not_publicly_reexported = + {$outer_ident_descr} `{$outer_ident}` is not publicly re-exported + resolve_param_in_enum_discriminant = generic parameters may not be used in enum discriminant values .label = cannot perform const operation using `{$name}` @@ -217,6 +330,8 @@ resolve_param_in_ty_of_const_param = the type of const parameters must not depend on other generic parameters .label = the type must not depend on the parameter `{$name}` +resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}` + resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it .help = you can define integration tests in a directory named `tests` @@ -233,6 +348,8 @@ resolve_relative_2018 = resolve_remove_surrounding_derive = remove from the surrounding `derive()` +resolve_remove_unnecessary_import = remove unnecessary import + resolve_self_import_can_only_appear_once_in_the_list = `self` import can only appear once in an import list .label = can only appear once in an import list @@ -254,16 +371,43 @@ resolve_self_in_generic_param_default = generic parameters cannot use `Self` in their defaults .label = `Self` in generic parameter default +resolve_similarly_named_defined_here = + similarly named {$candidate_descr} `{$candidate}` defined here + +resolve_single_item_defined_here = + {$candidate_descr} `{$candidate}` defined here + +resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$lifetime}` + .label = 'static is a reserved lifetime name + +resolve_suggestion_import_ident_directly = + import `{$ident}` directly + +resolve_suggestion_import_ident_through_reexport = + import `{$ident}` through the re-export + resolve_tool_module_imported = cannot use a tool module through an import .note = the tool module imported here +resolve_tool_only_accepts_identifiers = + `{$tool}` only accepts identifiers + .label = not an identifier + +resolve_tool_was_already_registered = + tool `{$tool}` was already registered + .label = already registered here + resolve_trait_impl_duplicate = duplicate definitions with name `{$name}`: .label = duplicate definition .old_span_label = previous definition here .trait_item_span = item in trait +resolve_trait_impl_mismatch = + item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}` + .label = does not match trait + .trait_impl_mismatch_label_item = item in trait resolve_try_using_similarly_named_label = try using similarly named label @@ -284,12 +428,18 @@ resolve_undeclared_label = use of undeclared label `{$name}` .label = undeclared label `{$name}` +resolve_underscore_lifetime_is_reserved = `'_` cannot be used here + .label = `'_` 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_unnamed_crate_root_import = + crate root imports need to be explicitly named: `use crate as name;` + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` @@ -312,3 +462,8 @@ resolve_variable_bound_with_different_mode = variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` .label = bound in different ways .first_binding_span = first binding + +resolve_variable_is_not_bound_in_all_patterns = + variable `{$name}` is not bound in all patterns + +resolve_variable_not_in_all_patterns = variable not in all patterns diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 375f20dd809..1b6387acf71 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -19,7 +19,6 @@ 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::{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}; @@ -529,11 +528,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } if ident.name == kw::Crate { - self.r.dcx().span_err( - ident.span, - "crate root imports need to be explicitly named: \ - `use crate as name;`", - ); + self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span }); } let kind = ImportKind::Single { @@ -848,16 +843,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let expansion = parent_scope.expansion; let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower { - self.r - .dcx() - .struct_span_err(item.span, "`extern crate self;` requires renaming") - .with_span_suggestion( - item.span, - "rename the `self` crate to be able to import it", - "extern crate self as name;", - Applicability::HasPlaceholders, - ) - .emit(); + self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp }); return; } else if orig_name == Some(kw::SelfLower) { Some(self.r.graph_root) @@ -897,9 +883,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if parent == self.r.graph_root { if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { - let msg = "macro-expanded `extern crate` items cannot \ - shadow names passed with `--extern`"; - self.r.dcx().span_err(item.span, msg); + self.r.dcx().emit_err( + errors::MacroExpandedExternCrateCannotShadowExternArguments { + span: item.span, + }, + ); // `return` is intended to discard this binding because it's an // unregistered ambiguity error which would result in a panic // caused by inconsistency `path_res` @@ -1030,10 +1018,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { allow_shadowing: bool, ) { if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { - let msg = format!("`{name}` is already in scope"); - let note = - "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - self.r.dcx().struct_span_err(span, msg).with_note(note).emit(); + self.r.dcx().emit_err(errors::MacroUseNameAlreadyInUse { span, name }); } } @@ -1044,13 +1029,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { for attr in &item.attrs { if attr.has_name(sym::macro_use) { if self.parent_scope.module.parent.is_some() { - struct_span_code_err!( - self.r.dcx(), - item.span, - E0468, - "an `extern crate` loading macros must be at the crate root" - ) - .emit(); + self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { + span: item.span, + }); } if let ItemKind::ExternCrate(Some(orig_name)) = item.kind { if orig_name == kw::SelfLower { @@ -1058,7 +1039,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } let ill_formed = |span| { - struct_span_code_err!(self.r.dcx(), span, E0466, "bad macro import").emit(); + self.r.dcx().emit_err(errors::BadMacroImport { span }); }; match attr.meta() { Some(meta) => match meta.kind { @@ -1143,13 +1124,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { allow_shadowing, ); } else { - struct_span_code_err!( - self.r.dcx(), - ident.span, - E0469, - "imported macro not found" - ) - .emit(); + self.r.dcx().emit_err(errors::ImportedMacroNotFound { span: ident.span }); } } } @@ -1160,18 +1135,16 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { if attr.has_name(sym::macro_escape) { - let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`"; - let mut err = self.r.dcx().struct_span_warn(attr.span, msg); - if let ast::AttrStyle::Inner = attr.style { - err.help("try an outer attribute: `#[macro_use]`"); - } - err.emit(); + let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner).then_some(()); + self.r + .dcx() + .emit_warn(errors::MacroExternDeprecated { span: attr.span, inner_attribute }); } else if !attr.has_name(sym::macro_use) { continue; } if !attr.is_word() { - self.r.dcx().span_err(attr.span, "arguments to `macro_use` are not allowed here"); + self.r.dcx().emit_err(errors::ArgumentsMacroUseNotAllowed { span: attr.span }); } return true; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4057bc9ffbd..12484462f82 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::{ - codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, Diag, - DiagCtxt, ErrorGuaranteed, MultiSpan, SuggestionStyle, + codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxt, + ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -29,10 +29,9 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::{thin_vec, ThinVec}; -use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion}; use crate::errors::{ - ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, - MaybeMissingMacroRulesName, + self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, + ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, MaybeMissingMacroRulesName, }; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; @@ -226,16 +225,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ModuleKind::Block => "block", }; - let old_noun = match old_binding.is_import_user_facing() { - true => "import", - false => "definition", - }; - - let new_participle = match new_binding.is_import_user_facing() { - true => "imported", - false => "defined", - }; - let (name, span) = (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span)); @@ -254,35 +243,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (TypeNS, _) => "type", }; - let msg = format!("the name `{name}` is defined multiple times"); - - let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { - (true, true) => struct_span_code_err!(self.dcx(), span, E0259, "{}", msg), + let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { + (true, true) => E0259, (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() { - true => struct_span_code_err!(self.dcx(), span, E0254, "{}", msg), - false => struct_span_code_err!(self.dcx(), span, E0260, "{}", msg), + true => E0254, + false => E0260, }, _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) { - (false, false) => struct_span_code_err!(self.dcx(), span, E0428, "{}", msg), - (true, true) => struct_span_code_err!(self.dcx(), span, E0252, "{}", msg), - _ => struct_span_code_err!(self.dcx(), span, E0255, "{}", msg), + (false, false) => E0428, + (true, true) => E0252, + _ => E0255, }, }; - err.note(format!( - "`{}` must be defined only once in the {} namespace of this {}", - name, - ns.descr(), - container - )); - - err.span_label(span, format!("`{name}` re{new_participle} here")); - if !old_binding.span.is_dummy() && old_binding.span != span { - err.span_label( - self.tcx.sess.source_map().guess_head_span(old_binding.span), - format!("previous {old_noun} of the {old_kind} `{name}` here"), - ); - } + let label = match new_binding.is_import_user_facing() { + true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name }, + false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name }, + }; + + let old_binding_label = + (!old_binding.span.is_dummy() && old_binding.span != span).then(|| { + let span = self.tcx.sess.source_map().guess_head_span(old_binding.span); + match old_binding.is_import_user_facing() { + true => errors::NameDefinedMultipleTimeOldBindingLabel::Import { + span, + name, + old_kind, + }, + false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition { + span, + name, + old_kind, + }, + } + }); + + let mut err = self + .dcx() + .create_err(errors::NameDefinedMultipleTime { + span, + descr: ns.descr(), + container, + label, + old_binding_label, + }) + .with_code(code); // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; @@ -330,20 +335,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match import { Some((import, span, true)) if should_remove_import && import.is_nested() => { - self.add_suggestion_for_duplicate_nested_use(&mut err, import, span) + self.add_suggestion_for_duplicate_nested_use(&mut err, import, span); } Some((import, _, true)) if should_remove_import && !import.is_glob() => { // Simple case - remove the entire import. Due to the above match arm, this can // only be a single use so just remove it entirely. - err.tool_only_span_suggestion( - import.use_span_with_attributes, - "remove unnecessary import", - "", - Applicability::MaybeIncorrect, + err.subdiagnostic( + self.tcx.dcx(), + errors::ToolOnlyRemoveUnnecessaryImport { + span: import.use_span_with_attributes, + }, ); } Some((import, span, _)) => { - self.add_suggestion_for_rename_of_use(&mut err, name, import, span) + self.add_suggestion_for_rename_of_use(&mut err, name, import, span); } _ => {} } @@ -444,7 +449,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { binding_span: Span, ) { assert!(import.is_nested()); - let message = "remove unnecessary import"; // Two examples will be used to illustrate the span manipulations we're doing: // @@ -460,22 +464,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // previous imports. if found_closing_brace { if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) { - err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect); + err.subdiagnostic(self.dcx(), errors::ToolOnlyRemoveUnnecessaryImport { span }); } else { // Remove the entire line if we cannot extend the span back, this indicates an // `issue_52891::{self}` case. - err.span_suggestion( - import.use_span_with_attributes, - message, - "", - Applicability::MaybeIncorrect, + err.subdiagnostic( + self.dcx(), + errors::RemoveUnnecessaryImport { span: import.use_span_with_attributes }, ); } return; } - err.span_suggestion(span, message, "", Applicability::MachineApplicable); + err.subdiagnostic(self.dcx(), errors::RemoveUnnecessaryImport { span }); } pub(crate) fn lint_if_path_starts_with_module( @@ -571,14 +573,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolution_error: ResolutionError<'a>, ) -> Diag<'_> { match resolution_error { - ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => { + 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::Static { .. } => { + Some(errs::GenericParamsFromOuterItemStaticOrConst::Static) + } DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const), _ => None, }; - let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); + let is_self = + matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); let mut err = errs::GenericParamsFromOuterItem { span, label: None, @@ -677,18 +686,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let origin_sp = origin.iter().copied().collect::<Vec<_>>(); let msp = MultiSpan::from_spans(target_sp.clone()); - let mut err = struct_span_code_err!( - self.dcx(), - msp, - E0408, - "variable `{}` is not bound in all patterns", - name, - ); + let mut err = self + .dcx() + .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name }); for sp in target_sp { - err.span_label(sp, format!("pattern doesn't bind `{name}`")); + err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { span: sp, name }); } for sp in origin_sp { - err.span_label(sp, "variable not in all patterns"); + err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { span: sp }); } if could_be_path { let import_suggestions = self.lookup_import_candidates( @@ -961,17 +966,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { code, trait_item_span, trait_path, - } => { - self.dcx().struct_span_err( + } => self + .dcx() + .create_err(errors::TraitImplMismatch { span, - format!( - "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`", - ), - ) - .with_code(code) - .with_span_label(span, "does not match trait") - .with_span_label(trait_item_span, "item in trait") - } + name, + kind, + trait_path, + trait_item_span, + }) + .with_code(code), ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self .dcx() .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }), @@ -1005,7 +1009,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None }, ), VisResolutionError::ExpectedFound(span, path_str, res) => { - self.dcx().create_err(errs::ExpectedFound { span, res, path_str }) + self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str }) } VisResolutionError::Indeterminate(span) => { self.dcx().create_err(errs::Indeterminate(span)) @@ -1532,17 +1536,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if let crate::NameBindingKind::Import { import, .. } = binding.kind { if !import.span.is_dummy() { - err.span_note( - import.span, - format!("`{ident}` is imported here, but it is {desc}"), - ); + let note = errors::IdentImporterHereButItIsDesc { + span: import.span, + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(self.tcx.dcx(), note); // Silence the 'unused import' warning we might get, // since this diagnostic already covers that import. self.record_use(ident, binding, Used::Other); return; } } - err.note(format!("`{ident}` is in scope, but it is {desc}")); + let note = errors::IdentInScopeButItIsDesc { + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(self.tcx.dcx(), note); return; } } @@ -1582,20 +1592,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // | ^ return false; } - let prefix = match suggestion.target { - SuggestionTarget::SimilarlyNamed => "similarly named ", - SuggestionTarget::SingleItem => "", + let span = self.tcx.sess.source_map().guess_head_span(def_span); + let candidate_descr = suggestion.res.descr(); + let candidate = suggestion.candidate; + let label = match suggestion.target { + SuggestionTarget::SimilarlyNamed => { + errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate } + } + SuggestionTarget::SingleItem => { + errors::DefinedHere::SingleItem { span, candidate_descr, candidate } + } }; - - err.span_label( - self.tcx.sess.source_map().guess_head_span(def_span), - format!( - "{}{} `{}` defined here", - prefix, - suggestion.res.descr(), - suggestion.candidate, - ), - ); + err.subdiagnostic(self.tcx.dcx(), label); } let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target @@ -1749,16 +1757,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. - let descr = get_descr(binding); - let mut err = struct_span_code_err!( - self.dcx(), - ident.span, - E0603, - "{} `{}` is private", - descr, - ident - ); - err.span_label(ident.span, format!("private {descr}")); + let ident_descr = get_descr(binding); + let mut err = + self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { @@ -1782,10 +1783,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If we suggest importing a public re-export, don't point at the definition. if point_to_def && ident.span != outer_ident.span { not_publicly_reexported = true; - err.span_label( - outer_ident.span, - format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()), - ); + let label = errors::OuterIdentIsNotPubliclyReexported { + span: outer_ident.span, + outer_ident_descr: this_res.descr(), + outer_ident, + }; + err.subdiagnostic(self.tcx.dcx(), label); } } @@ -1799,18 +1802,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { - err.span_label(span, "a constructor is private if any of the fields is private"); + let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; + err.subdiagnostic(self.tcx.dcx(), label); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { - err.multipart_suggestion_verbose( - format!( - "consider making the field{} publicly accessible", - pluralize!(fields.len()) - ), - fields.iter().map(|span| (*span, "pub ".to_string())).collect(), - Applicability::MaybeIncorrect, - ); + let spans = fields.iter().map(|span| *span).collect(); + let sugg = + errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() }; + err.subdiagnostic(self.tcx.dcx(), sugg); } } @@ -1893,13 +1893,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} } let first = binding == first_binding; - let msg = format!( - "{and_refers_to}the {item} `{name}`{which} is defined here{dots}", - and_refers_to = if first { "" } else { "...and refers to " }, - item = get_descr(binding), - which = if first { "" } else { " which" }, - dots = if next_binding.is_some() { "..." } else { "" }, - ); let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); if !first && binding.vis.is_public() { @@ -1919,7 +1912,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "cannot be constructed because it is `#[non_exhaustive]`", ); } - err.span_note(note_span, msg); + let note = errors::NoteAndRefersToTheItemDefinedHere { + span: note_span, + binding_descr: get_descr(binding), + binding_name: name, + first, + dots: next_binding.is_some(), + }; + err.subdiagnostic(self.tcx.dcx(), note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); @@ -1933,15 +1933,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { continue; } let path = sugg.join("::"); - err.span_suggestion_verbose( - dedup_span, - format!( - "import `{ident}` {}", - if reexport { "through the re-export" } else { "directly" } - ), - path, - Applicability::MachineApplicable, - ); + let sugg = if reexport { + errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } + } else { + errors::ImportIdent::Directly { span: dedup_span, ident, path } + }; + err.subdiagnostic(self.tcx.dcx(), sugg); break; } @@ -2521,13 +2518,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { continue; } - err.span_note(name.span, "found an item that was configured out"); + let note = errors::FoundItemConfigureOut { span: name.span }; + err.subdiagnostic(self.tcx.dcx(), note); if let MetaItemKind::List(nested) = &cfg.kind && let NestedMetaItem::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { - err.note(format!("the item is gated behind the `{}` feature", feature_name.symbol)); + let note = errors::ItemWasBehindFeature { feature: feature_name.symbol }; + err.subdiagnostic(self.tcx.dcx(), note); } } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 5eee6a51fd2..b0329702d11 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{codes::*, Applicability}; +use rustc_errors::{codes::*, Applicability, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ symbol::{Ident, Symbol}, @@ -495,8 +495,8 @@ pub(crate) struct Relative2018 { pub(crate) struct AncestorOnly(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_expected_found, code = E0577)] -pub(crate) struct ExpectedFound { +#[diag(resolve_expected_module_found, code = E0577)] +pub(crate) struct ExpectedModuleFound { #[primary_span] #[label] pub(crate) span: Span, @@ -525,8 +525,10 @@ pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span); #[diag(resolve_macro_expected_found)] pub(crate) struct MacroExpectedFound<'a> { #[primary_span] + #[label] pub(crate) span: Span, pub(crate) found: &'a str, + pub(crate) article: &'static str, pub(crate) expected: &'a str, pub(crate) macro_path: &'a str, #[subdiagnostic] @@ -801,3 +803,421 @@ pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg { pub ident: Ident, pub snippet: String, } + +#[derive(Diagnostic)] +#[diag(resolve_extern_crate_loading_macro_not_at_crate_root, code = E0468)] +pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_bad_macro_import, code = E0466)] +pub(crate) struct BadMacroImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_extern_crate_self_requires_renaming)] +pub(crate) struct ExternCrateSelfRequiresRenaming { + #[primary_span] + #[suggestion(code = "extern crate self as name;", applicability = "has-placeholders")] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_macro_use_name_already_in_use)] +#[note] +pub(crate) struct MacroUseNameAlreadyInUse { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(resolve_imported_macro_not_found, code = E0469)] +pub(crate) struct ImportedMacroNotFound { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_macro_extern_deprecated)] +pub(crate) struct MacroExternDeprecated { + #[primary_span] + pub(crate) span: Span, + #[help] + pub inner_attribute: Option<()>, +} + +#[derive(Diagnostic)] +#[diag(resolve_arguments_macro_use_not_allowed)] +pub(crate) struct ArgumentsMacroUseNotAllowed { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_unnamed_crate_root_import)] +pub(crate) struct UnnamedCrateRootImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments)] +pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)] +pub(crate) struct ElidedAnonymousLivetimeReportError { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + resolve_elided_anonymous_lifetime_report_error_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { + #[suggestion_part(code = "for<'a> ")] + pub(crate) lo: Span, + #[suggestion_part(code = "'a ")] + pub(crate) hi: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)] +pub(crate) struct ExplicitAnonymousLivetimeReportError { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_implicit_elided_lifetimes_not_allowed_here, code = E0726)] +pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +pub(crate) struct UnderscoreLifetimeIsReserved { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_static_lifetime_is_reserved, code = E0262)] +pub(crate) struct StaticLifetimeIsReserved { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) lifetime: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_attempt_to_define_builtin_macro_twice, code = E0773)] +pub(crate) struct AttemptToDefineBuiltinMacroTwice { + #[primary_span] + pub(crate) span: Span, + #[note] + pub(crate) note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_variable_is_not_bound_in_all_patterns, code = E0408)] +pub(crate) struct VariableIsNotBoundInAllPatterns { + #[primary_span] + pub(crate) multispan: MultiSpan, + pub(crate) name: Symbol, +} + +#[derive(Subdiagnostic, Debug, Clone)] +#[label(resolve_pattern_doesnt_bind_name)] +pub(crate) struct PatternDoesntBindName { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Symbol, +} + +#[derive(Subdiagnostic, Debug, Clone)] +#[label(resolve_variable_not_in_all_patterns)] +pub(crate) struct VariableNotInAllPatterns { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_name_defined_multiple_time)] +#[note] +pub(crate) struct NameDefinedMultipleTime { + #[primary_span] + pub(crate) span: Span, + pub(crate) descr: &'static str, + pub(crate) container: &'static str, + #[subdiagnostic] + pub(crate) label: NameDefinedMultipleTimeLabel, + #[subdiagnostic] + pub(crate) old_binding_label: Option<NameDefinedMultipleTimeOldBindingLabel>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum NameDefinedMultipleTimeLabel { + #[label(resolve_name_defined_multiple_time_reimported)] + Reimported { + #[primary_span] + span: Span, + name: Symbol, + }, + #[label(resolve_name_defined_multiple_time_redefined)] + Redefined { + #[primary_span] + span: Span, + name: Symbol, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum NameDefinedMultipleTimeOldBindingLabel { + #[label(resolve_name_defined_multiple_time_old_binding_import)] + Import { + #[primary_span] + span: Span, + name: Symbol, + old_kind: &'static str, + }, + #[label(resolve_name_defined_multiple_time_old_binding_definition)] + Definition { + #[primary_span] + span: Span, + name: Symbol, + old_kind: &'static str, + }, +} + +#[derive(Diagnostic)] +#[diag(resolve_is_private, code = E0603)] +pub(crate) struct IsPrivate<'a> { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) ident_descr: &'a str, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_generic_arguments_in_macro_path)] +pub(crate) struct GenericArgumentsInMacroPath { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_attributes_starting_with_rustc_are_reserved)] +pub(crate) struct AttributesStartingWithRustcAreReserved { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_cannot_use_through_an_import)] +pub(crate) struct CannotUseThroughAnImport { + #[primary_span] + pub(crate) span: Span, + pub(crate) article: &'static str, + pub(crate) descr: &'static str, + #[note] + pub(crate) binding_span: Option<Span>, +} + +#[derive(Diagnostic)] +#[diag(resolve_name_reserved_in_attribute_namespace)] +pub(crate) struct NameReservedInAttributeNamespace { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_cannot_find_builtin_macro_with_name)] +pub(crate) struct CannotFindBuiltinMacroWithName { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_tool_was_already_registered)] +pub(crate) struct ToolWasAlreadyRegistered { + #[primary_span] + pub(crate) span: Span, + pub(crate) tool: Ident, + #[label] + pub(crate) old_ident_span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_tool_only_accepts_identifiers)] +pub(crate) struct ToolOnlyAcceptsIdentifiers { + #[label] + #[primary_span] + pub(crate) span: Span, + pub(crate) tool: Symbol, +} + +#[derive(Subdiagnostic)] +pub(crate) enum DefinedHere { + #[label(resolve_similarly_named_defined_here)] + SimilarlyNamed { + #[primary_span] + span: Span, + candidate_descr: &'static str, + candidate: Symbol, + }, + #[label(resolve_single_item_defined_here)] + SingleItem { + #[primary_span] + span: Span, + candidate_descr: &'static str, + candidate: Symbol, + }, +} + +#[derive(Subdiagnostic)] +#[label(resolve_outer_ident_is_not_publicly_reexported)] +pub(crate) struct OuterIdentIsNotPubliclyReexported { + #[primary_span] + pub(crate) span: Span, + pub(crate) outer_ident_descr: &'static str, + pub(crate) outer_ident: Ident, +} + +#[derive(Subdiagnostic)] +#[label(resolve_constructor_private_if_any_field_private)] +pub(crate) struct ConstructorPrivateIfAnyFieldPrivate { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + resolve_consider_making_the_field_public, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct ConsiderMakingTheFieldPublic { + #[suggestion_part(code = "pub ")] + pub(crate) spans: Vec<Span>, + pub(crate) number_of_fields: usize, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ImportIdent { + #[suggestion( + resolve_suggestion_import_ident_through_reexport, + code = "{path}", + applicability = "machine-applicable", + style = "verbose" + )] + ThroughReExport { + #[primary_span] + span: Span, + ident: Ident, + path: String, + }, + #[suggestion( + resolve_suggestion_import_ident_directly, + code = "{path}", + applicability = "machine-applicable", + style = "verbose" + )] + Directly { + #[primary_span] + span: Span, + ident: Ident, + path: String, + }, +} + +#[derive(Subdiagnostic)] +#[note(resolve_note_and_refers_to_the_item_defined_here)] +pub(crate) struct NoteAndRefersToTheItemDefinedHere<'a> { + #[primary_span] + pub(crate) span: MultiSpan, + pub(crate) binding_descr: &'a str, + pub(crate) binding_name: Ident, + pub(crate) first: bool, + pub(crate) dots: bool, +} + +#[derive(Subdiagnostic)] +#[suggestion(resolve_remove_unnecessary_import, code = "", applicability = "maybe-incorrect")] +pub(crate) struct RemoveUnnecessaryImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_remove_unnecessary_import, + code = "", + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct ToolOnlyRemoveUnnecessaryImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[note(resolve_ident_imported_here_but_it_is_desc)] +pub(crate) struct IdentImporterHereButItIsDesc<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) imported_ident: Ident, + pub(crate) imported_ident_desc: &'a str, +} + +#[derive(Subdiagnostic)] +#[note(resolve_ident_in_scope_but_it_is_desc)] +pub(crate) struct IdentInScopeButItIsDesc<'a> { + pub(crate) imported_ident: Ident, + pub(crate) imported_ident_desc: &'a str, +} + +#[derive(Subdiagnostic)] +#[note(resolve_found_an_item_configured_out)] +pub(crate) struct FoundItemConfigureOut { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[note(resolve_item_was_behind_feature)] +pub(crate) struct ItemWasBehindFeature { + pub(crate) feature: Symbol, +} + +#[derive(Diagnostic)] +#[diag(resolve_trait_impl_mismatch)] +pub(crate) struct TraitImplMismatch { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) name: Symbol, + pub(crate) kind: &'static str, + pub(crate) trait_path: String, + #[label(resolve_trait_impl_mismatch_label_item)] + pub(crate) trait_item_span: Span, +} diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 76fe36a77cb..3d9380a3ebd 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1391,6 +1391,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut redundant_spans: Vec<_> = redundant_span.present_items().collect(); redundant_spans.sort(); redundant_spans.dedup(); + /* FIXME(unused_imports): Add this back as a new lint self.lint_buffer.buffer_lint_with_diagnostic( UNUSED_IMPORTS, id, @@ -1398,6 +1399,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("the item `{source}` is imported redundantly"), BuiltinLintDiag::RedundantImport(redundant_spans, source), ); + */ return true; } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 49b4a6efd3c..33c9c7fcc62 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,8 +6,7 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. -use crate::errors::ImportsCannotReferTo; -use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; +use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{BindingKey, Used}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; @@ -16,9 +15,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, DiagArgValue, IntoDiagArg, StashKey, -}; +use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey}; 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}; @@ -1666,18 +1663,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); } LifetimeRibKind::AnonymousReportError => { - let (msg, note) = if elided { - ( - "`&` without an explicit lifetime name cannot be used here", - "explicit lifetime name needed here", - ) - } else { - ("`'_` cannot be used here", "`'_` is a reserved lifetime name") - }; - let mut diag = - struct_span_code_err!(self.r.dcx(), lifetime.ident.span, E0637, "{}", msg,); - diag.span_label(lifetime.ident.span, note); if elided { + let mut suggestion = None; for rib in self.lifetime_ribs[i..].iter().rev() { if let LifetimeRibKind::Generics { span, @@ -1685,19 +1672,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { .. } = &rib.kind { - diag.multipart_suggestion( - "consider introducing a higher-ranked lifetime here", - vec![ - (span.shrink_to_lo(), "for<'a> ".into()), - (lifetime.ident.span.shrink_to_hi(), "'a ".into()), - ], - Applicability::MachineApplicable, - ); + suggestion = + Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + lo: span.shrink_to_lo(), + hi: lifetime.ident.span.shrink_to_hi(), + }); break; } } - } - diag.emit(); + self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + span: lifetime.ident.span, + suggestion, + }); + } else { + self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { + span: lifetime.ident.span, + }); + }; self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); return; } @@ -1863,13 +1854,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // async fn foo(_: std::cell::Ref<u32>) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } | LifetimeRibKind::AnonymousWarn(_) => { + let mut err = + self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere { + span: path_span, + }); let sess = self.r.tcx.sess; - let mut err = struct_span_code_err!( - sess.dcx(), - path_span, - E0726, - "implicit elided lifetime not allowed here" - ); rustc_errors::add_elided_lifetime_in_path_suggestion( sess.source_map(), &mut err, @@ -2313,7 +2302,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_error = |this: &Self, ns| { if this.should_report_errs() { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - this.r.dcx().emit_err(ImportsCannotReferTo { span: ident.span, what }); + this.r.dcx().emit_err(errors::ImportsCannotReferTo { span: ident.span, what }); } }; @@ -2633,29 +2622,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::UnderscoreLifetime { - struct_span_code_err!( - self.r.dcx(), - param.ident.span, - E0637, - "`'_` cannot be used here" - ) - .with_span_label(param.ident.span, "`'_` is a reserved lifetime name") - .emit(); + self.r + .dcx() + .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span }); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); continue; } if param.ident.name == kw::StaticLifetime { - struct_span_code_err!( - self.r.dcx(), - param.ident.span, - E0262, - "invalid lifetime parameter name: `{}`", - param.ident, - ) - .with_span_label(param.ident.span, "'static is a reserved lifetime name") - .emit(); + self.r.dcx().emit_err(errors::StaticLifetimeIsReserved { + span: param.ident.span, + lifetime: param.ident, + }); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); continue; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 39ccf6d3714..b8221d9d7f9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -177,7 +177,7 @@ enum ImplTraitContext { /// Used for tracking import use types which will be used for redundant import checking. /// ### Used::Scope Example -/// ```rust,compile_fail +/// ```rust,ignore (redundant_imports) /// #![deny(unused_imports)] /// use std::mem::drop; /// fn main() { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index dbca2f9895d..2a23ed71753 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -14,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::{codes::*, struct_span_code_err, Applicability, StashKey}; +use rustc_errors::{Applicability, StashKey}; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; @@ -123,20 +123,18 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { match nested_meta.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { - let msg = format!("{} `{}` was already registered", "tool", ident); - tcx.dcx() - .struct_span_err(ident.span, msg) - .with_span_label(old_ident.span, "already registered here") - .emit(); + tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered { + span: ident.span, + tool: ident, + old_ident_span: old_ident.span, + }); } } None => { - let msg = format!("`{}` only accepts identifiers", sym::register_tool); - let span = nested_meta.span(); - tcx.dcx() - .struct_span_err(span, msg) - .with_span_label(span, "not an identifier") - .emit(); + tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers { + span: nested_meta.span(), + tool: sym::register_tool, + }); } } } @@ -485,13 +483,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Report errors for the resolved macro. for segment in &path.segments { if let Some(args) = &segment.args { - self.dcx().span_err(args.span(), "generic arguments in macro path"); + self.dcx().emit_err(errors::GenericArgumentsInMacroPath { span: args.span() }); } if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") { - self.dcx().span_err( - segment.ident.span, - "attributes starting with `rustc` are reserved for use by the `rustc` compiler", - ); + self.dcx().emit_err(errors::AttributesStartingWithRustcAreReserved { + span: segment.ident.span, + }); } } @@ -535,6 +532,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut err = MacroExpectedFound { span: path.span, expected, + article, found: res.descr(), macro_path: &path_str, remove_surrounding_derive: None, @@ -550,10 +548,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); } - self.dcx() - .create_err(err) - .with_span_label(path.span, format!("not {article} {expected}")) - .emit(); + self.dcx().emit_err(err); return Ok((self.dummy_ext(kind), Res::Err)); } @@ -872,13 +867,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ) { if let Some(Res::NonMacroAttr(kind)) = res { if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) { - let msg = - format!("cannot use {} {} through an import", kind.article(), kind.descr()); - let mut err = self.dcx().struct_span_err(span, msg); - if let Some(binding) = binding { - err.span_note(binding.span, format!("the {} imported here", kind.descr())); - } - err.emit(); + let binding_span = binding.map(|binding| binding.span); + self.dcx().emit_err(errors::CannotUseThroughAnImport { + span, + article: kind.article(), + descr: kind.descr(), + binding_span, + }); } } } @@ -889,10 +884,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if ident.name == sym::cfg || ident.name == sym::cfg_attr { let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind()); if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { - self.dcx().span_err( - ident.span, - format!("name `{ident}` is reserved in attribute namespace"), - ); + self.dcx() + .emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident }); } } } @@ -916,19 +909,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { rule_spans = Vec::new(); } BuiltinMacroState::AlreadySeen(span) => { - struct_span_code_err!( - self.dcx(), - item.span, - E0773, - "attempted to define built-in macro more than once" - ) - .with_span_note(span, "previously defined here") - .emit(); + self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice { + span: item.span, + note_span: span, + }); } } } else { - let msg = format!("cannot find a built-in macro with name `{}`", item.ident); - self.dcx().span_err(item.span, msg); + self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { + span: item.span, + ident: item.ident, + }); } } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 0ebcad3cdb8..0bc7579918c 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -194,12 +194,12 @@ pub fn attrs_to_doc_fragments<'a>( for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); - let kind = if attr.is_doc_comment() { - DocFragmentKind::SugaredDoc + let (span, kind) = if attr.is_doc_comment() { + (attr.span, DocFragmentKind::SugaredDoc) } else { - DocFragmentKind::RawDoc + (span_for_value(attr), DocFragmentKind::RawDoc) }; - let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 }; + let fragment = DocFragment { span, doc, kind, item_id, indent: 0 }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -211,6 +211,16 @@ pub fn attrs_to_doc_fragments<'a>( (doc_fragments, other_attrs) } +fn span_for_value(attr: &ast::Attribute) -> Span { + if let ast::AttrKind::Normal(normal) = &attr.kind + && let ast::AttrArgs::Eq(_, ast::AttrArgsEq::Hir(meta)) = &normal.item.args + { + meta.span.with_ctxt(attr.span.ctxt()) + } else { + attr.span + } +} + /// Return the doc-comments on this item, grouped by the module they came from. /// The module can be different if this is a re-export with added documentation. /// @@ -482,15 +492,36 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. /// -/// This method will return `None` if we cannot construct a span from the source map or if the -/// fragments are not all sugared doc comments. It's difficult to calculate the correct span in -/// that case due to escaping and other source features. +/// This method does not always work, because markdown bytes don't necessarily match source bytes, +/// like if escapes are used in the string. In this case, it returns `None`. +/// +/// This method will return `Some` only if: +/// +/// - The doc is made entirely from sugared doc comments, which cannot contain escapes +/// - The doc is entirely from a single doc fragment, with a string literal, exactly equal +/// - The doc comes from `include_str!` pub fn source_span_for_markdown_range( tcx: TyCtxt<'_>, markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], ) -> Option<Span> { + if let &[fragment] = &fragments + && fragment.kind == DocFragmentKind::RawDoc + && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(fragment.span) + && snippet.trim_end() == markdown.trim_end() + && let Ok(md_range_lo) = u32::try_from(md_range.start) + && let Ok(md_range_hi) = u32::try_from(md_range.end) + { + // Single fragment with string that contains same bytes as doc. + return Some(Span::new( + fragment.span.lo() + rustc_span::BytePos(md_range_lo), + fragment.span.lo() + rustc_span::BytePos(md_range_hi), + fragment.span.ctxt(), + fragment.span.parent(), + )); + } + let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc); if !is_all_sugared_doc { diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml new file mode 100644 index 00000000000..aea2f7dda7f --- /dev/null +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rustc_sanitizers" +version = "0.0.0" +edition = "2021" + +[dependencies] +bitflags = "2.5.0" +tracing = "0.1" +twox-hash = "1.6.3" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_middle = { path = "../rustc_middle" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_sanitizers/README.md b/compiler/rustc_sanitizers/README.md new file mode 100644 index 00000000000..d2e8f5d3a97 --- /dev/null +++ b/compiler/rustc_sanitizers/README.md @@ -0,0 +1,2 @@ +The `rustc_sanitizers` crate contains the source code for providing support for +the [sanitizers](https://github.com/google/sanitizers) to the Rust compiler. diff --git a/compiler/rustc_sanitizers/src/cfi/mod.rs b/compiler/rustc_sanitizers/src/cfi/mod.rs new file mode 100644 index 00000000000..90dab5e0333 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/mod.rs @@ -0,0 +1,6 @@ +//! LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI support for the Rust compiler. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +pub mod typeid; +pub use crate::cfi::typeid::{typeid_for_fnabi, typeid_for_instance, TypeIdOptions}; diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 7f223f13250..40cd0c14b05 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -1,76 +1,46 @@ -/// Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow -/// Integrity (CFI) and cross-language LLVM CFI support. -/// -/// Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium -/// C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that -/// are not used across the FFI boundary. -/// -/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, -/// see design document in the tracking issue #89653. +//! Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium +//! C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that +//! are not used across the FFI boundary. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::bug; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind, - TermKind, Ty, TyCtxt, UintTy, + self, Const, ExistentialPredicate, FloatTy, FnSig, GenericArg, GenericArgKind, GenericArgsRef, + IntTy, List, Region, RegionKind, TermKind, Ty, TyCtxt, TypeFoldable, UintTy, }; -use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; -use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use rustc_span::def_id::DefId; use rustc_span::sym; -use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; use std::fmt::Write as _; -use std::iter; +use tracing::instrument; -use crate::typeid::TypeIdOptions; +use crate::cfi::typeid::itanium_cxx_abi::transform::{TransformTy, TransformTyOptions}; +use crate::cfi::typeid::TypeIdOptions; -/// Type and extended type qualifiers. -#[derive(Eq, Hash, PartialEq)] -enum TyQ { - None, - Const, - Mut, -} +/// Options for encode_ty. +pub type EncodeTyOptions = TypeIdOptions; /// Substitution dictionary key. #[derive(Eq, Hash, PartialEq)] -enum DictKey<'tcx> { +pub enum DictKey<'tcx> { Ty(Ty<'tcx>, TyQ), Region(Region<'tcx>), Const(Const<'tcx>), Predicate(ExistentialPredicate<'tcx>), } -/// Options for encode_ty. -type EncodeTyOptions = TypeIdOptions; - -/// Options for transform_ty. -type TransformTyOptions = TypeIdOptions; - -/// Converts a number to a disambiguator (see -/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>). -fn to_disambiguator(num: u64) -> String { - if let Some(num) = num.checked_sub(1) { - format!("s{}_", base_n::encode(num as u128, 62)) - } else { - "s_".to_string() - } -} - -/// Converts a number to a sequence number (see -/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>). -fn to_seq_id(num: usize) -> String { - if let Some(num) = num.checked_sub(1) { - base_n::encode(num as u128, 36).to_uppercase() - } else { - "".to_string() - } +/// Type and extended type qualifiers. +#[derive(Eq, Hash, PartialEq)] +pub enum TyQ { + None, + Const, + Mut, } /// Substitutes a component if found in the substitution dictionary (see @@ -91,6 +61,37 @@ fn compress<'tcx>( } } +/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust +/// types that are not used at the FFI boundary. +fn encode_args<'tcx>( + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + // [I<subst1..substN>E] as part of vendor extended type + let mut s = String::new(); + let args: Vec<GenericArg<'_>> = args.iter().collect(); + if !args.is_empty() { + s.push('I'); + for arg in args { + match arg.unpack() { + GenericArgKind::Lifetime(region) => { + s.push_str(&encode_region(region, dict)); + } + GenericArgKind::Type(ty) => { + s.push_str(&encode_ty(tcx, ty, dict, options)); + } + GenericArgKind::Const(c) => { + s.push_str(&encode_const(tcx, c, dict, options)); + } + } + } + s.push('E'); + } + s +} + /// Encodes a const using the Itanium C++ ABI as a literal argument (see /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>). fn encode_const<'tcx>( @@ -159,7 +160,6 @@ fn encode_const<'tcx>( /// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. -#[instrument(level = "trace", skip(tcx, dict))] fn encode_fnsig<'tcx>( tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>, @@ -283,12 +283,12 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, s.push('E'); compress(dict, DictKey::Region(region), &mut s); } - // FIXME(@lcnr): Why is `ReEarlyParam` reachable here. - RegionKind::ReEarlyParam(..) | RegionKind::ReErased => { + RegionKind::ReErased => { s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReLateParam(..) + RegionKind::ReEarlyParam(..) + | RegionKind::ReLateParam(..) | RegionKind::ReStatic | RegionKind::ReError(_) | RegionKind::ReVar(..) @@ -299,137 +299,10 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, s } -/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust -/// types that are not used at the FFI boundary. -fn encode_args<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, - dict: &mut FxHashMap<DictKey<'tcx>, usize>, - options: EncodeTyOptions, -) -> String { - // [I<subst1..substN>E] as part of vendor extended type - let mut s = String::new(); - let args: Vec<GenericArg<'_>> = args.iter().collect(); - if !args.is_empty() { - s.push('I'); - for arg in args { - match arg.unpack() { - GenericArgKind::Lifetime(region) => { - s.push_str(&encode_region(region, dict)); - } - GenericArgKind::Type(ty) => { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - GenericArgKind::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); - } - } - } - s.push('E'); - } - s -} - -/// Encodes a ty:Ty name, including its crate and path disambiguators and names. -fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { - // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where - // <element-type> is <subst>, using v0's <path> without v0's extended form of paths: - // - // N<namespace-tagN>..N<namespace-tag1> - // C<crate-disambiguator><crate-name> - // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN> - // - // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance: - // - // pub type Type1 = impl Send; - // let _: Type1 = <Struct1<i32>>::foo; - // fn foo1(_: Type1) { } - // - // pub type Type2 = impl Send; - // let _: Type2 = <Trait1<i32>>::foo; - // fn foo2(_: Type2) { } - // - // pub type Type3 = impl Send; - // let _: Type3 = <i32 as Trait1<i32>>::foo; - // fn foo3(_: Type3) { } - // - // pub type Type4 = impl Send; - // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo; - // fn foo3(_: Type4) { } - // - // Are encoded as: - // - // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE - // - // The reason for not using v0's extended form of paths is to use a consistent and simpler - // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e., - // keep symbol names close to how methods are represented in error messages). See - // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods. - let mut s = String::new(); - - // Start and namespace tags - let mut def_path = tcx.def_path(def_id); - def_path.data.reverse(); - for disambiguated_data in &def_path.data { - s.push('N'); - s.push_str(match disambiguated_data.data { - hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace> - hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace> - hir::definitions::DefPathData::TypeNs(..) => "t", - hir::definitions::DefPathData::ValueNs(..) => "v", - hir::definitions::DefPathData::Closure => "C", - hir::definitions::DefPathData::Ctor => "c", - hir::definitions::DefPathData::AnonConst => "k", - hir::definitions::DefPathData::OpaqueTy => "i", - hir::definitions::DefPathData::CrateRoot - | hir::definitions::DefPathData::Use - | hir::definitions::DefPathData::GlobalAsm - | hir::definitions::DefPathData::MacroNs(..) - | hir::definitions::DefPathData::LifetimeNs(..) - | hir::definitions::DefPathData::AnonAdt => { - bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); - } - }); - } - - // Crate disambiguator and name - s.push('C'); - s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64())); - let crate_name = tcx.crate_name(def_path.krate).to_string(); - let _ = write!(s, "{}{}", crate_name.len(), &crate_name); - - // Disambiguators and names - def_path.data.reverse(); - for disambiguated_data in &def_path.data { - let num = disambiguated_data.disambiguator as u64; - if num > 0 { - s.push_str(&to_disambiguator(num)); - } - - let name = disambiguated_data.data.to_string(); - let _ = write!(s, "{}", name.len()); - - // Prepend a '_' if name starts with a digit or '_' - if let Some(first) = name.as_bytes().first() { - if first.is_ascii_digit() || *first == b'_' { - s.push('_'); - } - } else { - bug!("encode_ty_name: invalid name `{:?}`", name); - } - - s.push_str(&name); - } - - s -} - /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. -fn encode_ty<'tcx>( +#[instrument(level = "trace", skip(tcx, dict))] +pub fn encode_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>, @@ -533,6 +406,16 @@ fn encode_ty<'tcx>( typeid.push_str(&s); } + ty::Pat(ty0, pat) => { + // u3patI<element-type><pattern>E as vendor extended type + let mut s = String::from("u3patI"); + s.push_str(&encode_ty(tcx, *ty0, dict, options)); + write!(s, "{:?}", **pat).unwrap(); + s.push('E'); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + ty::Slice(ty0) => { // u5sliceI<element-type>E as vendor extended type let mut s = String::from("u5sliceI"); @@ -752,501 +635,119 @@ fn encode_ty<'tcx>( typeid } -struct TransformTy<'tcx> { - tcx: TyCtxt<'tcx>, - options: TransformTyOptions, - parents: Vec<Ty<'tcx>>, -} - -impl<'tcx> TransformTy<'tcx> { - fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self { - TransformTy { tcx, options, parents: Vec::new() } - } -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { - // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms - // all c_void types into unit types unconditionally, generalizes pointers if - // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if - // TransformTyOptions::NORMALIZE_INTEGERS option is set. - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind() { - ty::Array(..) - | ty::Closure(..) - | ty::Coroutine(..) - | ty::CoroutineClosure(..) - | ty::CoroutineWitness(..) - | ty::Float(..) - | ty::FnDef(..) - | ty::Foreign(..) - | ty::Never - | ty::Slice(..) - | ty::Str - | ty::Tuple(..) => t.super_fold_with(self), - - ty::Bool => { - if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Note: on all platforms that Rust's currently supports, its size and alignment - // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs. - // - // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.) - // - // Clang represents bool as an 8-bit unsigned integer. - self.tcx.types.u8 - } else { - t - } - } - - ty::Char => { - if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Since #118032, char is guaranteed to have the same size, alignment, and - // function call ABI as u32 on all platforms. - self.tcx.types.u32 - } else { - t - } - } - - ty::Int(..) | ty::Uint(..) => { - if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit - // wide. All platforms we currently support have a C platform, and as a - // consequence, isize/usize are at least 16-bit wide for all of them. - // - // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.) - match t.kind() { - ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width { - 16 => self.tcx.types.i16, - 32 => self.tcx.types.i32, - 64 => self.tcx.types.i64, - 128 => self.tcx.types.i128, - _ => bug!( - "fold_ty: unexpected pointer width `{}`", - self.tcx.sess.target.pointer_width - ), - }, - ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width { - 16 => self.tcx.types.u16, - 32 => self.tcx.types.u32, - 64 => self.tcx.types.u64, - 128 => self.tcx.types.u128, - _ => bug!( - "fold_ty: unexpected pointer width `{}`", - self.tcx.sess.target.pointer_width - ), - }, - _ => t, - } - } else { - t - } - } - - ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit, - - ty::Adt(adt_def, args) => { - if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t) - { - // Don't transform repr(transparent) types with an user-defined CFI encoding to - // preserve the user-defined CFI encoding. - if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) { - return t; - } - let variant = adt_def.non_enum_variant(); - let param_env = self.tcx.param_env(variant.def_id); - let field = variant.fields.iter().find(|field| { - let ty = self.tcx.type_of(field.did).instantiate_identity(); - let is_zst = self - .tcx - .layout_of(param_env.and(ty)) - .is_ok_and(|layout| layout.is_zst()); - !is_zst - }); - if let Some(field) = field { - let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args); - // Generalize any repr(transparent) user-defined type that is either a - // pointer or reference, and either references itself or any other type that - // contains or references itself, to avoid a reference cycle. - - // If the self reference is not through a pointer, for example, due - // to using `PhantomData`, need to skip normalizing it if we hit it again. - self.parents.push(t); - let ty = if ty0.is_any_ptr() && ty0.contains(t) { - let options = self.options; - self.options |= TransformTyOptions::GENERALIZE_POINTERS; - let ty = ty0.fold_with(self); - self.options = options; - ty - } else { - ty0.fold_with(self) - }; - self.parents.pop(); - ty - } else { - // Transform repr(transparent) types without non-ZST field into () - self.tcx.types.unit - } - } else { - t.super_fold_with(self) - } - } - - ty::Ref(..) => { - if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if t.is_mutable_ptr() { - Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) - } else { - Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) - } - } else { - t.super_fold_with(self) - } - } - - ty::RawPtr(..) => { - if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if t.is_mutable_ptr() { - Ty::new_mut_ptr(self.tcx, self.tcx.types.unit) - } else { - Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) - } - } else { - t.super_fold_with(self) - } - } - - ty::FnPtr(..) => { - if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) - } else { - t.super_fold_with(self) - } - } - - ty::Dynamic(predicates, _region, kind) => { - let predicates = self.tcx.mk_poly_existential_predicates_from_iter( - predicates.iter().filter_map(|predicate| match predicate.skip_binder() { - ty::ExistentialPredicate::Trait(trait_ref) => { - let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id); - Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref), - ))) - } - ty::ExistentialPredicate::Projection(..) => None, - ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), - }), - ); - - Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind) - } - - ty::Alias(..) => { - self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t)) - } +/// Encodes a ty:Ty name, including its crate and path disambiguators and names. +fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { + // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where + // <element-type> is <subst>, using v0's <path> without v0's extended form of paths: + // + // N<namespace-tagN>..N<namespace-tag1> + // C<crate-disambiguator><crate-name> + // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN> + // + // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance: + // + // pub type Type1 = impl Send; + // let _: Type1 = <Struct1<i32>>::foo; + // fn foo1(_: Type1) { } + // + // pub type Type2 = impl Send; + // let _: Type2 = <Trait1<i32>>::foo; + // fn foo2(_: Type2) { } + // + // pub type Type3 = impl Send; + // let _: Type3 = <i32 as Trait1<i32>>::foo; + // fn foo3(_: Type3) { } + // + // pub type Type4 = impl Send; + // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo; + // fn foo3(_: Type4) { } + // + // Are encoded as: + // + // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE + // + // The reason for not using v0's extended form of paths is to use a consistent and simpler + // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e., + // keep symbol names close to how methods are represented in error messages). See + // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods. + let mut s = String::new(); - ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { - bug!("fold_ty: unexpected `{:?}`", t.kind()); + // Start and namespace tags + let mut def_path = tcx.def_path(def_id); + def_path.data.reverse(); + for disambiguated_data in &def_path.data { + s.push('N'); + s.push_str(match disambiguated_data.data { + hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace> + hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace> + hir::definitions::DefPathData::TypeNs(..) => "t", + hir::definitions::DefPathData::ValueNs(..) => "v", + hir::definitions::DefPathData::Closure => "C", + hir::definitions::DefPathData::Ctor => "c", + hir::definitions::DefPathData::AnonConst => "k", + hir::definitions::DefPathData::OpaqueTy => "i", + hir::definitions::DefPathData::CrateRoot + | hir::definitions::DefPathData::Use + | hir::definitions::DefPathData::GlobalAsm + | hir::definitions::DefPathData::MacroNs(..) + | hir::definitions::DefPathData::LifetimeNs(..) + | hir::definitions::DefPathData::AnonAdt => { + bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } - } - } - - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx + }); } -} -/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor -/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. -#[instrument(level = "trace", skip(tcx))] -pub fn typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> String { - // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions - // its type. - let mut typeid = String::from("_Z"); - - // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type - // metadata identifiers for function pointers. The typeinfo name encoding is a two-character - // code (i.e., 'TS') prefixed to the type encoding for the function. - typeid.push_str("TS"); - - // Function types are delimited by an "F..E" pair - typeid.push('F'); - - // A dictionary of substitution candidates used for compression (see - // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). - let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default(); + // Crate disambiguator and name + s.push('C'); + s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64())); + let crate_name = tcx.crate_name(def_path.krate).to_string(); + let _ = write!(s, "{}{}", crate_name.len(), &crate_name); - let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - match fn_abi.conv { - Conv::C => { - encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); - } - _ => { - encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); + // Disambiguators and names + def_path.data.reverse(); + for disambiguated_data in &def_path.data { + let num = disambiguated_data.disambiguator as u64; + if num > 0 { + s.push_str(&to_disambiguator(num)); } - } - // Encode the return type - let transform_ty_options = TransformTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - let mut type_folder = TransformTy::new(tcx, transform_ty_options); - let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - - // Encode the parameter types + let name = disambiguated_data.data.to_string(); + let _ = write!(s, "{}", name.len()); - // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how - // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR - // interpretation today will allow skipped arguments to simply not be passed at a call-site. - if !fn_abi.c_variadic { - let mut pushed_arg = false; - for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { - pushed_arg = true; - let ty = arg.layout.ty.fold_with(&mut type_folder); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - } - if !pushed_arg { - // Empty parameter lists, whether declared as () or conventionally as (void), are - // encoded with a void parameter specifier "v". - typeid.push('v'); - } - } else { - for n in 0..fn_abi.fixed_count as usize { - if fn_abi.args[n].mode == PassMode::Ignore { - continue; + // Prepend a '_' if name starts with a digit or '_' + if let Some(first) = name.as_bytes().first() { + if first.is_ascii_digit() || *first == b'_' { + s.push('_'); } - let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } else { + bug!("encode_ty_name: invalid name `{:?}`", name); } - typeid.push('z'); - } - - // Close the "F..E" pair - typeid.push('E'); - - // Add encoding suffixes - if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - typeid.push_str(".normalized"); - } - - if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) { - typeid.push_str(".generalized"); + s.push_str(&name); } - typeid + s } -/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with -/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary. -pub fn typeid_for_instance<'tcx>( - tcx: TyCtxt<'tcx>, - mut instance: Instance<'tcx>, - options: TypeIdOptions, -) -> String { - if (matches!(instance.def, ty::InstanceDef::Virtual(..)) - && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) - || matches!(instance.def, ty::InstanceDef::DropGlue(..)) - { - // Adjust the type ids of DropGlues - // - // DropGlues may have indirect calls to one or more given types drop function. Rust allows - // for types to be erased to any trait object and retains the drop function for the original - // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is - // called a second time, it only has information after type erasure and it could be a call - // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on - // declaration/definition, and during code generation at call sites so they have the same - // type id and match. - // - // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of - // any other type. - // - let def_id = tcx - .lang_items() - .drop_trait() - .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); - let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { - def_id: def_id, - args: List::empty(), - }); - let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); - let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); - instance.args = tcx.mk_args_trait(self_ty, List::empty()); - } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def { - let upcast_ty = match tcx.trait_of_item(def_id) { - Some(trait_id) => trait_object_ty( - tcx, - ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), - ), - // drop_in_place won't have a defining trait, skip the upcast - None => instance.args.type_at(0), - }; - let stripped_ty = strip_receiver_auto(tcx, upcast_ty); - instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1)); - } else if let ty::InstanceDef::VTableShim(def_id) = instance.def - && let Some(trait_id) = tcx.trait_of_item(def_id) - { - // VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable, - // as the caller will not know the concrete Self. - let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - } - - if !options.contains(EncodeTyOptions::USE_CONCRETE_SELF) { - if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) - && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) - { - let impl_method = tcx.associated_item(instance.def_id()); - let method_id = impl_method - .trait_item_def_id - .expect("Part of a trait implementation, but not linked to the def_id?"); - let trait_method = tcx.associated_item(method_id); - let trait_id = trait_ref.skip_binder().def_id; - if traits::is_vtable_safe_method(tcx, trait_id, trait_method) - && tcx.object_safety_violations(trait_id).is_empty() - { - // Trait methods will have a Self polymorphic parameter, where the concreteized - // implementatation will not. We need to walk back to the more general trait method - let trait_ref = tcx.instantiate_and_normalize_erasing_regions( - instance.args, - ty::ParamEnv::reveal_all(), - trait_ref, - ); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - - // At the call site, any call to this concrete function through a vtable will be - // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the - // original method id, and we've recovered the trait arguments, we can make the callee - // instance we're computing the alias set for match the caller instance. - // - // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. - // If we ever *do* start encoding the vtable index, we will need to generate an alias set - // based on which vtables we are putting this method into, as there will be more than one - // index value when supertraits are involved. - instance.def = ty::InstanceDef::Virtual(method_id, 0); - let abstract_trait_args = - tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); - } - } else if tcx.is_closure_like(instance.def_id()) { - // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, - // instantiate it, and take the type of its only method as our own. - let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - let (trait_id, inputs) = match closure_ty.kind() { - ty::Closure(..) => { - let closure_args = instance.args.as_closure(); - let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap(); - let tuple_args = - tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0]; - (trait_id, Some(tuple_args)) - } - ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { - hir::CoroutineKind::Coroutine(..) => ( - tcx.require_lang_item(LangItem::Coroutine, None), - Some(instance.args.as_coroutine().resume_ty()), - ), - hir::CoroutineKind::Desugared(desugaring, _) => { - let lang_item = match desugaring { - hir::CoroutineDesugaring::Async => LangItem::Future, - hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, - hir::CoroutineDesugaring::Gen => LangItem::Iterator, - }; - (tcx.require_lang_item(lang_item, None), None) - } - }, - ty::CoroutineClosure(..) => ( - tcx.require_lang_item(LangItem::FnOnce, None), - Some( - tcx.instantiate_bound_regions_with_erased( - instance.args.as_coroutine_closure().coroutine_closure_sig(), - ) - .tupled_inputs_ty, - ), - ), - x => bug!("Unexpected type kind for closure-like: {x:?}"), - }; - let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into)); - let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - // There should be exactly one method on this trait, and it should be the one we're - // defining. - let call = tcx - .associated_items(trait_id) - .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) - .expect("No call-family function on closure-like Fn trait?") - .def_id; - - instance.def = ty::InstanceDef::Virtual(call, 0); - instance.args = abstract_args; - } +/// Converts a number to a disambiguator (see +/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>). +fn to_disambiguator(num: u64) -> String { + if let Some(num) = num.checked_sub(1) { + format!("s{}_", base_n::encode(num as u128, base_n::ALPHANUMERIC_ONLY)) + } else { + "s_".to_string() } - - let fn_abi = tcx - .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) - .unwrap_or_else(|error| { - bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") - }); - - typeid_for_fnabi(tcx, fn_abi, options) } -fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty::Dynamic(preds, lifetime, kind) = ty.kind() else { - bug!("Tried to strip auto traits from non-dynamic type {ty}"); - }; - if preds.principal().is_some() { - let filtered_preds = - tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { - !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) - })); - Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind) +/// Converts a number to a sequence number (see +/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>). +fn to_seq_id(num: usize) -> String { + if let Some(num) = num.checked_sub(1) { + base_n::encode(num as u128, base_n::CASE_INSENSITIVE).to_uppercase() } else { - // If there's no principal type, re-encode it as a unit, since we don't know anything - // about it. This technically discards the knowledge that it was a type that was made - // into a trait object at some point, but that's not a lot. - tcx.types.unit + "".to_string() } } - -#[instrument(skip(tcx), ret)] -fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { - assert!(!poly_trait_ref.has_non_region_param()); - let principal_pred = poly_trait_ref.map_bound(|trait_ref| { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) - }); - let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref) - .flat_map(|super_poly_trait_ref| { - tcx.associated_items(super_poly_trait_ref.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) - .map(move |assoc_ty| { - super_poly_trait_ref.map_bound(|super_trait_ref| { - let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args); - let resolved = tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), - alias_ty.to_ty(tcx), - ); - debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - def_id: assoc_ty.def_id, - args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, - term: resolved.into(), - }) - }) - }) - }) - .collect(); - assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - let preds = tcx.mk_poly_existential_predicates_from_iter( - iter::once(principal_pred).chain(assoc_preds.into_iter()), - ); - Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn) -} diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs new file mode 100644 index 00000000000..b6182dc4e63 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs @@ -0,0 +1,123 @@ +//! Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow +//! Integrity (CFI) and cross-language LLVM CFI support. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::bug; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_target::abi::call::{Conv, FnAbi, PassMode}; +use tracing::instrument; + +mod encode; +mod transform; +use crate::cfi::typeid::itanium_cxx_abi::encode::{encode_ty, DictKey, EncodeTyOptions}; +use crate::cfi::typeid::itanium_cxx_abi::transform::{ + transform_instance, TransformTy, TransformTyOptions, +}; +use crate::cfi::typeid::TypeIdOptions; + +/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor +/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. +#[instrument(level = "trace", skip(tcx))] +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> String { + // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions + // its type. + let mut typeid = String::from("_Z"); + + // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type + // metadata identifiers for function pointers. The typeinfo name encoding is a two-character + // code (i.e., 'TS') prefixed to the type encoding for the function. + typeid.push_str("TS"); + + // Function types are delimited by an "F..E" pair + typeid.push('F'); + + // A dictionary of substitution candidates used for compression (see + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). + let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default(); + + let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); + match fn_abi.conv { + Conv::C => { + encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); + } + _ => { + encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); + } + } + + // Encode the return type + let transform_ty_options = TransformTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); + let mut type_folder = TransformTy::new(tcx, transform_ty_options); + let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + + // Encode the parameter types + + // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how + // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR + // interpretation today will allow skipped arguments to simply not be passed at a call-site. + if !fn_abi.c_variadic { + let mut pushed_arg = false; + for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { + pushed_arg = true; + let ty = arg.layout.ty.fold_with(&mut type_folder); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + if !pushed_arg { + // Empty parameter lists, whether declared as () or conventionally as (void), are + // encoded with a void parameter specifier "v". + typeid.push('v'); + } + } else { + for n in 0..fn_abi.fixed_count as usize { + if fn_abi.args[n].mode == PassMode::Ignore { + continue; + } + let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + + typeid.push('z'); + } + + // Close the "F..E" pair + typeid.push('E'); + + // Add encoding suffixes + if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + typeid.push_str(".normalized"); + } + + if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) { + typeid.push_str(".generalized"); + } + + typeid +} + +/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with +/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary. +#[instrument(level = "trace", skip(tcx))] +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + options: TypeIdOptions, +) -> String { + let transform_ty_options = TransformTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits())); + let instance = transform_instance(tcx, instance, transform_ty_options); + let fn_abi = tcx + .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) + .unwrap_or_else(|error| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") + }); + typeid_for_fnabi(tcx, fn_abi, options) +} diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs new file mode 100644 index 00000000000..7141c6c9bb0 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -0,0 +1,450 @@ +//! Transforms instances and types for LLVM CFI and cross-language LLVM CFI support using Itanium +//! C++ ABI mangling. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +use rustc_hir as hir; +use rustc_hir::LangItem; +use rustc_middle::bug; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{ + self, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, UintTy, +}; +use rustc_span::sym; +use rustc_trait_selection::traits; +use std::iter; +use tracing::{debug, instrument}; + +use crate::cfi::typeid::itanium_cxx_abi::encode::EncodeTyOptions; +use crate::cfi::typeid::TypeIdOptions; + +/// Options for transform_ty. +pub type TransformTyOptions = TypeIdOptions; + +pub struct TransformTy<'tcx> { + tcx: TyCtxt<'tcx>, + options: TransformTyOptions, + parents: Vec<Ty<'tcx>>, +} + +impl<'tcx> TransformTy<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self { + TransformTy { tcx, options, parents: Vec::new() } + } +} + +/// Transforms a ty:Ty for being encoded and used in the substitution dictionary. +/// +/// * Transforms all c_void types into unit types. +/// * Generalizes pointers if TransformTyOptions::GENERALIZE_POINTERS option is set. +/// * Normalizes integers if TransformTyOptions::NORMALIZE_INTEGERS option is set. +/// * Generalizes any repr(transparent) user-defined type that is either a pointer or reference, and +/// either references itself or any other type that contains or references itself, to avoid a +/// reference cycle. +/// * Transforms repr(transparent) types without non-ZST field into (). +/// +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { + // Transforms a ty:Ty for being encoded and used in the substitution dictionary. + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.kind() { + ty::Array(..) + | ty::Closure(..) + | ty::Coroutine(..) + | ty::CoroutineClosure(..) + | ty::CoroutineWitness(..) + | ty::Dynamic(..) + | ty::Float(..) + | ty::FnDef(..) + | ty::Foreign(..) + | ty::Never + | ty::Pat(..) + | ty::Slice(..) + | ty::Str + | ty::Tuple(..) => t.super_fold_with(self), + + ty::Bool => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Note: on all platforms that Rust's currently supports, its size and alignment + // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs. + // + // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.) + // + // Clang represents bool as an 8-bit unsigned integer. + self.tcx.types.u8 + } else { + t + } + } + + ty::Char => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Since #118032, char is guaranteed to have the same size, alignment, and + // function call ABI as u32 on all platforms. + self.tcx.types.u32 + } else { + t + } + } + + ty::Int(..) | ty::Uint(..) => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit + // wide. All platforms we currently support have a C platform, and as a + // consequence, isize/usize are at least 16-bit wide for all of them. + // + // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.) + match t.kind() { + ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width { + 16 => self.tcx.types.i16, + 32 => self.tcx.types.i32, + 64 => self.tcx.types.i64, + 128 => self.tcx.types.i128, + _ => bug!( + "fold_ty: unexpected pointer width `{}`", + self.tcx.sess.target.pointer_width + ), + }, + ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width { + 16 => self.tcx.types.u16, + 32 => self.tcx.types.u32, + 64 => self.tcx.types.u64, + 128 => self.tcx.types.u128, + _ => bug!( + "fold_ty: unexpected pointer width `{}`", + self.tcx.sess.target.pointer_width + ), + }, + _ => t, + } + } else { + t + } + } + + ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit, + + ty::Adt(adt_def, args) => { + if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t) + { + // Don't transform repr(transparent) types with an user-defined CFI encoding to + // preserve the user-defined CFI encoding. + if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) { + return t; + } + let variant = adt_def.non_enum_variant(); + let param_env = self.tcx.param_env(variant.def_id); + let field = variant.fields.iter().find(|field| { + let ty = self.tcx.type_of(field.did).instantiate_identity(); + let is_zst = self + .tcx + .layout_of(param_env.and(ty)) + .is_ok_and(|layout| layout.is_zst()); + !is_zst + }); + if let Some(field) = field { + let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args); + // Generalize any repr(transparent) user-defined type that is either a + // pointer or reference, and either references itself or any other type that + // contains or references itself, to avoid a reference cycle. + + // If the self reference is not through a pointer, for example, due + // to using `PhantomData`, need to skip normalizing it if we hit it again. + self.parents.push(t); + let ty = if ty0.is_any_ptr() && ty0.contains(t) { + let options = self.options; + self.options |= TransformTyOptions::GENERALIZE_POINTERS; + let ty = ty0.fold_with(self); + self.options = options; + ty + } else { + ty0.fold_with(self) + }; + self.parents.pop(); + ty + } else { + // Transform repr(transparent) types without non-ZST field into () + self.tcx.types.unit + } + } else { + t.super_fold_with(self) + } + } + + ty::Ref(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if t.is_mutable_ptr() { + Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) + } else { + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) + } + } else { + t.super_fold_with(self) + } + } + + ty::RawPtr(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if t.is_mutable_ptr() { + Ty::new_mut_ptr(self.tcx, self.tcx.types.unit) + } else { + Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) + } + } else { + t.super_fold_with(self) + } + } + + ty::FnPtr(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) + } else { + t.super_fold_with(self) + } + } + + ty::Alias(..) => { + self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t)) + } + + ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { + bug!("fold_ty: unexpected `{:?}`", t.kind()); + } + } + } + + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +#[instrument(skip(tcx), ret)] +fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { + assert!(!poly_trait_ref.has_non_region_param()); + let principal_pred = poly_trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) + }); + let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref) + .flat_map(|super_poly_trait_ref| { + tcx.associated_items(super_poly_trait_ref.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .map(move |assoc_ty| { + super_poly_trait_ref.map_bound(|super_trait_ref| { + let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args); + let resolved = tcx.normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + alias_ty.to_ty(tcx), + ); + debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + def_id: assoc_ty.def_id, + args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, + term: resolved.into(), + }) + }) + }) + }) + .collect(); + assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + let preds = tcx.mk_poly_existential_predicates_from_iter( + iter::once(principal_pred).chain(assoc_preds.into_iter()), + ); + Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn) +} + +/// Transforms an instance for LLVM CFI and cross-language LLVM CFI support using Itanium C++ ABI +/// mangling. +/// +/// typeid_for_instance is called at two locations, initially when declaring/defining functions and +/// methods, and later during code generation at call sites, after type erasure might have ocurred. +/// +/// In the first call (i.e., when declaring/defining functions and methods), it encodes type ids for +/// an FnAbi or Instance, and these type ids are attached to functions and methods. (These type ids +/// are used later by the LowerTypeTests LLVM pass to aggregate functions in groups derived from +/// these type ids.) +/// +/// In the second call (i.e., during code generation at call sites), it encodes a type id for an +/// FnAbi or Instance, after type erasure might have occured, and this type id is used for testing +/// if a function is member of the group derived from this type id. Therefore, in the first call to +/// typeid_for_fnabi (when type ids are attached to functions and methods), it can only include at +/// most as much information that would be available in the second call (i.e., during code +/// generation at call sites); otherwise, the type ids would not not match. +/// +/// For this, it: +/// +/// * Adjust the type ids of DropGlues (see below). +/// * Adjusts the type ids of VTableShims to the type id expected in the call sites for the +/// entry in the vtable (i.e., by using the signature of the closure passed as an argument to the +/// shim, or by just removing self). +/// * Performs type erasure for calls on trait objects by transforming self into a trait object of +/// the trait that defines the method. +/// * Performs type erasure for closures call methods by transforming self into a trait object of +/// the Fn trait that defines the method (for being attached as a secondary type id). +/// +#[instrument(level = "trace", skip(tcx))] +pub fn transform_instance<'tcx>( + tcx: TyCtxt<'tcx>, + mut instance: Instance<'tcx>, + options: TransformTyOptions, +) -> Instance<'tcx> { + if (matches!(instance.def, ty::InstanceDef::Virtual(..)) + && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) + || matches!(instance.def, ty::InstanceDef::DropGlue(..)) + { + // Adjust the type ids of DropGlues + // + // DropGlues may have indirect calls to one or more given types drop function. Rust allows + // for types to be erased to any trait object and retains the drop function for the original + // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is + // called a second time, it only has information after type erasure and it could be a call + // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on + // declaration/definition, and during code generation at call sites so they have the same + // type id and match. + // + // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of + // any other type. + // + let def_id = tcx + .lang_items() + .drop_trait() + .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); + let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { + def_id: def_id, + args: List::empty(), + }); + let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); + let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); + instance.args = tcx.mk_args_trait(self_ty, List::empty()); + } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def { + // Transform self into a trait object of the trait that defines the method for virtual + // functions to match the type erasure done below. + let upcast_ty = match tcx.trait_of_item(def_id) { + Some(trait_id) => trait_object_ty( + tcx, + ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), + ), + // drop_in_place won't have a defining trait, skip the upcast + None => instance.args.type_at(0), + }; + let ty::Dynamic(preds, lifetime, kind) = upcast_ty.kind() else { + bug!("Tried to remove autotraits from non-dynamic type {upcast_ty}"); + }; + let self_ty = if preds.principal().is_some() { + let filtered_preds = + tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { + !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) + })); + Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind) + } else { + // If there's no principal type, re-encode it as a unit, since we don't know anything + // about it. This technically discards the knowledge that it was a type that was made + // into a trait object at some point, but that's not a lot. + tcx.types.unit + }; + instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1)); + } else if let ty::InstanceDef::VTableShim(def_id) = instance.def + && let Some(trait_id) = tcx.trait_of_item(def_id) + { + // Adjust the type ids of VTableShims to the type id expected in the call sites for the + // entry in the vtable (i.e., by using the signature of the closure passed as an argument + // to the shim, or by just removing self). + let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + } + + if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) { + // Perform type erasure for calls on trait objects by transforming self into a trait object + // of the trait that defines the method. + if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) + && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) + { + let impl_method = tcx.associated_item(instance.def_id()); + let method_id = impl_method + .trait_item_def_id + .expect("Part of a trait implementation, but not linked to the def_id?"); + let trait_method = tcx.associated_item(method_id); + let trait_id = trait_ref.skip_binder().def_id; + if traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.object_safety_violations(trait_id).is_empty() + { + // Trait methods will have a Self polymorphic parameter, where the concreteized + // implementatation will not. We need to walk back to the more general trait method + let trait_ref = tcx.instantiate_and_normalize_erasing_regions( + instance.args, + ty::ParamEnv::reveal_all(), + trait_ref, + ); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + + // At the call site, any call to this concrete function through a vtable will be + // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the + // original method id, and we've recovered the trait arguments, we can make the callee + // instance we're computing the alias set for match the caller instance. + // + // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. + // If we ever *do* start encoding the vtable index, we will need to generate an alias set + // based on which vtables we are putting this method into, as there will be more than one + // index value when supertraits are involved. + instance.def = ty::InstanceDef::Virtual(method_id, 0); + let abstract_trait_args = + tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); + } + } else if tcx.is_closure_like(instance.def_id()) { + // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, + // instantiate it, and take the type of its only method as our own. + let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let (trait_id, inputs) = match closure_ty.kind() { + ty::Closure(..) => { + let closure_args = instance.args.as_closure(); + let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap(); + let tuple_args = + tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0]; + (trait_id, Some(tuple_args)) + } + ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { + hir::CoroutineKind::Coroutine(..) => ( + tcx.require_lang_item(LangItem::Coroutine, None), + Some(instance.args.as_coroutine().resume_ty()), + ), + hir::CoroutineKind::Desugared(desugaring, _) => { + let lang_item = match desugaring { + hir::CoroutineDesugaring::Async => LangItem::Future, + hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, + hir::CoroutineDesugaring::Gen => LangItem::Iterator, + }; + (tcx.require_lang_item(lang_item, None), None) + } + }, + ty::CoroutineClosure(..) => ( + tcx.require_lang_item(LangItem::FnOnce, None), + Some( + tcx.instantiate_bound_regions_with_erased( + instance.args.as_coroutine_closure().coroutine_closure_sig(), + ) + .tupled_inputs_ty, + ), + ), + x => bug!("Unexpected type kind for closure-like: {x:?}"), + }; + let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into)); + let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + // There should be exactly one method on this trait, and it should be the one we're + // defining. + let call = tcx + .associated_items(trait_id) + .in_definition_order() + .find(|it| it.kind == ty::AssocKind::Fn) + .expect("No call-family function on closure-like Fn trait?") + .def_id; + + instance.def = ty::InstanceDef::Virtual(call, 0); + instance.args = abstract_args; + } + } + + instance +} diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs new file mode 100644 index 00000000000..ad8b1804439 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs @@ -0,0 +1,54 @@ +//! Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI +//! support for the Rust compiler. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +use bitflags::bitflags; +use rustc_middle::ty::{Instance, Ty, TyCtxt}; +use rustc_target::abi::call::FnAbi; + +bitflags! { + /// Options for typeid_for_fnabi. + #[derive(Clone, Copy, Debug)] + pub struct TypeIdOptions: u32 { + /// Generalizes pointers for compatibility with Clang + /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI + /// support. + const GENERALIZE_POINTERS = 1; + /// Generalizes repr(C) user-defined type for extern function types with the "C" calling + /// convention (or extern types) for cross-language LLVM CFI and KCFI support. + const GENERALIZE_REPR_C = 2; + /// Normalizes integers for compatibility with Clang + /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM + /// CFI and KCFI support. + const NORMALIZE_INTEGERS = 4; + /// Do not perform self type erasure for attaching a secondary type id to methods with their + /// concrete self so they can be used as function pointers. + /// + /// (This applies to typeid_for_instance only and should be used to attach a secondary type + /// id to methods during their declaration/definition so they match the type ids returned by + /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for + /// type membership tests when methods are used as function pointers.) + const USE_CONCRETE_SELF = 8; + } +} + +pub mod itanium_cxx_abi; + +/// Returns a type metadata identifier for the specified FnAbi. +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> String { + itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options) +} + +/// Returns a type metadata identifier for the specified Instance. +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + options: TypeIdOptions, +) -> String { + itanium_cxx_abi::typeid_for_instance(tcx, instance, options) +} diff --git a/compiler/rustc_sanitizers/src/kcfi/mod.rs b/compiler/rustc_sanitizers/src/kcfi/mod.rs new file mode 100644 index 00000000000..a8b632940b0 --- /dev/null +++ b/compiler/rustc_sanitizers/src/kcfi/mod.rs @@ -0,0 +1,7 @@ +//! LLVM Kernel Control Flow Integrity (KCFI) and cross-language LLVM KCFI support for the Rust +//! compiler. +//! +//! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler, +//! see the tracking issue #123479. +pub mod typeid; +pub use crate::kcfi::typeid::{typeid_for_fnabi, typeid_for_instance, TypeIdOptions}; diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs new file mode 100644 index 00000000000..436c398e39b --- /dev/null +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -0,0 +1,55 @@ +//! Type metadata identifiers for LLVM Kernel Control Flow Integrity (KCFI) and cross-language LLVM +//! KCFI support for the Rust compiler. +//! +//! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler, +//! see the tracking issue #123479. +use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; +use rustc_target::abi::call::FnAbi; +use std::hash::Hasher; +use twox_hash::XxHash64; + +pub use crate::cfi::typeid::{itanium_cxx_abi, TypeIdOptions}; + +/// Returns a KCFI type metadata identifier for the specified FnAbi. +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> u32 { + // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the + // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write(itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes()); + hash.finish() as u32 +} + +/// Returns a KCFI type metadata identifier for the specified Instance. +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + mut options: TypeIdOptions, +) -> u32 { + // KCFI support for Rust shares most of its implementation with the CFI support, with some key + // differences: + // + // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI + // to not require LTO. + // 2. KCFI has the limitation that a function or method may have one type id assigned only. + // + // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does + // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for: + // + // * Supporting casting between function items, closures, and Fn trait objects. + // * Supporting methods being cast as function pointers. + // + // This was implemented for KCFI support in #123106 and #123052 (which introduced the + // ReifyReason). The tracking issue for KCFI support for Rust is #123479. + if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) { + options.insert(TypeIdOptions::USE_CONCRETE_SELF); + } + // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the + // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write(itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); + hash.finish() as u32 +} diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs new file mode 100644 index 00000000000..1f73e255490 --- /dev/null +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -0,0 +1,7 @@ +#![feature(let_chains)] +//! Sanitizers support for the Rust compiler. +//! +//! This crate contains the source code for providing support for the sanitizers to the Rust +//! compiler. +pub mod cfi; +pub mod kcfi; diff --git a/compiler/rustc_serialize/src/int_overflow.rs b/compiler/rustc_serialize/src/int_overflow.rs new file mode 100644 index 00000000000..f2aac2ef711 --- /dev/null +++ b/compiler/rustc_serialize/src/int_overflow.rs @@ -0,0 +1,65 @@ +// This would belong to `rustc_data_structures`, but `rustc_serialize` needs it too. + +/// Addition, but only overflow checked when `cfg(debug_assertions)` is set +/// instead of respecting `-Coverflow-checks`. +/// +/// This exists for performance reasons, as we ship rustc with overflow checks. +/// While overflow checks are perf neutral in almost all of the compiler, there +/// are a few particularly hot areas where we don't want overflow checks in our +/// dist builds. Overflow is still a bug there, so we want overflow check for +/// builds with debug assertions. +/// +/// That's a long way to say that this should be used in areas where overflow +/// is a bug but overflow checking is too slow. +pub trait DebugStrictAdd { + /// See [`DebugStrictAdd`]. + fn debug_strict_add(self, other: Self) -> Self; +} + +macro_rules! impl_debug_strict_add { + ($( $ty:ty )*) => { + $( + impl DebugStrictAdd for $ty { + fn debug_strict_add(self, other: Self) -> Self { + if cfg!(debug_assertions) { + self + other + } else { + self.wrapping_add(other) + } + } + } + )* + }; +} + +/// See [`DebugStrictAdd`]. +pub trait DebugStrictSub { + /// See [`DebugStrictAdd`]. + fn debug_strict_sub(self, other: Self) -> Self; +} + +macro_rules! impl_debug_strict_sub { + ($( $ty:ty )*) => { + $( + impl DebugStrictSub for $ty { + fn debug_strict_sub(self, other: Self) -> Self { + if cfg!(debug_assertions) { + self - other + } else { + self.wrapping_sub(other) + } + } + } + )* + }; +} + +impl_debug_strict_add! { + u8 u16 u32 u64 u128 usize + i8 i16 i32 i64 i128 isize +} + +impl_debug_strict_sub! { + u8 u16 u32 u64 u128 usize + i8 i16 i32 i64 i128 isize +} diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index ca661bac78c..44324804468 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -1,6 +1,10 @@ use crate::opaque::MemDecoder; use crate::serialize::Decoder; +// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. +// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 +use crate::int_overflow::DebugStrictAdd; + /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type pub const fn max_leb128_len<T>() -> usize { // The longest LEB128 encoding for an integer uses 7 bits per byte. @@ -24,7 +28,7 @@ macro_rules! impl_write_unsigned_leb128 { *out.get_unchecked_mut(i) = value as u8; } - i += 1; + i = i.debug_strict_add(1); break; } else { unsafe { @@ -32,7 +36,7 @@ macro_rules! impl_write_unsigned_leb128 { } value >>= 7; - i += 1; + i = i.debug_strict_add(1); } } @@ -69,7 +73,7 @@ macro_rules! impl_read_unsigned_leb128 { } else { result |= ((byte & 0x7F) as $int_ty) << shift; } - shift += 7; + shift = shift.debug_strict_add(7); } } }; @@ -101,7 +105,7 @@ macro_rules! impl_write_signed_leb128 { *out.get_unchecked_mut(i) = byte; } - i += 1; + i = i.debug_strict_add(1); if !more { break; @@ -130,7 +134,7 @@ macro_rules! impl_read_signed_leb128 { loop { byte = decoder.read_u8(); result |= <$int_ty>::from(byte & 0x7F) << shift; - shift += 7; + shift = shift.debug_strict_add(7); if (byte & 0x80) == 0 { break; diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index b67b7d79d97..5a9403e0a85 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -23,5 +23,6 @@ pub use self::serialize::{Decodable, Decoder, Encodable, Encoder}; mod serialize; +pub mod int_overflow; pub mod leb128; pub mod opaque; diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index cc8d1c25092..eec83c02d35 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -7,6 +7,10 @@ use std::ops::Range; use std::path::Path; use std::path::PathBuf; +// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. +// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 +use crate::int_overflow::DebugStrictAdd; + // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- @@ -65,7 +69,7 @@ impl FileEncoder { // Tracking position this way instead of having a `self.position` field // means that we only need to update `self.buffered` on a write call, // as opposed to updating `self.position` and `self.buffered`. - self.flushed + self.buffered + self.flushed.debug_strict_add(self.buffered) } #[cold] @@ -119,7 +123,7 @@ impl FileEncoder { } if let Some(dest) = self.buffer_empty().get_mut(..buf.len()) { dest.copy_from_slice(buf); - self.buffered += buf.len(); + self.buffered = self.buffered.debug_strict_add(buf.len()); } else { self.write_all_cold_path(buf); } @@ -158,7 +162,7 @@ impl FileEncoder { if written > N { Self::panic_invalid_write::<N>(written); } - self.buffered += written; + self.buffered = self.buffered.debug_strict_add(written); } #[cold] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d51fcf693ed..7aca86f7169 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -10,19 +10,16 @@ use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{filesearch, lint, HashStableContext}; use crate::{EarlyDiagCtxt, Session}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; -use rustc_target::abi::Align; -use rustc_target::spec::LinkSelfContainedComponents; -use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; -use rustc_target::spec::{Target, TargetTriple, TARGETS}; +use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures}; +use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -36,8 +33,11 @@ use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::LazyLock; +mod cfg; pub mod sigpipe; +pub use cfg::{Cfg, CheckCfg, ExpectedValues}; + /// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { @@ -292,6 +292,48 @@ impl LinkSelfContained { } } +/// The different values that `-Z linker-features` can take on the CLI: a list of individually +/// enabled or disabled features used during linking. +/// +/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be +/// used to turn `LinkerFeatures` on or off, without needing to change the linker flavor: +/// - using the system lld, or the self-contained `rust-lld` linker +/// - using a C/C++ compiler to drive the linker (not yet exposed on the CLI) +/// - etc. +#[derive(Default, Copy, Clone, PartialEq, Debug)] +pub struct LinkerFeaturesCli { + /// The linker features that are enabled on the CLI, using the `+feature` syntax. + pub enabled: LinkerFeatures, + + /// The linker features that are disabled on the CLI, using the `-feature` syntax. + pub disabled: LinkerFeatures, +} + +impl LinkerFeaturesCli { + /// Accumulates an enabled or disabled feature as specified on the CLI, if possible. + /// For example: `+lld`, and `-lld`. + pub(crate) fn handle_cli_feature(&mut self, feature: &str) -> Option<()> { + // Duplicate flags are reduced as we go, the last occurrence wins: + // `+feature,-feature,+feature` only enables the feature, and does not record it as both + // enabled and disabled on the CLI. + // We also only expose `+/-lld` at the moment, as it's currenty the only implemented linker + // feature and toggling `LinkerFeatures::CC` would be a noop. + match feature { + "+lld" => { + self.enabled.insert(LinkerFeatures::LLD); + self.disabled.remove(LinkerFeatures::LLD); + Some(()) + } + "-lld" => { + self.disabled.insert(LinkerFeatures::LLD); + self.enabled.remove(LinkerFeatures::LLD); + Some(()) + } + _ => None, + } + } +} + /// Used with `-Z assert-incr-state`. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum IncrementalStateAssertion { @@ -1201,346 +1243,10 @@ pub(crate) const fn default_lib_output() -> CrateType { CrateType::Rlib } -fn default_configuration(sess: &Session) -> Cfg { - let mut ret = Cfg::default(); - - macro_rules! ins_none { - ($key:expr) => { - ret.insert(($key, None)); - }; - } - macro_rules! ins_str { - ($key:expr, $val_str:expr) => { - ret.insert(($key, Some(Symbol::intern($val_str)))); - }; - } - macro_rules! ins_sym { - ($key:expr, $val_sym:expr) => { - ret.insert(($key, Some($val_sym))); - }; - } - - // Symbols are inserted in alphabetical order as much as possible. - // The exceptions are where control flow forces things out of order. - // - // Run `rustc --print cfg` to see the configuration in practice. - // - // NOTE: These insertions should be kept in sync with - // `CheckCfg::fill_well_known` below. - - if sess.opts.debug_assertions { - ins_none!(sym::debug_assertions); - } - - if sess.overflow_checks() { - ins_none!(sym::overflow_checks); - } - - ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); - - // JUSTIFICATION: before wrapper fn is available - #[allow(rustc::bad_opt_access)] - if sess.opts.crate_types.contains(&CrateType::ProcMacro) { - ins_none!(sym::proc_macro); - } - - if sess.is_nightly_build() { - ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol()); - } - - for mut s in sess.opts.unstable_opts.sanitizer { - // KASAN is still ASAN under the hood, so it uses the same attribute. - if s == SanitizerSet::KERNELADDRESS { - s = SanitizerSet::ADDRESS; - } - ins_str!(sym::sanitize, &s.to_string()); - } - - if sess.is_sanitizer_cfi_generalize_pointers_enabled() { - ins_none!(sym::sanitizer_cfi_generalize_pointers); - } - if sess.is_sanitizer_cfi_normalize_integers_enabled() { - ins_none!(sym::sanitizer_cfi_normalize_integers); - } - - ins_str!(sym::target_abi, &sess.target.abi); - ins_str!(sym::target_arch, &sess.target.arch); - ins_str!(sym::target_endian, sess.target.endian.as_str()); - ins_str!(sym::target_env, &sess.target.env); - - for family in sess.target.families.as_ref() { - ins_str!(sym::target_family, family); - if family == "windows" { - ins_none!(sym::windows); - } else if family == "unix" { - ins_none!(sym::unix); - } - } - - // `target_has_atomic*` - let layout = sess.target.parse_data_layout().unwrap_or_else(|err| { - sess.dcx().emit_fatal(err); - }); - let mut has_atomic = false; - for (i, align) in [ - (8, layout.i8_align.abi), - (16, layout.i16_align.abi), - (32, layout.i32_align.abi), - (64, layout.i64_align.abi), - (128, layout.i128_align.abi), - ] { - if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { - if !has_atomic { - has_atomic = true; - if sess.is_nightly_build() { - if sess.target.atomic_cas { - ins_none!(sym::target_has_atomic); - } - ins_none!(sym::target_has_atomic_load_store); - } - } - let mut insert_atomic = |sym, align: Align| { - if sess.target.atomic_cas { - ins_sym!(sym::target_has_atomic, sym); - } - if align.bits() == i { - ins_sym!(sym::target_has_atomic_equal_alignment, sym); - } - ins_sym!(sym::target_has_atomic_load_store, sym); - }; - insert_atomic(sym::integer(i), align); - if sess.target.pointer_width as u64 == i { - insert_atomic(sym::ptr, layout.pointer_align.abi); - } - } - } - - ins_str!(sym::target_os, &sess.target.os); - ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width)); - - if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) { - ins_none!(sym::target_thread_local); - } - - ins_str!(sym::target_vendor, &sess.target.vendor); - - // If the user wants a test runner, then add the test cfg. - if sess.is_test_crate() { - ins_none!(sym::test); - } - - ret -} - -/// The parsed `--cfg` options that define the compilation environment of the -/// crate, used to drive conditional compilation. -/// -/// An `FxIndexSet` is used to ensure deterministic ordering of error messages -/// relating to `--cfg`. -pub type Cfg = FxIndexSet<(Symbol, Option<Symbol>)>; - -/// The parsed `--check-cfg` options. -#[derive(Default)] -pub struct CheckCfg { - /// Is well known names activated - pub exhaustive_names: bool, - /// Is well known values activated - pub exhaustive_values: bool, - /// All the expected values for a config name - pub expecteds: FxHashMap<Symbol, ExpectedValues<Symbol>>, - /// Well known names (only used for diagnostics purposes) - pub well_known_names: FxHashSet<Symbol>, -} - -pub enum ExpectedValues<T> { - Some(FxHashSet<Option<T>>), - Any, -} - -impl<T: Eq + Hash> ExpectedValues<T> { - fn insert(&mut self, value: T) -> bool { - match self { - ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)), - ExpectedValues::Any => false, - } - } -} - -impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> { - fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { - match self { - ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)), - ExpectedValues::Any => {} - } - } -} - -impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> { - fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { - match self { - ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))), - ExpectedValues::Any => {} - } - } -} - -impl CheckCfg { - pub fn fill_well_known(&mut self, current_target: &Target) { - if !self.exhaustive_values && !self.exhaustive_names { - return; - } - - let no_values = || { - let mut values = FxHashSet::default(); - values.insert(None); - ExpectedValues::Some(values) - }; - - let empty_values = || { - let values = FxHashSet::default(); - ExpectedValues::Some(values) - }; - - macro_rules! ins { - ($name:expr, $values:expr) => {{ - self.well_known_names.insert($name); - self.expecteds.entry($name).or_insert_with($values) - }}; - } - - // Symbols are inserted in alphabetical order as much as possible. - // The exceptions are where control flow forces things out of order. - // - // NOTE: This should be kept in sync with `default_configuration`. - // Note that symbols inserted conditionally in `default_configuration` - // are inserted unconditionally here. - // - // When adding a new config here you should also update - // `tests/ui/check-cfg/well-known-values.rs`. - // - // Don't forget to update `src/doc/unstable-book/src/compiler-flags/check-cfg.md` - // in the unstable book as well! - - ins!(sym::debug_assertions, no_values); - - // These four are never set by rustc, but we set them anyway: they - // should not trigger a lint because `cargo clippy`, `cargo doc`, - // `cargo test` and `cargo miri run` (respectively) can set them. - ins!(sym::clippy, no_values); - ins!(sym::doc, no_values); - ins!(sym::doctest, no_values); - ins!(sym::miri, no_values); - - ins!(sym::overflow_checks, no_values); - - ins!(sym::panic, empty_values).extend(&PanicStrategy::all()); - - ins!(sym::proc_macro, no_values); - - ins!(sym::relocation_model, empty_values).extend(RelocModel::all()); - - let sanitize_values = SanitizerSet::all() - .into_iter() - .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); - ins!(sym::sanitize, empty_values).extend(sanitize_values); - - ins!(sym::sanitizer_cfi_generalize_pointers, no_values); - ins!(sym::sanitizer_cfi_normalize_integers, no_values); - - ins!(sym::target_feature, empty_values).extend( - rustc_target::target_features::all_known_features() - .map(|(f, _sb)| f) - .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned()) - .map(Symbol::intern), - ); - - // sym::target_* - { - const VALUES: [&Symbol; 8] = [ - &sym::target_abi, - &sym::target_arch, - &sym::target_endian, - &sym::target_env, - &sym::target_family, - &sym::target_os, - &sym::target_pointer_width, - &sym::target_vendor, - ]; - - // Initialize (if not already initialized) - for &e in VALUES { - if !self.exhaustive_values { - ins!(e, || ExpectedValues::Any); - } else { - ins!(e, empty_values); - } - } - - if self.exhaustive_values { - // Get all values map at once otherwise it would be costly. - // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). - let [ - values_target_abi, - values_target_arch, - values_target_endian, - values_target_env, - values_target_family, - values_target_os, - values_target_pointer_width, - values_target_vendor, - ] = self - .expecteds - .get_many_mut(VALUES) - .expect("unable to get all the check-cfg values buckets"); - - for target in TARGETS - .iter() - .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) - .chain(iter::once(current_target.clone())) - { - values_target_abi.insert(Symbol::intern(&target.options.abi)); - values_target_arch.insert(Symbol::intern(&target.arch)); - values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); - values_target_env.insert(Symbol::intern(&target.options.env)); - values_target_family.extend( - target.options.families.iter().map(|family| Symbol::intern(family)), - ); - values_target_os.insert(Symbol::intern(&target.options.os)); - values_target_pointer_width.insert(sym::integer(target.pointer_width)); - values_target_vendor.insert(Symbol::intern(&target.options.vendor)); - } - } - } - - let atomic_values = &[ - sym::ptr, - sym::integer(8usize), - sym::integer(16usize), - sym::integer(32usize), - sym::integer(64usize), - sym::integer(128usize), - ]; - for sym in [ - sym::target_has_atomic, - sym::target_has_atomic_equal_alignment, - sym::target_has_atomic_load_store, - ] { - ins!(sym, no_values).extend(atomic_values); - } - - ins!(sym::target_thread_local, no_values); - - ins!(sym::test, no_values); - - ins!(sym::unix, no_values); - ins!(sym::windows, no_values); - } -} - pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { // Combine the configuration requested by the session (command line) with // some default and generated configuration items. - user_cfg.extend(default_configuration(sess)); + user_cfg.extend(cfg::default_configuration(sess)); user_cfg } @@ -2611,13 +2317,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M check_error_format_stability(early_dcx, &unstable_opts, error_format); - if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { - early_dcx.early_fatal( - "the `-Z unstable-options` flag must also be passed to enable \ - the flag `--json=unused-externs`", - ); - } - let output_types = parse_output_types(early_dcx, &unstable_opts, matches); let mut cg = CodegenOptions::build(early_dcx, matches); diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs new file mode 100644 index 00000000000..34dcd0cf598 --- /dev/null +++ b/compiler/rustc_session/src/config/cfg.rs @@ -0,0 +1,379 @@ +//! cfg and check-cfg configuration +//! +//! This module contains the definition of [`Cfg`] and [`CheckCfg`] +//! as well as the logic for creating the default configuration for a +//! given [`Session`]. +//! +//! It also contains the filling of the well known configs, which should +//! ALWAYS be in sync with the default_configuration. +//! +//! ## Adding a new cfg +//! +//! Adding a new feature requires two new symbols one for the cfg it-self +//! and the second one for the unstable feature gate, those are defined in +//! `rustc_span::symbol`. +//! +//! As well as the following points, +//! - Add the activation logic in [`default_configuration`] +//! - Add the cfg to [`CheckCfg::fill_well_known`] (and related files), +//! so that the compiler can know the cfg is expected +//! - Add the feature gating in `compiler/rustc_feature/src/builtin_attrs.rs` + +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::Align; +use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet}; +use rustc_target::spec::{Target, TargetTriple, TARGETS}; + +use crate::config::CrateType; +use crate::Session; + +use std::hash::Hash; +use std::iter; + +/// The parsed `--cfg` options that define the compilation environment of the +/// crate, used to drive conditional compilation. +/// +/// An `FxIndexSet` is used to ensure deterministic ordering of error messages +/// relating to `--cfg`. +pub type Cfg = FxIndexSet<(Symbol, Option<Symbol>)>; + +/// The parsed `--check-cfg` options. +#[derive(Default)] +pub struct CheckCfg { + /// Is well known names activated + pub exhaustive_names: bool, + /// Is well known values activated + pub exhaustive_values: bool, + /// All the expected values for a config name + pub expecteds: FxHashMap<Symbol, ExpectedValues<Symbol>>, + /// Well known names (only used for diagnostics purposes) + pub well_known_names: FxHashSet<Symbol>, +} + +pub enum ExpectedValues<T> { + Some(FxHashSet<Option<T>>), + Any, +} + +impl<T: Eq + Hash> ExpectedValues<T> { + fn insert(&mut self, value: T) -> bool { + match self { + ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)), + ExpectedValues::Any => false, + } + } +} + +impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> { + fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { + match self { + ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)), + ExpectedValues::Any => {} + } + } +} + +impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> { + fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { + match self { + ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))), + ExpectedValues::Any => {} + } + } +} + +/// Generate the default configs for a given session +pub(crate) fn default_configuration(sess: &Session) -> Cfg { + let mut ret = Cfg::default(); + + macro_rules! ins_none { + ($key:expr) => { + ret.insert(($key, None)); + }; + } + macro_rules! ins_str { + ($key:expr, $val_str:expr) => { + ret.insert(($key, Some(Symbol::intern($val_str)))); + }; + } + macro_rules! ins_sym { + ($key:expr, $val_sym:expr) => { + ret.insert(($key, Some($val_sym))); + }; + } + + // Symbols are inserted in alphabetical order as much as possible. + // The exceptions are where control flow forces things out of order. + // + // Run `rustc --print cfg` to see the configuration in practice. + // + // NOTE: These insertions should be kept in sync with + // `CheckCfg::fill_well_known` below. + + if sess.opts.debug_assertions { + ins_none!(sym::debug_assertions); + } + + if sess.overflow_checks() { + ins_none!(sym::overflow_checks); + } + + ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); + + // JUSTIFICATION: before wrapper fn is available + #[allow(rustc::bad_opt_access)] + if sess.opts.crate_types.contains(&CrateType::ProcMacro) { + ins_none!(sym::proc_macro); + } + + if sess.is_nightly_build() { + ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol()); + } + + for mut s in sess.opts.unstable_opts.sanitizer { + // KASAN is still ASAN under the hood, so it uses the same attribute. + if s == SanitizerSet::KERNELADDRESS { + s = SanitizerSet::ADDRESS; + } + ins_str!(sym::sanitize, &s.to_string()); + } + + if sess.is_sanitizer_cfi_generalize_pointers_enabled() { + ins_none!(sym::sanitizer_cfi_generalize_pointers); + } + if sess.is_sanitizer_cfi_normalize_integers_enabled() { + ins_none!(sym::sanitizer_cfi_normalize_integers); + } + + ins_str!(sym::target_abi, &sess.target.abi); + ins_str!(sym::target_arch, &sess.target.arch); + ins_str!(sym::target_endian, sess.target.endian.as_str()); + ins_str!(sym::target_env, &sess.target.env); + + for family in sess.target.families.as_ref() { + ins_str!(sym::target_family, family); + if family == "windows" { + ins_none!(sym::windows); + } else if family == "unix" { + ins_none!(sym::unix); + } + } + + // `target_has_atomic*` + let layout = sess.target.parse_data_layout().unwrap_or_else(|err| { + sess.dcx().emit_fatal(err); + }); + let mut has_atomic = false; + for (i, align) in [ + (8, layout.i8_align.abi), + (16, layout.i16_align.abi), + (32, layout.i32_align.abi), + (64, layout.i64_align.abi), + (128, layout.i128_align.abi), + ] { + if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { + if !has_atomic { + has_atomic = true; + if sess.is_nightly_build() { + if sess.target.atomic_cas { + ins_none!(sym::target_has_atomic); + } + ins_none!(sym::target_has_atomic_load_store); + } + } + let mut insert_atomic = |sym, align: Align| { + if sess.target.atomic_cas { + ins_sym!(sym::target_has_atomic, sym); + } + if align.bits() == i { + ins_sym!(sym::target_has_atomic_equal_alignment, sym); + } + ins_sym!(sym::target_has_atomic_load_store, sym); + }; + insert_atomic(sym::integer(i), align); + if sess.target.pointer_width as u64 == i { + insert_atomic(sym::ptr, layout.pointer_align.abi); + } + } + } + + ins_str!(sym::target_os, &sess.target.os); + ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width)); + + if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) { + ins_none!(sym::target_thread_local); + } + + ins_str!(sym::target_vendor, &sess.target.vendor); + + // If the user wants a test runner, then add the test cfg. + if sess.is_test_crate() { + ins_none!(sym::test); + } + + if sess.ub_checks() { + ins_none!(sym::ub_checks); + } + + ret +} + +impl CheckCfg { + /// Fill the current [`CheckCfg`] with all the well known cfgs + pub fn fill_well_known(&mut self, current_target: &Target) { + if !self.exhaustive_values && !self.exhaustive_names { + return; + } + + // for `#[cfg(foo)]` (ie. cfg value is none) + let no_values = || { + let mut values = FxHashSet::default(); + values.insert(None); + ExpectedValues::Some(values) + }; + + // preparation for inserting some values + let empty_values = || { + let values = FxHashSet::default(); + ExpectedValues::Some(values) + }; + + macro_rules! ins { + ($name:expr, $values:expr) => {{ + self.well_known_names.insert($name); + self.expecteds.entry($name).or_insert_with($values) + }}; + } + + // Symbols are inserted in alphabetical order as much as possible. + // The exceptions are where control flow forces things out of order. + // + // NOTE: This should be kept in sync with `default_configuration`. + // Note that symbols inserted conditionally in `default_configuration` + // are inserted unconditionally here. + // + // When adding a new config here you should also update + // `tests/ui/check-cfg/well-known-values.rs` (in order to test the + // expected values of the new config) and bless the all directory. + // + // Don't forget to update `src/doc/unstable-book/src/compiler-flags/check-cfg.md` + // in the unstable book as well! + + ins!(sym::debug_assertions, no_values); + + // These four are never set by rustc, but we set them anyway: they + // should not trigger a lint because `cargo clippy`, `cargo doc`, + // `cargo test` and `cargo miri run` (respectively) can set them. + ins!(sym::clippy, no_values); + ins!(sym::doc, no_values); + ins!(sym::doctest, no_values); + ins!(sym::miri, no_values); + + ins!(sym::overflow_checks, no_values); + + ins!(sym::panic, empty_values).extend(&PanicStrategy::all()); + + ins!(sym::proc_macro, no_values); + + ins!(sym::relocation_model, empty_values).extend(RelocModel::all()); + + let sanitize_values = SanitizerSet::all() + .into_iter() + .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); + ins!(sym::sanitize, empty_values).extend(sanitize_values); + + ins!(sym::sanitizer_cfi_generalize_pointers, no_values); + ins!(sym::sanitizer_cfi_normalize_integers, no_values); + + ins!(sym::target_feature, empty_values).extend( + rustc_target::target_features::all_known_features() + .map(|(f, _sb)| f) + .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned()) + .map(Symbol::intern), + ); + + // sym::target_* + { + const VALUES: [&Symbol; 8] = [ + &sym::target_abi, + &sym::target_arch, + &sym::target_endian, + &sym::target_env, + &sym::target_family, + &sym::target_os, + &sym::target_pointer_width, + &sym::target_vendor, + ]; + + // Initialize (if not already initialized) + for &e in VALUES { + if !self.exhaustive_values { + ins!(e, || ExpectedValues::Any); + } else { + ins!(e, empty_values); + } + } + + if self.exhaustive_values { + // Get all values map at once otherwise it would be costly. + // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). + let [ + values_target_abi, + values_target_arch, + values_target_endian, + values_target_env, + values_target_family, + values_target_os, + values_target_pointer_width, + values_target_vendor, + ] = self + .expecteds + .get_many_mut(VALUES) + .expect("unable to get all the check-cfg values buckets"); + + for target in TARGETS + .iter() + .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) + .chain(iter::once(current_target.clone())) + { + values_target_abi.insert(Symbol::intern(&target.options.abi)); + values_target_arch.insert(Symbol::intern(&target.arch)); + values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); + values_target_env.insert(Symbol::intern(&target.options.env)); + values_target_family.extend( + target.options.families.iter().map(|family| Symbol::intern(family)), + ); + values_target_os.insert(Symbol::intern(&target.options.os)); + values_target_pointer_width.insert(sym::integer(target.pointer_width)); + values_target_vendor.insert(Symbol::intern(&target.options.vendor)); + } + } + } + + let atomic_values = &[ + sym::ptr, + sym::integer(8usize), + sym::integer(16usize), + sym::integer(32usize), + sym::integer(64usize), + sym::integer(128usize), + ]; + for sym in [ + sym::target_has_atomic, + sym::target_has_atomic_equal_alignment, + sym::target_has_atomic_load_store, + ] { + ins!(sym, no_values).extend(atomic_values); + } + + ins!(sym::target_thread_local, no_values); + + ins!(sym::test, no_values); + + ins!(sym::ub_checks, no_values); + + ins!(sym::unix, no_values); + ins!(sym::windows, no_values); + } +} diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index a0f5eb59b6a..cb6656bae06 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -4,12 +4,10 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; -use crate::Session; use rustc_ast as ast; use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; -use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -220,22 +218,6 @@ pub trait CrateStore: std::fmt::Debug { fn crate_name(&self, cnum: CrateNum) -> Symbol; fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId; fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum; - - /// Fetch a DefId from a DefPathHash for a foreign crate. - fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId; - fn expn_hash_to_expn_id( - &self, - sess: &Session, - cnum: CrateNum, - index_guess: u32, - hash: ExpnHash, - ) -> ExpnId; - - /// Imports all `SourceFile`s from the given crate into the current session. - /// This normally happens automatically when we decode a `Span` from - /// that crate's metadata - however, the incr comp cache needs - /// to trigger this manually when decoding a foreign `Span` - fn import_source_files(&self, sess: &Session, cnum: CrateNum); } pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4f0e3354680..aecf5954c4c 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -45,11 +45,6 @@ impl<'a> FileSearch<'a> { debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); FileSearch { sysroot, triple, search_paths, tlib_path, kind } } - - /// Returns just the directories within the search paths. - pub fn search_path_dirs(&self) -> Vec<PathBuf> { - self.search_paths().map(|sp| sp.dir.to_path_buf()).collect() - } } pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a76eb6b06aa..963c9558c17 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -426,6 +426,8 @@ mod desc { "one of supported split dwarf modes (`split` or `single`)"; pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \ components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`"; + pub const parse_linker_features: &str = + "a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld`"; pub const parse_polonius: &str = "either no value or `legacy` (the default), or `next`"; pub const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; @@ -1269,6 +1271,22 @@ mod parse { true } + /// Parse a comma-separated list of enabled and disabled linker features. + pub(crate) fn parse_linker_features(slot: &mut LinkerFeaturesCli, v: Option<&str>) -> bool { + match v { + Some(s) => { + for feature in s.split(',') { + if slot.handle_cli_feature(feature).is_none() { + return false; + } + } + + true + } + None => false, + } + } + pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool { match v { Some("command") => *slot = Some(WasiExecModel::Command), @@ -1721,6 +1739,8 @@ options! { "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), + linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED], + "a comma-separated list of linker features to enable (+) or disable (-): `lld`"), lint_mir: bool = (false, parse_bool, [UNTRACKED], "lint MIR before and after each transformation"), llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], @@ -1992,6 +2012,9 @@ written to standard error output)"), "in diagnostics, use heuristics to shorten paths referring to items"), tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), + #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] + ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED], + "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "emit compiler diagnostics in a form suitable for UI testing (default: no)"), uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 55fff4421ae..22ca8a3cf3e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -735,6 +735,10 @@ impl Session { self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions) } + pub fn ub_checks(&self) -> bool { + self.opts.unstable_opts.ub_checks.unwrap_or(self.opts.debug_assertions) + } + pub fn relocation_model(&self) -> RelocModel { self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model) } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index e8cc41cc886..0893bc31bfa 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -10,12 +10,12 @@ use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; -use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety}; +use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety}; use stable_mir::ty::{ Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, - GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind, - TraitRef, Ty, UintTy, VariantDef, VariantIdx, + GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Pattern, Region, RigidTy, Span, + TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx, }; use stable_mir::{CrateItem, CrateNum, DefId}; @@ -76,6 +76,19 @@ impl RustcInternal for Ty { } } +impl RustcInternal for Pattern { + type T<'tcx> = rustc_ty::Pattern<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.mk_pat(match self { + Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range { + start: start.as_ref().map(|c| ty_const(c, tables, tcx)), + end: end.as_ref().map(|c| ty_const(c, tables, tcx)), + include_end: *include_end, + }, + }) + } +} + impl RustcInternal for RigidTy { type T<'tcx> = rustc_ty::TyKind<'tcx>; @@ -90,6 +103,9 @@ impl RustcInternal for RigidTy { RigidTy::Array(ty, cnst) => { rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx)) } + RigidTy::Pat(ty, pat) => { + rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx)) + } RigidTy::Adt(def, args) => { rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx)) } @@ -535,6 +551,38 @@ impl RustcInternal for ProjectionElem { } } +impl RustcInternal for BinOp { + type T<'tcx> = rustc_middle::mir::BinOp; + + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + match self { + BinOp::Add => rustc_middle::mir::BinOp::Add, + BinOp::AddUnchecked => rustc_middle::mir::BinOp::AddUnchecked, + BinOp::Sub => rustc_middle::mir::BinOp::Sub, + BinOp::SubUnchecked => rustc_middle::mir::BinOp::SubUnchecked, + BinOp::Mul => rustc_middle::mir::BinOp::Mul, + BinOp::MulUnchecked => rustc_middle::mir::BinOp::MulUnchecked, + BinOp::Div => rustc_middle::mir::BinOp::Div, + BinOp::Rem => rustc_middle::mir::BinOp::Rem, + BinOp::BitXor => rustc_middle::mir::BinOp::BitXor, + BinOp::BitAnd => rustc_middle::mir::BinOp::BitAnd, + BinOp::BitOr => rustc_middle::mir::BinOp::BitOr, + BinOp::Shl => rustc_middle::mir::BinOp::Shl, + BinOp::ShlUnchecked => rustc_middle::mir::BinOp::ShlUnchecked, + BinOp::Shr => rustc_middle::mir::BinOp::Shr, + BinOp::ShrUnchecked => rustc_middle::mir::BinOp::ShrUnchecked, + BinOp::Eq => rustc_middle::mir::BinOp::Eq, + BinOp::Lt => rustc_middle::mir::BinOp::Lt, + BinOp::Le => rustc_middle::mir::BinOp::Le, + BinOp::Ne => rustc_middle::mir::BinOp::Ne, + BinOp::Ge => rustc_middle::mir::BinOp::Ge, + BinOp::Gt => rustc_middle::mir::BinOp::Gt, + BinOp::Cmp => rustc_middle::mir::BinOp::Cmp, + BinOp::Offset => rustc_middle::mir::BinOp::Offset, + } + } +} + impl<T> RustcInternal for &T where T: RustcInternal, diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 0762016ef75..221224eed01 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -4,9 +4,10 @@ //! monomorphic body using internal representation. //! After that, we convert the internal representation into a stable one. use crate::rustc_smir::{Stable, Tables}; +use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; /// Builds a monomorphic body for a given instance. pub struct BodyBuilder<'tcx> { @@ -16,46 +17,43 @@ pub struct BodyBuilder<'tcx> { impl<'tcx> BodyBuilder<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { + let instance = match instance.def { + // To get the fallback body of an intrinsic, we need to convert it to an item. + ty::InstanceDef::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), + _ => instance, + }; BodyBuilder { tcx, instance } } /// Build a stable monomorphic body for a given instance based on the MIR body. /// - /// Note that we skip instantiation for static and constants. Trying to do so can cause ICE. - /// - /// We do monomorphize non-generic functions to eval unevaluated constants. + /// All constants are also evaluated. pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body { - let mut body = self.tcx.instance_mir(self.instance.def).clone(); - if self.tcx.def_kind(self.instance.def_id()).is_fn_like() || !self.instance.args.is_empty() + let body = tables.tcx.instance_mir(self.instance.def).clone(); + let mono_body = if !self.instance.args.is_empty() + // Without the `generic_const_exprs` feature gate, anon consts in signatures do not + // get generic parameters. Which is wrong, but also not a problem without + // generic_const_exprs + || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst { - self.visit_body(&mut body); - } - body.stable(tables) - } - - fn monomorphize<T>(&self, value: T) -> T - where - T: ty::TypeFoldable<TyCtxt<'tcx>>, - { - self.instance.instantiate_mir_and_normalize_erasing_regions( - self.tcx, - ty::ParamEnv::reveal_all(), - ty::EarlyBinder::bind(value), - ) + let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions( + tables.tcx, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(body), + ); + self.visit_body(&mut mono_body); + mono_body + } else { + // Already monomorphic. + body + }; + mono_body.stable(tables) } } impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { - fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) { - *ct = self.monomorphize(*ct); - } - - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: mir::visit::TyContext) { - *ty = self.monomorphize(*ty); - } - fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) { - let const_ = self.monomorphize(constant.const_); + let const_ = constant.const_; let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), constant.span) { Ok(v) => v, Err(mir::interpret::ErrorHandled::Reported(..)) => return, @@ -68,10 +66,6 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { self.super_constant(constant, location); } - fn visit_args(&mut self, args: &mut GenericArgsRef<'tcx>, _: mir::Location) { - *args = self.monomorphize(*args); - } - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 7c12168b809..61bbedf9eec 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; -use stable_mir::mir::{Body, Place}; +use stable_mir::mir::{BinOp, Body, Place}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -668,6 +668,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; format!("{:?}", place.internal(&mut *tables, tcx)) } + + fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let rhs_internal = rhs.internal(&mut *tables, tcx); + let lhs_internal = lhs.internal(&mut *tables, tcx); + let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal); + ty.stable(&mut *tables) + } } pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 2ad8f350f10..112e44f674e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -330,6 +330,9 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { ty::Array(ty, constant) => { TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables))) } + ty::Pat(ty, pat) => { + TyKind::RigidTy(RigidTy::Pat(ty.stable(tables), pat.stable(tables))) + } ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))), ty::RawPtr(ty, mutbl) => { TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables))) @@ -385,6 +388,20 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { } } +impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { + type T = stable_mir::ty::Pattern; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + match **self { + ty::PatternKind::Range { start, end, include_end } => stable_mir::ty::Pattern::Range { + start: start.stable(tables), + end: end.stable(tables), + include_end, + }, + } + } +} + impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { type T = stable_mir::ty::Const; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7ce879807ca..c1e1175b4bd 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -743,6 +743,45 @@ impl Span { Some(self) } + /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same + /// [`SyntaxContext`] the initial span. + /// + /// This method is suitable for peeling through *local* macro expansions to find the "innermost" + /// span that is still local and shares the same [`SyntaxContext`]. For example, given + /// + /// ```ignore (illustrative example, contains type error) + /// macro_rules! outer { + /// ($x: expr) => { + /// inner!($x) + /// } + /// } + /// + /// macro_rules! inner { + /// ($x: expr) => { + /// format!("error: {}", $x) + /// //~^ ERROR mismatched types + /// } + /// } + /// + /// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> { + /// Err(outer!(x)) + /// } + /// ``` + /// + /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse + /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the + /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the + /// initial span. + pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span { + let mut cur = self; + while cur.eq_ctxt(self) + && let Some(parent_callsite) = cur.parent_callsite() + { + cur = parent_callsite; + } + cur + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 770624d331d..93d5f06a167 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -218,7 +218,7 @@ impl SourceMap { /// /// Unlike `load_file`, guarantees that no normalization like BOM-removal /// takes place. - pub fn load_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>> { + pub fn load_binary_file(&self, path: &Path) -> io::Result<(Lrc<[u8]>, Span)> { let bytes = self.file_loader.read_binary_file(path)?; // We need to add file to the `SourceMap`, so that it is present @@ -227,8 +227,16 @@ impl SourceMap { // via `mod`, so we try to use real file contents and not just an // empty string. let text = std::str::from_utf8(&bytes).unwrap_or("").to_string(); - self.new_source_file(path.to_owned().into(), text); - Ok(bytes) + let file = self.new_source_file(path.to_owned().into(), text); + Ok(( + bytes, + Span::new( + file.start_pos, + BytePos(file.start_pos.0 + file.source_len.0), + SyntaxContext::root(), + None, + ), + )) } // By returning a `MonotonicVec`, we ensure that consumers cannot invalidate @@ -654,6 +662,12 @@ impl SourceMap { }) } + /// Extends the span to include any trailing whitespace, or returns the original + /// span if a `SpanSnippetError` was encountered. + pub fn span_extend_while_whitespace(&self, span: Span) -> Span { + self.span_extend_while(span, char::is_whitespace).unwrap_or(span) + } + /// Extends the given `Span` to previous character while the previous character matches the predicate pub fn span_extend_prev_while( &self, @@ -1034,12 +1048,9 @@ impl SourceMap { /// // ^^^^^^ input /// ``` pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> { - let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?; - let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?)); - if self.span_to_snippet(span).as_deref() != Ok(";") { - return None; - } - Some(span) + let span = self.span_extend_while_whitespace(mac_call); + let span = self.next_point(span); + if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None } } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index e162695a13b..788a52faf56 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -5,6 +5,10 @@ use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; +// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. +// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 +use rustc_serialize::int_overflow::DebugStrictAdd; + /// A compressed span. /// /// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` only @@ -166,7 +170,7 @@ impl Span { debug_assert!(len <= MAX_LEN); SpanData { lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index + len), + hi: BytePos(self.lo_or_index.debug_strict_add(len)), ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), parent: None, } @@ -179,7 +183,7 @@ impl Span { }; SpanData { lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index + len), + hi: BytePos(self.lo_or_index.debug_strict_add(len)), ctxt: SyntaxContext::root(), parent: Some(parent), } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ea0f7adf6f9..bfd0f77c237 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -514,6 +514,7 @@ symbols! { cfg_target_has_atomic_equal_alignment, cfg_target_thread_local, cfg_target_vendor, + cfg_ub_checks, cfg_version, cfi, cfi_encoding, @@ -1008,6 +1009,7 @@ symbols! { io_stderr, io_stdout, irrefutable_let_patterns, + is, is_val_statically_known, isa_attribute, isize, @@ -1346,6 +1348,8 @@ symbols! { path, pattern_complexity, pattern_parentheses, + pattern_type, + pattern_types, phantom_data, pic, pie, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 1c8f1d03670..65aa9e40c8b 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" punycode = "0.4.0" rustc-demangle = "0.1.21" rustc_data_structures = { path = "../rustc_data_structures" } @@ -15,7 +14,5 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" -twox-hash = "1.6.3" # tidy-alphabetical-end diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 0588af9bda7..b9509478702 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -114,7 +114,6 @@ mod v0; pub mod errors; pub mod test; -pub mod typeid; /// This function computes the symbol name for the given `instance` and the /// given instantiating crate. That is, if you know that instance X is diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs deleted file mode 100644 index 7bd998294dd..00000000000 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ /dev/null @@ -1,100 +0,0 @@ -/// Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI -/// support. -/// -/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, -/// see design document in the tracking issue #89653. -use bitflags::bitflags; -use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; -use rustc_target::abi::call::FnAbi; -use std::hash::Hasher; -use twox_hash::XxHash64; - -bitflags! { - /// Options for typeid_for_fnabi. - #[derive(Clone, Copy, Debug)] - pub struct TypeIdOptions: u32 { - /// Generalizes pointers for compatibility with Clang - /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI - /// support. - const GENERALIZE_POINTERS = 1; - /// Generalizes repr(C) user-defined type for extern function types with the "C" calling - /// convention (or extern types) for cross-language LLVM CFI and KCFI support. - const GENERALIZE_REPR_C = 2; - /// Normalizes integers for compatibility with Clang - /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM - /// CFI and KCFI support. - const NORMALIZE_INTEGERS = 4; - /// Do not perform self type erasure for attaching a secondary type id to methods with their - /// concrete self so they can be used as function pointers. - /// - /// (This applies to typeid_for_instance only and should be used to attach a secondary type - /// id to methods during their declaration/definition so they match the type ids returned by - /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for - /// type membership tests when methods are used as function pointers.) - const USE_CONCRETE_SELF = 8; - } -} - -mod typeid_itanium_cxx_abi; - -/// Returns a type metadata identifier for the specified FnAbi. -pub fn typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> String { - typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options) -} - -/// Returns a type metadata identifier for the specified Instance. -pub fn typeid_for_instance<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - options: TypeIdOptions, -) -> String { - typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options) -} - -/// Returns a KCFI type metadata identifier for the specified FnAbi. -pub fn kcfi_typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> u32 { - // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the - // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) - let mut hash: XxHash64 = Default::default(); - hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes()); - hash.finish() as u32 -} - -/// Returns a KCFI type metadata identifier for the specified Instance. -pub fn kcfi_typeid_for_instance<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - mut options: TypeIdOptions, -) -> u32 { - // KCFI support for Rust shares most of its implementation with the CFI support, with some key - // differences: - // - // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI - // to not require LTO. - // 2. KCFI has the limitation that a function or method may have one type id assigned only. - // - // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does - // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for: - // - // * Supporting casting between function items, closures, and Fn trait objects. - // * Supporting methods being cast as function pointers. - // - // This was implemented for KCFI support in #123106 and #123052 (which introduced the - // ReifyReason). The tracking issue for KCFI support for Rust is #123479. - if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) { - options.insert(TypeIdOptions::USE_CONCRETE_SELF); - } - // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the - // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) - let mut hash: XxHash64 = Default::default(); - hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); - hash.finish() as u32 -} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 8cb5370bb4a..58b67c77a61 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -45,8 +45,8 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::ThreadLocalShim(_) => Some("tls"), ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_, None) => Some("reify"), - ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"), - ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"), + ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), + ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), @@ -371,6 +371,25 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty.print(self)?; } + ty::Pat(ty, pat) => match *pat { + ty::PatternKind::Range { start, end, include_end } => { + let consts = [ + start.unwrap_or(self.tcx.consts.unit), + end.unwrap_or(self.tcx.consts.unit), + ty::Const::from_bool(self.tcx, include_end).into(), + ]; + // HACK: Represent as tuple until we have something better. + // HACK: constants are used in arrays, even if the types don't match. + self.push("T"); + ty.print(self)?; + for ct in consts { + Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct) + .print(self)?; + } + self.push("E"); + } + }, + ty::Array(ty, len) => { self.push("A"); ty.print(self)?; @@ -812,7 +831,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { /// 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); + base_n::push_str(x as u128, base_n::ALPHANUMERIC_ONLY, output); } output.push('_'); } diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index f99f6a3b721..04020d13f22 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -31,7 +31,7 @@ where RegKind::Vector => size.bits() == 64 || size.bits() == 128, }; - valid_unit.then_some(Uniform { unit, total: size }) + valid_unit.then_some(Uniform::consecutive(unit, size)) }) } @@ -60,7 +60,7 @@ where let size = ret.layout.size; let bits = size.bits(); if bits <= 128 { - ret.cast_to(Uniform { unit: Reg::i64(), total: size }); + ret.cast_to(Uniform::new(Reg::i64(), size)); return; } ret.make_indirect(); @@ -100,9 +100,9 @@ where }; if size.bits() <= 128 { if align.bits() == 128 { - arg.cast_to(Uniform { unit: Reg::i128(), total: size }); + arg.cast_to(Uniform::new(Reg::i128(), size)); } else { - arg.cast_to(Uniform { unit: Reg::i64(), total: size }); + arg.cast_to(Uniform::new(Reg::i64(), size)); } return; } diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs index 95f6691d42a..9371e1b3958 100644 --- a/compiler/rustc_target/src/abi/call/arm.rs +++ b/compiler/rustc_target/src/abi/call/arm.rs @@ -21,7 +21,7 @@ where RegKind::Vector => size.bits() == 64 || size.bits() == 128, }; - valid_unit.then_some(Uniform { unit, total: size }) + valid_unit.then_some(Uniform::consecutive(unit, size)) }) } @@ -49,7 +49,7 @@ where let size = ret.layout.size; let bits = size.bits(); if bits <= 32 { - ret.cast_to(Uniform { unit: Reg::i32(), total: size }); + ret.cast_to(Uniform::new(Reg::i32(), size)); return; } ret.make_indirect(); @@ -78,7 +78,7 @@ where let align = arg.layout.align.abi.bytes(); let total = arg.layout.size; - arg.cast_to(Uniform { unit: if align <= 4 { Reg::i32() } else { Reg::i64() }, total }); + arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total)); } pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/abi/call/csky.rs index 8b4328db52e..7951f28beea 100644 --- a/compiler/rustc_target/src/abi/call/csky.rs +++ b/compiler/rustc_target/src/abi/call/csky.rs @@ -18,7 +18,7 @@ fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) { if total.bits() > 64 { arg.make_indirect(); } else if total.bits() > 32 { - arg.cast_to(Uniform { unit: Reg::i32(), total }); + arg.cast_to(Uniform::new(Reg::i32(), total)); } else { arg.cast_to(Reg::i32()); } @@ -38,7 +38,7 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { if arg.layout.is_aggregate() { let total = arg.layout.size; if total.bits() > 32 { - arg.cast_to(Uniform { unit: Reg::i32(), total }); + arg.cast_to(Uniform::new(Reg::i32(), total)); } else { arg.cast_to(Reg::i32()); } diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs index 35d4b331cb4..943b12a9fbf 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/abi/call/loongarch.rs @@ -195,7 +195,7 @@ where if total.bits() <= xlen { arg.cast_to(xlen_reg); } else { - arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) }); + arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2))); } return false; } @@ -278,10 +278,10 @@ fn classify_arg<'a, Ty, C>( if total.bits() > xlen { let align_regs = align > xlen; if is_loongarch_aggregate(arg) { - arg.cast_to(Uniform { - unit: if align_regs { double_xlen_reg } else { xlen_reg }, - total: Size::from_bits(xlen * 2), - }); + arg.cast_to(Uniform::new( + if align_regs { double_xlen_reg } else { xlen_reg }, + Size::from_bits(xlen * 2), + )); } if align_regs && is_vararg { *avail_gprs -= *avail_gprs % 2; diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs index 57ccfe2152b..0e5a7f37a09 100644 --- a/compiler/rustc_target/src/abi/call/mips.rs +++ b/compiler/rustc_target/src/abi/call/mips.rs @@ -27,7 +27,7 @@ where if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); - arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32); + arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs index 2700f67b209..b2a2c34b980 100644 --- a/compiler/rustc_target/src/abi/call/mips64.rs +++ b/compiler/rustc_target/src/abi/call/mips64.rs @@ -68,7 +68,7 @@ where } // Cast to a uniform int structure - ret.cast_to(Uniform { unit: Reg::i64(), total: size }); + ret.cast_to(Uniform::new(Reg::i64(), size)); } else { ret.make_indirect(); } @@ -139,7 +139,7 @@ where let rest_size = size - Size::from_bytes(8) * prefix_index as u64; arg.cast_to(CastTarget { prefix, - rest: Uniform { unit: Reg::i64(), total: rest_size }, + rest: Uniform::new(Reg::i64(), rest_size), attrs: ArgAttributes { regular: ArgAttribute::default(), arg_ext: ArgExtension::None, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index cdd3f0afd79..4502df339d1 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -255,11 +255,16 @@ pub struct Uniform { /// for 64-bit integers with a total size of 20 bytes. When the argument is actually passed, /// this size will be rounded up to the nearest multiple of `unit.size`. pub total: Size, + + /// Indicate that the argument is consecutive, in the sense that either all values need to be + /// passed in register, or all on the stack. If they are passed on the stack, there should be + /// no additional padding between elements. + pub is_consecutive: bool, } impl From<Reg> for Uniform { fn from(unit: Reg) -> Uniform { - Uniform { unit, total: unit.size } + Uniform { unit, total: unit.size, is_consecutive: false } } } @@ -267,6 +272,18 @@ impl Uniform { pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { self.unit.align(cx) } + + /// Pass using one or more values of the given type, without requiring them to be consecutive. + /// That is, some values may be passed in register and some on the stack. + pub fn new(unit: Reg, total: Size) -> Self { + Uniform { unit, total, is_consecutive: false } + } + + /// Pass using one or more consecutive values of the given type. Either all values will be + /// passed in registers, or all on the stack. + pub fn consecutive(unit: Reg, total: Size) -> Self { + Uniform { unit, total, is_consecutive: true } + } } /// Describes the type used for `PassMode::Cast`. diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs index 5c040ce9c3b..f85fa2419f0 100644 --- a/compiler/rustc_target/src/abi/call/nvptx64.rs +++ b/compiler/rustc_target/src/abi/call/nvptx64.rs @@ -35,7 +35,7 @@ where 16 => Reg::i128(), _ => unreachable!("Align is given as power of 2 no larger than 16 bytes"), }; - arg.cast_to(Uniform { unit, total: Size::from_bytes(2 * align_bytes) }); + arg.cast_to(Uniform::new(unit, Size::from_bytes(2 * align_bytes))); } else { // FIXME: find a better way to do this. See https://github.com/rust-lang/rust/issues/117271. arg.make_direct_deprecated(); diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs index 2d41f77e50e..11a6cb52bab 100644 --- a/compiler/rustc_target/src/abi/call/powerpc64.rs +++ b/compiler/rustc_target/src/abi/call/powerpc64.rs @@ -2,7 +2,7 @@ // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; +use crate::abi::call::{Align, ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::abi::{Endian, HasDataLayout, TyAbiInterface}; use crate::spec::HasTargetSpec; @@ -37,7 +37,7 @@ where RegKind::Vector => arg.layout.size.bits() == 128, }; - valid_unit.then_some(Uniform { unit, total: arg.layout.size }) + valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size)) }) } @@ -81,7 +81,7 @@ where Reg::i64() }; - ret.cast_to(Uniform { unit, total: size }); + ret.cast_to(Uniform::new(unit, size)); return; } @@ -108,18 +108,20 @@ where } let size = arg.layout.size; - let (unit, total) = if size.bits() <= 64 { + if size.bits() <= 64 { // Aggregates smaller than a doubleword should appear in // the least-significant bits of the parameter doubleword. - (Reg { kind: RegKind::Integer, size }, size) + arg.cast_to(Reg { kind: RegKind::Integer, size }) } else { - // Aggregates larger than a doubleword should be padded - // at the tail to fill out a whole number of doublewords. - let reg_i64 = Reg::i64(); - (reg_i64, size.align_to(reg_i64.align(cx))) + // Aggregates larger than i64 should be padded at the tail to fill out a whole number + // of i64s or i128s, depending on the aggregate alignment. Always use an array for + // this, even if there is only a single element. + let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() }; + arg.cast_to(Uniform::consecutive( + reg, + size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()), + )) }; - - arg.cast_to(Uniform { unit, total }); } pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 6a38496dc57..5d4b3a9d245 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -201,7 +201,7 @@ where if total.bits() <= xlen { arg.cast_to(xlen_reg); } else { - arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) }); + arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2))); } return false; } @@ -284,10 +284,10 @@ fn classify_arg<'a, Ty, C>( if total.bits() > xlen { let align_regs = align > xlen; if is_riscv_aggregate(arg) { - arg.cast_to(Uniform { - unit: if align_regs { double_xlen_reg } else { xlen_reg }, - total: Size::from_bits(xlen * 2), - }); + arg.cast_to(Uniform::new( + if align_regs { double_xlen_reg } else { xlen_reg }, + Size::from_bits(xlen * 2), + )); } if align_regs && is_vararg { *avail_gprs -= *avail_gprs % 2; diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs index 57ccfe2152b..0e5a7f37a09 100644 --- a/compiler/rustc_target/src/abi/call/sparc.rs +++ b/compiler/rustc_target/src/abi/call/sparc.rs @@ -27,7 +27,7 @@ where if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); - arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32); + arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index cbed5b4afc1..acdcd5cc0d4 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -192,7 +192,7 @@ where arg.cast_to(CastTarget { prefix: data.prefix, - rest: Uniform { unit: Reg::i64(), total: rest_size }, + rest: Uniform::new(Reg::i64(), rest_size), attrs: ArgAttributes { regular: data.arg_attribute, arg_ext: ArgExtension::None, @@ -205,7 +205,7 @@ where } } - arg.cast_to(Uniform { unit: Reg::i64(), total }); + arg.cast_to(Uniform::new(Reg::i64(), total)); } pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs index a7a2b314a94..a773fb1e814 100644 --- a/compiler/rustc_target/src/abi/call/wasm.rs +++ b/compiler/rustc_target/src/abi/call/wasm.rs @@ -1,4 +1,4 @@ -use crate::abi::call::{ArgAbi, FnAbi, Uniform}; +use crate::abi::call::{ArgAbi, FnAbi}; use crate::abi::{HasDataLayout, TyAbiInterface}; fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool @@ -10,7 +10,7 @@ where if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) { let size = val.layout.size; if unit.size == size { - val.cast_to(Uniform { unit, total: size }); + val.cast_to(unit); return true; } } diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 70528c1222c..5ae9a2e2058 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -87,6 +87,20 @@ fn reserved_x18( } } +fn restricted_for_arm64ec( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet<Symbol>, + _target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if arch == InlineAsmArch::Arm64EC { + Err("x13, x14, x23, x24, x28, v16-v31 cannot be used for Arm64EC") + } else { + Ok(()) + } +} + def_regs! { AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass { x0: reg = ["x0", "w0"], @@ -102,8 +116,8 @@ def_regs! { x10: reg = ["x10", "w10"], x11: reg = ["x11", "w11"], x12: reg = ["x12", "w12"], - x13: reg = ["x13", "w13"], - x14: reg = ["x14", "w14"], + x13: reg = ["x13", "w13"] % restricted_for_arm64ec, + x14: reg = ["x14", "w14"] % restricted_for_arm64ec, x15: reg = ["x15", "w15"], x16: reg = ["x16", "w16"], x17: reg = ["x17", "w17"], @@ -111,12 +125,12 @@ def_regs! { x20: reg = ["x20", "w20"], x21: reg = ["x21", "w21"], x22: reg = ["x22", "w22"], - x23: reg = ["x23", "w23"], - x24: reg = ["x24", "w24"], + x23: reg = ["x23", "w23"] % restricted_for_arm64ec, + x24: reg = ["x24", "w24"] % restricted_for_arm64ec, x25: reg = ["x25", "w25"], x26: reg = ["x26", "w26"], x27: reg = ["x27", "w27"], - x28: reg = ["x28", "w28"], + x28: reg = ["x28", "w28"] % restricted_for_arm64ec, x30: reg = ["x30", "w30", "lr", "wlr"], v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"], v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"], @@ -134,22 +148,22 @@ def_regs! { v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"], v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"], v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"], - v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"], - v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"], - v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"], - v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"], - v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"], - v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"], - v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"], - v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"], - v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"], - v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"], - v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"], - v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"], - v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"], - v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"], - v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"], - v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"], + v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"] % restricted_for_arm64ec, + v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"] % restricted_for_arm64ec, + v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"] % restricted_for_arm64ec, + v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"] % restricted_for_arm64ec, + v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"] % restricted_for_arm64ec, + v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"] % restricted_for_arm64ec, + v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"] % restricted_for_arm64ec, + v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"] % restricted_for_arm64ec, + v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"] % restricted_for_arm64ec, + v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"] % restricted_for_arm64ec, + v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"] % restricted_for_arm64ec, + v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"] % restricted_for_arm64ec, + v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"] % restricted_for_arm64ec, + v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"] % restricted_for_arm64ec, + v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"] % restricted_for_arm64ec, + v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"] % restricted_for_arm64ec, p0: preg = ["p0"], p1: preg = ["p1"], p2: preg = ["p2"], diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 2e04dca98c5..49de92b86cb 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -9,11 +9,11 @@ use std::str::FromStr; pub struct ModifierInfo { pub modifier: char, pub result: &'static str, - pub size: u64, + pub size: u16, } -impl From<(char, &'static str, u64)> for ModifierInfo { - fn from((modifier, result, size): (char, &'static str, u64)) -> Self { +impl From<(char, &'static str, u16)> for ModifierInfo { + fn from((modifier, result, size): (char, &'static str, u16)) -> Self { Self { modifier, result, size } } } @@ -217,6 +217,7 @@ pub enum InlineAsmArch { X86_64, Arm, AArch64, + Arm64EC, RiscV32, RiscV64, Nvptx64, @@ -246,6 +247,7 @@ impl FromStr for InlineAsmArch { "x86_64" => Ok(Self::X86_64), "arm" => Ok(Self::Arm), "aarch64" => Ok(Self::AArch64), + "arm64ec" => Ok(Self::Arm64EC), "riscv32" => Ok(Self::RiscV32), "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), @@ -341,7 +343,9 @@ impl InlineAsmReg { Ok(match arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?), InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?), - InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?), + InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => { + Self::AArch64(AArch64InlineAsmReg::parse(name)?) + } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { Self::RiscV(RiscVInlineAsmReg::parse(name)?) } @@ -610,7 +614,9 @@ impl InlineAsmRegClass { Self::X86(X86InlineAsmRegClass::parse(name)?) } InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?), - InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?), + InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => { + Self::AArch64(AArch64InlineAsmRegClass::parse(name)?) + } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { Self::RiscV(RiscVInlineAsmRegClass::parse(name)?) } @@ -783,7 +789,7 @@ pub fn allocatable_registers( arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } - InlineAsmArch::AArch64 => { + InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => { let mut map = aarch64::regclass_map(); aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map @@ -909,6 +915,10 @@ impl InlineAsmClobberAbi { }), _ => Err(&["C", "system", "efiapi"]), }, + InlineAsmArch::Arm64EC => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::AArch64NoX18), + _ => Err(&["C", "system"]), + }, InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name { "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV), _ => Err(&["C", "system", "efiapi"]), diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 96da0b6fd1f..021457b145f 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -368,6 +368,11 @@ fn watchos_deployment_target() -> (u32, u32) { from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) } +pub fn watchos_llvm_target(arch: Arch) -> String { + let (major, minor) = watchos_deployment_target(); + format!("{}-apple-watchos{}.{}.0", arch.target_name(), major, minor) +} + pub fn watchos_sim_llvm_target(arch: Arch) -> String { let (major, minor) = watchos_deployment_target(); format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor) diff --git a/compiler/rustc_target/src/spec/base/msvc.rs b/compiler/rustc_target/src/spec/base/msvc.rs index efe949a4e90..44fc376fea0 100644 --- a/compiler/rustc_target/src/spec/base/msvc.rs +++ b/compiler/rustc_target/src/spec/base/msvc.rs @@ -14,6 +14,7 @@ pub fn opts() -> TargetOptions { pre_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + archive_format: "coff".into(), // Currently this is the only supported method of debuginfo on MSVC // where `*.pdb` files show up next to the final artifact. diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index e94c7f3cc58..3a69b19ee60 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -448,6 +448,28 @@ impl LinkerFlavor { | LinkerFlavor::Ptx => false, } } + + /// For flavors with an `Lld` component, ensure it's enabled. Otherwise, returns the given + /// flavor unmodified. + pub fn with_lld_enabled(self) -> LinkerFlavor { + match self { + LinkerFlavor::Gnu(cc, Lld::No) => LinkerFlavor::Gnu(cc, Lld::Yes), + LinkerFlavor::Darwin(cc, Lld::No) => LinkerFlavor::Darwin(cc, Lld::Yes), + LinkerFlavor::Msvc(Lld::No) => LinkerFlavor::Msvc(Lld::Yes), + _ => self, + } + } + + /// For flavors with an `Lld` component, ensure it's disabled. Otherwise, returns the given + /// flavor unmodified. + pub fn with_lld_disabled(self) -> LinkerFlavor { + match self { + LinkerFlavor::Gnu(cc, Lld::Yes) => LinkerFlavor::Gnu(cc, Lld::No), + LinkerFlavor::Darwin(cc, Lld::Yes) => LinkerFlavor::Darwin(cc, Lld::No), + LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavor::Msvc(Lld::No), + _ => self, + } + } } macro_rules! linker_flavor_cli_impls { @@ -698,6 +720,58 @@ impl ToJson for LinkSelfContainedComponents { } } +bitflags::bitflags! { + /// The `-Z linker-features` components that can individually be enabled or disabled. + /// + /// They are feature flags intended to be a more flexible mechanism than linker flavors, and + /// also to prevent a combinatorial explosion of flavors whenever a new linker feature is + /// required. These flags are "generic", in the sense that they can work on multiple targets on + /// the CLI. Otherwise, one would have to select different linkers flavors for each target. + /// + /// Here are some examples of the advantages they offer: + /// - default feature sets for principal flavors, or for specific targets. + /// - flavor-specific features: for example, clang offers automatic cross-linking with + /// `--target`, which gcc-style compilers don't support. The *flavor* is still a C/C++ + /// compiler, and we don't need to multiply the number of flavors for this use-case. Instead, + /// we can have a single `+target` feature. + /// - umbrella features: for example if clang accumulates more features in the future than just + /// the `+target` above. That could be modeled as `+clang`. + /// - niche features for resolving specific issues: for example, on Apple targets the linker + /// flag implementing the `as-needed` native link modifier (#99424) is only possible on + /// sufficiently recent linker versions. + /// - still allows for discovery and automation, for example via feature detection. This can be + /// useful in exotic environments/build systems. + #[derive(Clone, Copy, PartialEq, Eq, Default)] + pub struct LinkerFeatures: u8 { + /// Invoke the linker via a C/C++ compiler (e.g. on most unix targets). + const CC = 1 << 0; + /// Use the lld linker, either the system lld or the self-contained linker `rust-lld`. + const LLD = 1 << 1; + } +} +rustc_data_structures::external_bitflags_debug! { LinkerFeatures } + +impl LinkerFeatures { + /// Parses a single `-Z linker-features` well-known feature, not a set of flags. + pub fn from_str(s: &str) -> Option<LinkerFeatures> { + Some(match s { + "cc" => LinkerFeatures::CC, + "lld" => LinkerFeatures::LLD, + _ => return None, + }) + } + + /// Returns whether the `lld` linker feature is enabled. + pub fn is_lld_enabled(self) -> bool { + self.contains(LinkerFeatures::LLD) + } + + /// Returns whether the `cc` linker feature is enabled. + pub fn is_cc_enabled(self) -> bool { + self.contains(LinkerFeatures::CC) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum PanicStrategy { Unwind, diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index 9bf09b4376d..f842a834c05 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -1,10 +1,11 @@ -use crate::spec::base::apple::{opts, Arch}; +use crate::spec::base::apple::{opts, watchos_llvm_target, Arch}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { - let base = opts("watchos", Arch::Arm64_32); + let arch = Arch::Arm64_32; + let base = opts("watchos", arch); Target { - llvm_target: "arm64_32-apple-watchos".into(), + llvm_target: watchos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { description: None, tier: None, 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 becd2fd7afb..970b43ad109 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 @@ -18,8 +18,6 @@ pub fn target() -> Target { "/SAFESEH", ], ); - // Workaround for #95429 - base.has_thread_local = false; Target { llvm_target: "i686-pc-windows-msvc".into(), 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 b68316f2830..ae1a44e44a8 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 @@ -18,8 +18,6 @@ pub fn target() -> Target { "/SAFESEH", ], ); - // Workaround for #95429 - base.has_thread_local = false; Target { llvm_target: "i686-pc-windows-msvc".into(), diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 7056288e758..0595e82b39e 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,5 +1,5 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, DefiningAnchor, ObligationCtxt, SelectionContext}; +use crate::traits::{self, ObligationCtxt, SelectionContext}; use crate::traits::TraitEngineExt as _; use rustc_hir::def_id::DefId; @@ -132,9 +132,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { R: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, { - let (infcx, key, canonical_inference_vars) = self - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build_with_canonical(DUMMY_SP, canonical_key); + let (infcx, key, canonical_inference_vars) = + self.build_with_canonical(DUMMY_SP, canonical_key); let ocx = ObligationCtxt::new(&infcx); let value = operation(&ocx, key)?; ocx.make_canonicalized_query_response(canonical_inference_vars, value) diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index b5fb710e4cc..057d00aeae8 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -22,6 +22,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extract_if)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(option_take_if)] #![feature(never_type)] diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 35f7d1d7151..8b5c029428c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -363,6 +363,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -596,6 +597,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -684,6 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) 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 00cd4b48797..a778414d9d1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -50,7 +50,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( Ok(vec![ty::Binder::dummy(element_ty)]) } - ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]), + ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => { + Ok(vec![ty::Binder::dummy(element_ty)]) + } ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet @@ -114,6 +116,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Array(..) + | ty::Pat(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -177,6 +180,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Ref(_, _, Mutability::Not) | ty::Array(..) => Err(NoSolution), + // Cannot implement in core, as we can't be generic over patterns yet, + // so we'd have to list all patterns and type combinations. + ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]), + ty::Dynamic(..) | ty::Str | ty::Slice(_) @@ -285,7 +292,9 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); - let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() + && !args.tupled_upvars_ty().is_ty_var() + { if !closure_kind.extends(goal_kind) { return Err(NoSolution); } @@ -347,6 +356,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) + | ty::Pat(_, _) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) @@ -393,7 +403,9 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); let mut nested = vec![]; - let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() + && !args.tupled_upvars_ty().is_ty_var() + { if !closure_kind.extends(goal_kind) { return Err(NoSolution); } @@ -526,6 +538,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 4a4efb6884f..0b37163d597 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -68,7 +68,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut orig_values, QueryInput { goal, - anchor: self.infcx.defining_use_anchor, predefined_opaques_in_body: self .tcx() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 1739bd70e7b..0154aff12b6 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1,5 +1,5 @@ use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -230,7 +230,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { .infer_ctxt() .intercrate(intercrate) .with_next_trait_solver(true) - .with_opaque_type_inference(canonical_input.value.anchor) .build_with_canonical(DUMMY_SP, &canonical_input); let mut ecx = EvalCtxt { @@ -936,8 +935,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - pub(super) fn can_define_opaque_ty(&self, def_id: LocalDefId) -> bool { - self.infcx.opaque_type_origin(def_id).is_some() + pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool { + self.infcx.can_define_opaque_ty(def_id) } pub(super) fn insert_hidden_type( diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 8294a8a67b1..da5cd15a10d 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -316,5 +316,6 @@ fn response_no_constraints_raw<'tcx>( external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), certainty, }, + defining_opaque_types: Default::default(), } } 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 fb296d55100..ebf2a0d9621 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -487,6 +487,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { bug!(); }; + // Bail if the upvars haven't been constrained. + if tupled_upvars_ty.expect_ty().is_ty_var() { + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + 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); @@ -533,6 +538,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Uint(..) | ty::Float(..) | ty::Array(..) + | ty::Pat(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) @@ -768,6 +774,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Uint(..) | ty::Float(..) | ty::Array(..) + | ty::Pat(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index eb3ad0aa782..e522339358a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -155,10 +155,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { if matches!(goal.param_env.reveal(), Reveal::All) || matches!(ecx.solver_mode(), SolverMode::Coherence) - || opaque_ty - .def_id - .as_local() - .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) + || ecx.can_define_opaque_ty(opaque_ty.def_id) { return Err(NoSolution); } @@ -1051,6 +1048,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Float(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8625ad378f7..77eaa4fd03e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -883,6 +883,7 @@ where | ty::Float(..) | ty::Str | ty::FnDef(..) + | ty::Pat(..) | ty::FnPtr(_) | ty::Array(..) | ty::Slice(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index ddb582ffab0..e6cb28df593 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -5,6 +5,7 @@ use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation}; use rustc_middle::ty; use rustc_span::{Span, DUMMY_SP}; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::ObligationCtxt; #[derive(Debug)] @@ -52,10 +53,21 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( _ => return false, } - let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args); - ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { - Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) - })); + let obligations = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_args) + .into_iter() + .map(|(predicate, _)| { + Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) + }) + // Kinda hacky, but let's just throw away obligations that overflow. + // This may reduce the accuracy of this check (if the obligation guides + // inference or it actually resulted in error after others are processed) + // ... but this is diagnostics code. + .filter(|obligation| { + infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok() + }); + ocx.register_obligations(obligations); ocx.select_where_possible().is_empty() }) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 10c03387a5b..837b784f272 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -40,7 +40,7 @@ pub struct ImplCandidate<'tcx> { enum GetSafeTransmuteErrorAndReason { Silent, - Error { err_msg: String, safe_transmute_explanation: String }, + Error { err_msg: String, safe_transmute_explanation: Option<String> }, } struct UnsatisfiedConst(pub bool); 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 af90372b97c..af8713ba3ff 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1592,8 +1592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .tcx .sess .source_map() - .span_extend_while(expr_span, char::is_whitespace) - .unwrap_or(expr_span) + .span_extend_while_whitespace(expr_span) .shrink_to_hi() .to(await_expr.span.shrink_to_hi()); err.span_suggestion( @@ -1880,19 +1879,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, span: Span, found_span: Option<Span>, - found: ty::PolyTraitRef<'tcx>, - expected: ty::PolyTraitRef<'tcx>, + found: ty::TraitRef<'tcx>, + expected: ty::TraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, found_node: Option<Node<'_>>, param_env: ty::ParamEnv<'tcx>, ) -> Diag<'tcx> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, ) -> Ty<'tcx> { - let inputs = trait_ref.skip_binder().args.type_at(1); + let inputs = trait_ref.args.type_at(1); let sig = match inputs.kind() { - ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id()) => { + ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id) => { infcx.tcx.mk_fn_sig( *inputs, infcx.next_ty_var(TypeVariableOrigin { @@ -1916,10 +1915,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ), }; - Ty::new_fn_ptr(infcx.tcx, trait_ref.rebind(sig)) + Ty::new_fn_ptr(infcx.tcx, ty::Binder::dummy(sig)) } - let argument_kind = match expected.skip_binder().self_ty().kind() { + let argument_kind = match expected.self_ty().kind() { ty::Closure(..) => "closure", ty::Coroutine(..) => "coroutine", _ => "function", @@ -4541,6 +4540,61 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Applicability::MachineApplicable, ); } + + fn ty_kind_suggestion(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<String> { + let tcx = self.infcx.tcx; + let implements_default = |ty| { + let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { + return false; + }; + self.type_implements_trait(default_trait, [ty], param_env).must_apply_modulo_regions() + }; + + Some(match ty.kind() { + ty::Never | ty::Error(_) => return None, + ty::Bool => "false".to_string(), + ty::Char => "\'x\'".to_string(), + ty::Int(_) | ty::Uint(_) => "42".into(), + ty::Float(_) => "3.14159".into(), + ty::Slice(_) => "[]".to_string(), + ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => { + "vec![]".to_string() + } + ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => { + "String::new()".to_string() + } + ty::Adt(def, args) if def.is_box() => { + format!("Box::new({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?) + } + ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => { + "None".to_string() + } + ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => { + format!("Ok({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?) + } + ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(), + ty::Ref(_, ty, mutability) => { + if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) { + "\"\"".to_string() + } else { + let ty = self.ty_kind_suggestion(param_env, *ty)?; + format!("&{}{ty}", mutability.prefix_str()) + } + } + ty::Array(ty, len) if let Some(len) = len.try_eval_target_usize(tcx, param_env) => { + format!("[{}; {}]", self.ty_kind_suggestion(param_env, *ty)?, len) + } + ty::Tuple(tys) => format!( + "({}{})", + tys.iter() + .map(|ty| self.ty_kind_suggestion(param_env, ty)) + .collect::<Option<Vec<String>>>()? + .join(", "), + if tys.len() == 1 { "," } else { "" } + ), + _ => "value".to_string(), + }) + } } /// Add a hint to add a missing borrow or remove an unnecessary one. @@ -4851,10 +4905,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( let hir::IsAsync::Async(async_span) = sig.header.asyncness else { return None; }; - let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) - else { - return None; - }; + let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span); let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { 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 144971b63c0..6be4589d380 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 @@ -558,7 +558,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation, - } => (err_msg, Some(safe_transmute_explanation)), + } => (err_msg, safe_transmute_explanation), } } else { (err_msg, None) @@ -1804,6 +1804,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Foreign(..) => Some(19), ty::CoroutineWitness(..) => Some(20), ty::CoroutineClosure(..) => Some(21), + ty::Pat(..) => Some(22), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } @@ -2398,12 +2399,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if ambiguities.len() > 5 { let infcx = self.infcx; if !ambiguities.iter().all(|option| match option { - DefId(did) => infcx.fresh_args_for_item(DUMMY_SP, *did).is_empty(), + DefId(did) => infcx.tcx.generics_of(*did).count() == 0, ParamEnv(_) => true, }) { // If not all are blanket impls, we filter blanked impls out. ambiguities.retain(|option| match option { - DefId(did) => infcx.fresh_args_for_item(DUMMY_SP, *did).is_empty(), + DefId(did) => infcx.tcx.generics_of(*did).count() == 0, ParamEnv(_) => true, }); } @@ -3067,28 +3068,33 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return GetSafeTransmuteErrorAndReason::Silent; }; + let dst = trait_ref.args.type_at(0); + let src = trait_ref.args.type_at(1); + let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); + match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( obligation.cause, src_and_dst, assume, ) { Answer::No(reason) => { - let dst = trait_ref.args.type_at(0); - let src = trait_ref.args.type_at(1); - let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); let safe_transmute_explanation = match reason { rustc_transmute::Reason::SrcIsNotYetSupported => { - format!("analyzing the transmutability of `{src}` is not yet supported.") + format!("analyzing the transmutability of `{src}` is not yet supported") } rustc_transmute::Reason::DstIsNotYetSupported => { - format!("analyzing the transmutability of `{dst}` is not yet supported.") + format!("analyzing the transmutability of `{dst}` is not yet supported") } rustc_transmute::Reason::DstIsBitIncompatible => { format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`") } + rustc_transmute::Reason::DstUninhabited => { + format!("`{dst}` is uninhabited") + } + rustc_transmute::Reason::DstMayHaveSafetyInvariants => { format!("`{dst}` may carry safety invariants") } @@ -3134,14 +3140,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("`{dst}` has an unknown layout") } }; - GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation } + GetSafeTransmuteErrorAndReason::Error { + err_msg, + safe_transmute_explanation: Some(safe_transmute_explanation), + } } // Should never get a Yes at this point! We already ran it before, and did not get a Yes. Answer::Yes => span_bug!( span, "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", ), - other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"), + // Reached when a different obligation (namely `Freeze`) causes the + // transmutability analysis to fail. In this case, silence the + // transmutability error message in favor of that more specific + // error. + Answer::If(_) => { + GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None } + } } } @@ -3365,11 +3380,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn report_cyclic_signature_error( &self, obligation: &PredicateObligation<'tcx>, - found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + found_trait_ref: ty::TraitRef<'tcx>, + expected_trait_ref: ty::TraitRef<'tcx>, terr: TypeError<'tcx>, ) -> Diag<'tcx> { - let self_ty = found_trait_ref.self_ty().skip_binder(); + let self_ty = found_trait_ref.self_ty(); let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() { ( ObligationCause::dummy_with_span(self.tcx.def_span(def_id)), @@ -3379,7 +3394,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (obligation.cause.clone(), terr) }; self.report_and_explain_type_error( - TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref), + TypeTrace::trait_refs(&cause, true, expected_trait_ref, found_trait_ref), terr, ) } @@ -3419,17 +3434,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, span: Span, - found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + found_trait_ref: ty::TraitRef<'tcx>, + expected_trait_ref: ty::TraitRef<'tcx>, ) -> Result<Diag<'tcx>, 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); expected_trait_ref.self_ty().error_reported()?; - - let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else { - self.dcx().bug("bound vars outside binder"); - }; + let found_trait_ty = found_trait_ref.self_ty(); let found_did = match *found_trait_ty.kind() { ty::Closure(did, _) | ty::FnDef(did, _) | ty::Coroutine(did, ..) => Some(did), @@ -3447,7 +3459,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut not_tupled = false; - let found = match found_trait_ref.skip_binder().args.type_at(1).kind() { + let found = match found_trait_ref.args.type_at(1).kind() { ty::Tuple(tys) => vec![ArgKind::empty(); tys.len()], _ => { not_tupled = true; @@ -3455,7 +3467,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - let expected_ty = expected_trait_ref.skip_binder().args.type_at(1); + let expected_ty = expected_trait_ref.args.type_at(1); let expected = match expected_ty.kind() { ty::Tuple(tys) => { tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() @@ -3472,11 +3484,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // traits manually, but don't make it more confusing when it does // happen. Ok( - if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().coroutine_trait() + if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled { self.report_and_explain_type_error( - TypeTrace::poly_trait_refs( + TypeTrace::trait_refs( &obligation.cause, true, expected_trait_ref, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2c8116b779b..98d5b466cd0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -119,7 +119,9 @@ pub fn predicates_for_generics<'tcx>( /// Determines whether the type `ty` is known to meet `bound` and /// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound. +/// `bound` or is not known to meet bound (note that this is +/// conservative towards *no impl*, which is the opposite of the +/// `evaluate` methods). pub fn type_known_to_meet_bound_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -127,8 +129,50 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( def_id: DefId, ) -> bool { let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); - let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref); - infcx.predicate_must_hold_modulo_regions(&obligation) + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref) +} + +/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? +/// +/// Ping me on zulip if you want to use this method and need help with finding +/// an appropriate replacement. +#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] +fn pred_known_to_hold_modulo_regions<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + pred: impl ToPredicate<'tcx>, +) -> bool { + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); + + let result = infcx.evaluate_obligation_no_overflow(&obligation); + debug!(?result); + + if result.must_apply_modulo_regions() { + true + } else if result.may_apply() { + // Sometimes obligations are ambiguous because the recursive evaluator + // is not smart enough, so we fall back to fulfillment when we're not certain + // that an obligation holds or not. Even still, we must make sure that + // the we do no inference in the process of checking this obligation. + let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + infcx.probe(|_| { + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligation(obligation); + + let errors = ocx.select_all_or_error(); + match errors.as_slice() { + // Only known to hold if we did no inference. + [] => infcx.shallow_resolve(goal) == goal, + + errors => { + debug!(?errors); + false + } + } + }) + } else { + false + } } #[instrument(level = "debug", skip(tcx, elaborated_env))] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9246a41a2bc..a5483c5bbc0 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -793,6 +793,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let Some(clause) = clause.as_projection_clause() else { return ControlFlow::Continue(()); }; + if clause.projection_def_id() != obligation.predicate.def_id { + return ControlFlow::Continue(()); + } let is_match = selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true)); @@ -1045,6 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Foreign(_) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(..) | ty::Ref(..) @@ -1096,6 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Float(_) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(..) | ty::Ref(..) @@ -1596,7 +1601,10 @@ fn confirm_closure_candidate<'cx, 'tcx>( // If we know the kind and upvars, use that directly. // Otherwise, defer to `AsyncFnKindHelper::Upvars` to delay // the projection, like the `AsyncFn*` traits do. - let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind() { + let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind() + // Fall back to projection if upvars aren't constrained + && !args.tupled_upvars_ty().is_ty_var() + { sig.to_coroutine_given_kind_and_upvars( tcx, args.parent_args(), @@ -1726,7 +1734,10 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => { - if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if let Some(closure_kind) = kind_ty.to_opt_closure_kind() + // Fall back to projection if upvars aren't constrained + && !args.tupled_upvars_ty().is_ty_var() + { if !closure_kind.extends(goal_kind) { bug!("we should not be confirming if the closure kind is not met"); } 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 aaa38d14d6e..326c68e01db 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -42,8 +42,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Foreign(..) | ty::Error(_) => true, - // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty), + // `T is PAT`, `[T; N]`, and `[T]` have same properties as T. + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty), // (T1..Tn) and closures have same properties as T1..Tn -- // check if *all* of them are trivial. @@ -222,7 +222,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // these types never have a destructor } - ty::Array(ety, _) | ty::Slice(ety) => { + ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints) 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 faf218131b8..ae4cdb9258e 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 @@ -159,53 +159,70 @@ where .0); } + let mut error_info = None; let mut region_constraints = QueryRegionConstraints::default(); - let (output, error_info, mut obligations, _) = - Q::fully_perform_into(self, infcx, &mut region_constraints, span).map_err(|_| { - infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}")) - })?; - - // Typically, instantiating NLL query results does not - // create obligations. However, in some cases there - // are unresolved type variables, and unify them *can* - // create obligations. In that case, we have to go - // fulfill them. We do this via a (recursive) query. - while !obligations.is_empty() { - trace!("{:#?}", obligations); - let mut progress = false; - for obligation in std::mem::take(&mut obligations) { - let obligation = infcx.resolve_vars_if_possible(obligation); - match ProvePredicate::fully_perform_into( - obligation.param_env.and(ProvePredicate::new(obligation.predicate)), - infcx, - &mut region_constraints, - span, - ) { - Ok(((), _, new, certainty)) => { - obligations.extend(new); - progress = true; - if let Certainty::Ambiguous = certainty { - obligations.push(obligation); + + // HACK(type_alias_impl_trait): When moving an opaque type to hidden type mapping from the query to the current inferctxt, + // we sometimes end up with `Opaque<'a> = Opaque<'b>` instead of an actual hidden type. In that case we don't register a + // hidden type but just equate the lifetimes. Thus we need to scrape the region constraints even though we're also manually + // collecting region constraints via `region_constraints`. + let (mut output, _) = scrape_region_constraints( + infcx, + |_ocx| { + let (output, ei, mut obligations, _) = + Q::fully_perform_into(self, infcx, &mut region_constraints, span)?; + error_info = ei; + + // Typically, instantiating NLL query results does not + // create obligations. However, in some cases there + // are unresolved type variables, and unify them *can* + // create obligations. In that case, we have to go + // fulfill them. We do this via a (recursive) query. + while !obligations.is_empty() { + trace!("{:#?}", obligations); + let mut progress = false; + for obligation in std::mem::take(&mut obligations) { + let obligation = infcx.resolve_vars_if_possible(obligation); + match ProvePredicate::fully_perform_into( + obligation.param_env.and(ProvePredicate::new(obligation.predicate)), + infcx, + &mut region_constraints, + span, + ) { + Ok(((), _, new, certainty)) => { + obligations.extend(new); + progress = true; + if let Certainty::Ambiguous = certainty { + obligations.push(obligation); + } + } + Err(_) => obligations.push(obligation), } } - Err(_) => obligations.push(obligation), + if !progress { + infcx.dcx().span_bug( + span, + format!("ambiguity processing {obligations:?} from {self:?}"), + ); + } } - } - if !progress { - infcx - .dcx() - .span_bug(span, format!("ambiguity processing {obligations:?} from {self:?}")); - } - } - - Ok(TypeOpOutput { - output, - constraints: if region_constraints.is_empty() { - None - } else { - Some(infcx.tcx.arena.alloc(region_constraints)) + Ok(output) }, - error_info, - }) + "fully_perform", + span, + )?; + output.error_info = error_info; + if let Some(constraints) = output.constraints { + region_constraints + .member_constraints + .extend(constraints.member_constraints.iter().cloned()); + region_constraints.outlives.extend(constraints.outlives.iter().cloned()); + } + output.constraints = if region_constraints.is_empty() { + None + } else { + Some(infcx.tcx.arena.alloc(region_constraints)) + }; + Ok(output) } } 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 c6ea596b819..974e5ef0e16 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -400,39 +400,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); let is_const = self.tcx().is_const_fn_raw(def_id); - match self.infcx.closure_kind(self_ty) { - Some(closure_kind) => { - let no_borrows = match self - .infcx - .shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()) - .kind() - { - ty::Tuple(tys) => tys.is_empty(), - ty::Error(_) => false, - _ => bug!("tuple_fields called on non-tuple"), - }; - // A coroutine-closure implements `FnOnce` *always*, since it may - // always be called once. It additionally implements `Fn`/`FnMut` - // only if it has no upvars (therefore no borrows from the closure - // that would need to be represented with a lifetime) and if the - // closure kind permits it. - // FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut` - // if it takes all of its upvars by copy, and none by ref. This would - // require us to record a bit more information during upvar analysis. - if no_borrows && closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate { is_const }); - } else if kind == ty::ClosureKind::FnOnce { - candidates.vec.push(ClosureCandidate { is_const }); - } + if let Some(closure_kind) = self.infcx.closure_kind(self_ty) + // Ambiguity if upvars haven't been constrained yet + && !args.tupled_upvars_ty().is_ty_var() + { + let no_borrows = match args.tupled_upvars_ty().kind() { + ty::Tuple(tys) => tys.is_empty(), + ty::Error(_) => false, + _ => bug!("tuple_fields called on non-tuple"), + }; + // A coroutine-closure implements `FnOnce` *always*, since it may + // always be called once. It additionally implements `Fn`/`FnMut` + // only if it has no upvars (therefore no borrows from the closure + // that would need to be represented with a lifetime) and if the + // closure kind permits it. + // FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut` + // if it takes all of its upvars by copy, and none by ref. This would + // require us to record a bit more information during upvar analysis. + if no_borrows && closure_kind.extends(kind) { + candidates.vec.push(ClosureCandidate { is_const }); + } else if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); } - None => { - if kind == ty::ClosureKind::FnOnce { - candidates.vec.push(ClosureCandidate { is_const }); - } else { - // This stays ambiguous until kind+upvars are determined. - candidates.ambiguous = true; - } + } else { + if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); + } else { + // This stays ambiguous until kind+upvars are determined. + candidates.ambiguous = true; } } } @@ -670,6 +667,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -803,6 +801,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Float(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::Adt(..) | ty::RawPtr(_, _) @@ -1193,6 +1192,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Never | ty::Foreign(_) | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1270,6 +1270,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(_, _) | ty::Ref(_, _, _) | ty::FnDef(_, _) + | ty::Pat(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(..) @@ -1329,6 +1330,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(..) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0459246553b..716b9a49ab5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -314,12 +314,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(|cond| flatten_answer_tree(tcx, obligation, predicate, cond)) .collect(), Condition::IfTransmutable { src, dst } => { - let trait_def_id = obligation.predicate.def_id(); + let transmute_trait = obligation.predicate.def_id(); let assume_const = predicate.trait_ref.args.const_at(2); - let make_obl = |from_ty, to_ty| { - let trait_ref1 = ty::TraitRef::new( + let make_transmute_obl = |from_ty, to_ty| { + let trait_ref = ty::TraitRef::new( tcx, - trait_def_id, + transmute_trait, [ ty::GenericArg::from(to_ty), ty::GenericArg::from(from_ty), @@ -331,17 +331,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, - trait_ref1, + trait_ref, ) }; + let make_freeze_obl = |ty| { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.lang_items().freeze_trait().unwrap(), + [ty::GenericArg::from(ty)], + ); + Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref, + ) + }; + + let mut obls = vec![]; + + // If the source is a shared reference, it must be `Freeze`; + // otherwise, transmuting could lead to data races. + if src.mutability == Mutability::Not { + obls.extend([make_freeze_obl(src.ty), make_freeze_obl(dst.ty)]) + } + // If Dst is mutable, check bidirectionally. // For example, transmuting bool -> u8 is OK as long as you can't update that u8 // to be > 1, because you could later transmute the u8 back to a bool and get UB. match dst.mutability { - Mutability::Not => vec![make_obl(src.ty, dst.ty)], - Mutability::Mut => vec![make_obl(src.ty, dst.ty), make_obl(dst.ty, src.ty)], + Mutability::Not => obls.push(make_transmute_obl(src.ty, dst.ty)), + Mutability::Mut => obls.extend([ + make_transmute_obl(src.ty, dst.ty), + make_transmute_obl(dst.ty, src.ty), + ]), } + + obls } } } @@ -1051,8 +1079,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .map_err(|terr| { SignatureMismatch(Box::new(SignatureMismatchData { - expected_trait_ref: ty::Binder::dummy(obligation_trait_ref), - found_trait_ref: ty::Binder::dummy(found_trait_ref), + expected_trait_ref: obligation_trait_ref, + found_trait_ref, terr, })) }) @@ -1417,7 +1445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // These types are built-in, so we can fast-track by registering // nested predicates for their constituent type(s) - ty::Array(ty, _) | ty::Slice(ty) => { + ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => { stack.push(ty); } ty::Tuple(tys) => { @@ -1469,7 +1497,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If we have any other type (e.g. an ADT), just register a nested obligation // since it's either not `const Drop` (and we raise an error during selection), // or it's an ADT (and we need to check for a custom impl during selection) - _ => { + ty::Error(_) + | ty::Dynamic(..) + | ty::CoroutineClosure(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Adt(..) + | ty::Alias(ty::Opaque | ty::Weak, _) + | ty::Infer(_) + | ty::Placeholder(_) => { let predicate = self_ty.rebind(ty::TraitPredicate { trait_ref: ty::TraitRef::from_lang_item( self.tcx(), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index aa4ab9c7ee9..e363119393a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1732,6 +1732,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, ) -> ProjectionMatchesProjection { + debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id()); + let mut nested_obligations = Vec::new(); let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, @@ -2140,6 +2142,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])), ), + ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])), + ty::Adt(def, args) => { if let Some(sized_crit) = def.sized_constraint(self.tcx()) { // (*) binder moved here @@ -2200,6 +2204,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { Where(obligation.predicate.rebind(tys.iter().collect())) } + ty::Pat(ty, _) => { + // (*) binder moved here + Where(obligation.predicate.rebind(vec![ty])) + } + ty::Coroutine(coroutine_def_id, args) => { match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => None, @@ -2338,7 +2347,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]), - ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]), ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index b89406ca023..6778ac81aea 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -126,7 +126,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { return ControlFlow::Continue(()); } - ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { + ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. return ty.super_visit_with(self); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index a44a5ae0e6b..5553490542b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -681,6 +681,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // Note that we handle the len is implicitly checked while walking `arg`. } + ty::Pat(subty, _) => { + self.require_sized(subty, traits::MiscObligation); + } + ty::Tuple(tys) => { if let Some((_last, rest)) = tys.split_last() { for &elem in rest { diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index b8922696e30..77d5a48f158 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -35,6 +35,7 @@ impl<R> Transitions<R> where R: Ref, { + #[allow(dead_code)] fn insert(&mut self, transition: Transition<R>, state: State) { match transition { Transition::Byte(b) => { @@ -82,6 +83,7 @@ impl<R> Dfa<R> where R: Ref, { + #[allow(dead_code)] pub(crate) fn unit() -> Self { let transitions: Map<State, Transitions<R>> = Map::default(); let start = State::new(); diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index 78fcceb5f2c..3c5963202c6 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -160,6 +160,7 @@ where Self { transitions, start, accepting } } + #[allow(dead_code)] pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> { self.transitions.get(&start) } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index f6bc224c7e7..12c984f1603 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -173,16 +173,20 @@ pub(crate) mod rustc { use super::Tree; use crate::layout::rustc::{Def, Ref}; + use rustc_middle::ty::layout::HasTyCtxt; + use rustc_middle::ty::layout::LayoutCx; use rustc_middle::ty::layout::LayoutError; + use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::AdtDef; - use rustc_middle::ty::GenericArgsRef; - use rustc_middle::ty::ParamEnv; + use rustc_middle::ty::AdtKind; + use rustc_middle::ty::List; use rustc_middle::ty::ScalarInt; - use rustc_middle::ty::VariantDef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::ErrorGuaranteed; - use rustc_target::abi::Align; - use std::alloc; + use rustc_target::abi::FieldsShape; + use rustc_target::abi::Size; + use rustc_target::abi::TyAndLayout; + use rustc_target::abi::Variants; #[derive(Debug, Copy, Clone)] pub(crate) enum Err { @@ -206,176 +210,64 @@ pub(crate) mod rustc { } } - trait LayoutExt { - fn clamp_align(&self, min_align: Align, max_align: Align) -> Self; - } - - impl LayoutExt for alloc::Layout { - fn clamp_align(&self, min_align: Align, max_align: Align) -> Self { - let min_align = min_align.bytes().try_into().unwrap(); - let max_align = max_align.bytes().try_into().unwrap(); - Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap() - } - } - - struct LayoutSummary { - total_align: Align, - total_size: usize, - discriminant_size: usize, - discriminant_align: Align, - } - - impl LayoutSummary { - fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> { - use rustc_middle::ty::ParamEnvAnd; - use rustc_target::abi::{TyAndLayout, Variants}; - - let param_env = ParamEnv::reveal_all(); - let param_env_and_type = ParamEnvAnd { param_env, value: ty }; - let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; - - let total_size: usize = layout.size().bytes_usize(); - let total_align: Align = layout.align().abi; - let discriminant_align: Align; - let discriminant_size: usize; - - if let Variants::Multiple { tag, .. } = layout.variants() { - discriminant_align = tag.align(&ctx).abi; - discriminant_size = tag.size(&ctx).bytes_usize(); - } else { - discriminant_align = Align::ONE; - discriminant_size = 0; - }; - - Ok(Self { total_align, total_size, discriminant_align, discriminant_size }) - } - - fn into(&self) -> alloc::Layout { - alloc::Layout::from_size_align( - self.total_size, - self.total_align.bytes().try_into().unwrap(), - ) - .unwrap() - } - } - impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> { - pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> { - use rustc_middle::ty::FloatTy::*; - use rustc_middle::ty::IntTy::*; - use rustc_middle::ty::UintTy::*; + pub fn from_ty( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { use rustc_target::abi::HasDataLayout; - if let Err(e) = ty.error_reported() { + if let Err(e) = ty_and_layout.ty.error_reported() { return Err(Err::TypeError(e)); } - let target = tcx.data_layout(); + let target = cx.tcx.data_layout(); + let pointer_size = target.pointer_size; - match ty.kind() { + match ty_and_layout.ty.kind() { ty::Bool => Ok(Self::bool()), - ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()), - ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)), - ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)), - ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)), - ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)), - ty::Int(Isize) | ty::Uint(Usize) => { - Ok(Self::number(target.pointer_size.bytes_usize())) + ty::Float(nty) => { + let width = nty.bit_width() / 8; + Ok(Self::number(width as _)) } - ty::Tuple(members) => { - if members.len() == 0 { - Ok(Tree::unit()) - } else { - Err(Err::NotYetSupported) - } + ty::Int(nty) => { + let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8; + Ok(Self::number(width as _)) } - ty::Array(ty, len) => { - let len = len - .try_eval_target_usize(tcx, ParamEnv::reveal_all()) - .ok_or(Err::NotYetSupported)?; - let elt = Tree::from_ty(*ty, tcx)?; - Ok(std::iter::repeat(elt) - .take(len as usize) - .fold(Tree::unit(), |tree, elt| tree.then(elt))) + ty::Uint(nty) => { + let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8; + Ok(Self::number(width as _)) } - ty::Adt(adt_def, args_ref) => { - use rustc_middle::ty::AdtKind; + ty::Tuple(members) => Self::from_tuple(ty_and_layout, members, cx), - // If the layout is ill-specified, halt. - if !(adt_def.repr().c() || adt_def.repr().int.is_some()) { + ty::Array(inner_ty, len) => { + let FieldsShape::Array { stride, count } = &ty_and_layout.fields else { return Err(Err::NotYetSupported); - } + }; + let inner_ty_and_layout = cx.layout_of(*inner_ty)?; + assert_eq!(*stride, inner_ty_and_layout.size); + let elt = Tree::from_ty(inner_ty_and_layout, cx)?; + Ok(std::iter::repeat(elt) + .take(*count as usize) + .fold(Tree::unit(), |tree, elt| tree.then(elt))) + } - // Compute a summary of the type's layout. - let layout_summary = LayoutSummary::from_ty(ty, tcx)?; - - // The layout begins with this adt's visibility. - let vis = Self::def(Def::Adt(*adt_def)); - - // And is followed the layout(s) of its variants - Ok(vis.then(match adt_def.adt_kind() { - AdtKind::Struct => Self::from_repr_c_variant( - ty, - *adt_def, - args_ref, - &layout_summary, - None, - adt_def.non_enum_variant(), - tcx, - )?, - AdtKind::Enum => { - trace!(?adt_def, "treeifying enum"); - let mut tree = Tree::uninhabited(); - - for (idx, variant) in adt_def.variants().iter_enumerated() { - let tag = tcx.tag_for_variant((ty, idx)); - tree = tree.or(Self::from_repr_c_variant( - ty, - *adt_def, - args_ref, - &layout_summary, - tag, - variant, - tcx, - )?); - } - - tree - } - AdtKind::Union => { - // is the layout well-defined? - if !adt_def.repr().c() { - return Err(Err::NotYetSupported); - } - - let ty_layout = layout_of(tcx, ty)?; - - let mut tree = Tree::uninhabited(); - - for field in adt_def.all_fields() { - let variant_ty = field.ty(tcx, args_ref); - let variant_layout = layout_of(tcx, variant_ty)?; - let padding_needed = ty_layout.size() - variant_layout.size(); - let variant = Self::def(Def::Field(field)) - .then(Self::from_ty(variant_ty, tcx)?) - .then(Self::padding(padding_needed)); - - tree = tree.or(variant); - } - - tree - } - })) + ty::Adt(adt_def, _args_ref) if !ty_and_layout.ty.is_box() => { + match adt_def.adt_kind() { + AdtKind::Struct => Self::from_struct(ty_and_layout, *adt_def, cx), + AdtKind::Enum => Self::from_enum(ty_and_layout, *adt_def, cx), + AdtKind::Union => Self::from_union(ty_and_layout, *adt_def, cx), + } } ty::Ref(lifetime, ty, mutability) => { - let layout = layout_of(tcx, *ty)?; - let align = layout.align(); - let size = layout.size(); + let ty_and_layout = cx.layout_of(*ty)?; + let align = ty_and_layout.align.abi.bytes() as usize; + let size = ty_and_layout.size.bytes_usize(); Ok(Tree::Ref(Ref { lifetime: *lifetime, ty: *ty, @@ -389,80 +281,143 @@ pub(crate) mod rustc { } } - fn from_repr_c_variant( - ty: Ty<'tcx>, - adt_def: AdtDef<'tcx>, - args_ref: GenericArgsRef<'tcx>, - layout_summary: &LayoutSummary, - tag: Option<ScalarInt>, - variant_def: &'tcx VariantDef, - tcx: TyCtxt<'tcx>, + /// Constructs a `Tree` from a tuple. + fn from_tuple( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + members: &'tcx List<Ty<'tcx>>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ) -> Result<Self, Err> { - let mut tree = Tree::unit(); - - let repr = adt_def.repr(); - let min_align = repr.align.unwrap_or(Align::ONE); - let max_align = repr.pack.unwrap_or(Align::MAX); - - let variant_span = trace_span!( - "treeifying variant", - min_align = ?min_align, - max_align = ?max_align, - ) - .entered(); - - let mut variant_layout = alloc::Layout::from_size_align( - 0, - layout_summary.total_align.bytes().try_into().unwrap(), - ) - .unwrap(); - - // The layout of the variant is prefixed by the tag, if any. - if let Some(tag) = tag { - let tag_layout = - alloc::Layout::from_size_align(tag.size().bytes_usize(), 1).unwrap(); - tree = tree.then(Self::from_tag(tag, tcx)); - variant_layout = variant_layout.extend(tag_layout).unwrap().0; + match &ty_and_layout.fields { + FieldsShape::Primitive => { + assert_eq!(members.len(), 1); + let inner_ty = members[0]; + let inner_ty_and_layout = cx.layout_of(inner_ty)?; + assert_eq!(ty_and_layout.layout, inner_ty_and_layout.layout); + Self::from_ty(inner_ty_and_layout, cx) + } + FieldsShape::Arbitrary { offsets, .. } => { + assert_eq!(offsets.len(), members.len()); + Self::from_variant(Def::Primitive, None, ty_and_layout, ty_and_layout.size, cx) + } + FieldsShape::Array { .. } | FieldsShape::Union(_) => Err(Err::NotYetSupported), + } + } + + /// Constructs a `Tree` from a struct. + /// + /// # Panics + /// + /// Panics if `def` is not a struct definition. + fn from_struct( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + def: AdtDef<'tcx>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + assert!(def.is_struct()); + let def = Def::Adt(def); + Self::from_variant(def, None, ty_and_layout, ty_and_layout.size, cx) + } + + /// Constructs a `Tree` from an enum. + /// + /// # Panics + /// + /// Panics if `def` is not an enum definition. + fn from_enum( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + def: AdtDef<'tcx>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + assert!(def.is_enum()); + let layout = ty_and_layout.layout; + + if let Variants::Multiple { tag_field, .. } = layout.variants() { + // For enums (but not coroutines), the tag field is + // currently always the first field of the layout. + assert_eq!(*tag_field, 0); } - // Next come fields. - let fields_span = trace_span!("treeifying fields").entered(); - for field_def in variant_def.fields.iter() { - let field_ty = field_def.ty(tcx, args_ref); - let _span = trace_span!("treeifying field", field = ?field_ty).entered(); + let variants = def.discriminants(cx.tcx()).try_fold( + Self::uninhabited(), + |variants, (idx, ref discriminant)| { + let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, idx)); + let variant_def = Def::Variant(def.variant(idx)); + let variant_ty_and_layout = ty_and_layout.for_variant(&cx, idx); + let variant = Self::from_variant( + variant_def, + tag, + variant_ty_and_layout, + layout.size, + cx, + )?; + Result::<Self, Err>::Ok(variants.or(variant)) + }, + )?; - // begin with the field's visibility - tree = tree.then(Self::def(Def::Field(field_def))); + return Ok(Self::def(Def::Adt(def)).then(variants)); + } - // compute the field's layout characteristics - let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align); + /// Constructs a `Tree` from a 'variant-like' layout. + /// + /// A 'variant-like' layout includes those of structs and, of course, + /// enum variants. Pragmatically speaking, this method supports anything + /// with `FieldsShape::Arbitrary`. + /// + /// Note: This routine assumes that the optional `tag` is the first + /// field, and enum callers should check that `tag_field` is, in fact, + /// `0`. + fn from_variant( + def: Def<'tcx>, + tag: Option<ScalarInt>, + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + total_size: Size, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + // This constructor does not support non-`FieldsShape::Arbitrary` + // layouts. + let FieldsShape::Arbitrary { offsets, memory_index } = ty_and_layout.layout.fields() + else { + return Err(Err::NotYetSupported); + }; - // next comes the field's padding - let padding_needed = variant_layout.padding_needed_for(field_layout.align()); - if padding_needed > 0 { - tree = tree.then(Self::padding(padding_needed)); - } + // When this function is invoked with enum variants, + // `ty_and_layout.size` does not encompass the entire size of the + // enum. We rely on `total_size` for this. + assert!(ty_and_layout.size <= total_size); - // finally, the field's layout - tree = tree.then(Self::from_ty(field_ty, tcx)?); + let mut size = Size::ZERO; + let mut struct_tree = Self::def(def); - // extend the variant layout with the field layout - variant_layout = variant_layout.extend(field_layout).unwrap().0; + // If a `tag` is provided, place it at the start of the layout. + if let Some(tag) = tag { + size += tag.size(); + struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx)); } - drop(fields_span); - // finally: padding - let padding_span = trace_span!("adding trailing padding").entered(); - if layout_summary.total_size > variant_layout.size() { - let padding_needed = layout_summary.total_size - variant_layout.size(); - tree = tree.then(Self::padding(padding_needed)); - }; - drop(padding_span); - drop(variant_span); - Ok(tree) + // Append the fields, in memory order, to the layout. + let inverse_memory_index = memory_index.invert_bijective_mapping(); + for (memory_idx, field_idx) in inverse_memory_index.iter_enumerated() { + // Add interfield padding. + let padding_needed = offsets[*field_idx] - size; + let padding = Self::padding(padding_needed.bytes_usize()); + + let field_ty_and_layout = ty_and_layout.field(&cx, field_idx.as_usize()); + let field_tree = Self::from_ty(field_ty_and_layout, cx)?; + + struct_tree = struct_tree.then(padding).then(field_tree); + + size += padding_needed + field_ty_and_layout.size; + } + + // Add trailing padding. + let padding_needed = total_size - size; + let trailing_padding = Self::padding(padding_needed.bytes_usize()); + + Ok(struct_tree.then(trailing_padding)) } - pub fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { + /// Constructs a `Tree` representing the value of a enum tag. + fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { use rustc_target::abi::Endian; let size = tag.size(); let bits = tag.to_bits(size).unwrap(); @@ -479,24 +434,42 @@ pub(crate) mod rustc { }; Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect()) } - } - fn layout_of<'tcx>( - ctx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - ) -> Result<alloc::Layout, &'tcx LayoutError<'tcx>> { - use rustc_middle::ty::ParamEnvAnd; - use rustc_target::abi::TyAndLayout; - - let param_env = ParamEnv::reveal_all(); - let param_env_and_type = ParamEnvAnd { param_env, value: ty }; - let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; - let layout = alloc::Layout::from_size_align( - layout.size().bytes_usize(), - layout.align().abi.bytes().try_into().unwrap(), - ) - .unwrap(); - trace!(?ty, ?layout, "computed layout for type"); - Ok(layout) + /// Constructs a `Tree` from a union. + /// + /// # Panics + /// + /// Panics if `def` is not a union definition. + fn from_union( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + def: AdtDef<'tcx>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + assert!(def.is_union()); + + let union_layout = ty_and_layout.layout; + + // This constructor does not support non-`FieldsShape::Union` + // layouts. Fields of this shape are all placed at offset 0. + let FieldsShape::Union(fields) = union_layout.fields() else { + return Err(Err::NotYetSupported); + }; + + let fields = &def.non_enum_variant().fields; + let fields = fields.iter_enumerated().try_fold( + Self::uninhabited(), + |fields, (idx, ref field_def)| { + let field_def = Def::Field(field_def); + let field_ty_and_layout = ty_and_layout.field(&cx, idx.as_usize()); + let field = Self::from_ty(field_ty_and_layout, cx)?; + let trailing_padding_needed = union_layout.size - field_ty_and_layout.size; + let trailing_padding = Self::padding(trailing_padding_needed.bytes_usize()); + let field_and_padding = field.then(trailing_padding); + Result::<Self, Err>::Ok(fields.or(field_and_padding)) + }, + )?; + + Ok(Self::def(Def::Adt(def)).then(fields)) + } } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index b6f937ebe47..12312271646 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,6 +1,6 @@ #![feature(alloc_layout_extra)] #![feature(never_type)] -#![allow(dead_code, unused_variables)] +#![allow(unused_variables)] #[macro_use] extern crate tracing; @@ -49,6 +49,8 @@ pub enum Reason<T> { DstIsNotYetSupported, /// The layout of the destination type is bit-incompatible with the source type. DstIsBitIncompatible, + /// The destination type is uninhabited. + DstUninhabited, /// The destination type may carry safety invariants. DstMayHaveSafetyInvariants, /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 16d15580a05..2789fe8f6b1 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -33,6 +33,9 @@ mod rustc { use super::*; use crate::layout::tree::rustc::Err; + use rustc_middle::ty::layout::LayoutCx; + use rustc_middle::ty::layout::LayoutOf; + use rustc_middle::ty::ParamEnv; use rustc_middle::ty::Ty; use rustc_middle::ty::TyCtxt; @@ -43,12 +46,20 @@ mod rustc { pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> { let Self { src, dst, assume, context } = self; + let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() }; + let layout_of = |ty| { + layout_cx + .layout_of(ty) + .map_err(|_| Err::NotYetSupported) + .and_then(|tl| Tree::from_ty(tl, layout_cx)) + }; + // Convert `src` and `dst` from their rustc representations, to `Tree`-based // representations. If these conversions fail, conclude that the transmutation is // unacceptable; the layouts of both the source and destination types must be // well-defined. - let src = Tree::from_ty(src, context); - let dst = Tree::from_ty(dst, context); + let src = layout_of(src); + let dst = layout_of(dst); match (src, dst) { (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => { @@ -86,6 +97,10 @@ where // references. let src = src.prune(&|def| false); + if src.is_inhabited() && !dst.is_inhabited() { + return Answer::No(Reason::DstUninhabited); + } + trace!(?src, "pruned src"); // Remove all `Def` nodes from `dst`, additionally... diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 54ed03d44e6..1ccb6f36c8e 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -5,8 +5,6 @@ pub(crate) trait QueryContext { type Def: layout::Def; type Ref: layout::Ref; type Scope: Copy; - - fn min_align(&self, reference: Self::Ref) -> usize; } #[cfg(test)] @@ -31,10 +29,6 @@ pub(crate) mod test { type Def = Def; type Ref = !; type Scope = (); - - fn min_align(&self, reference: !) -> usize { - unimplemented!() - } } } @@ -48,9 +42,5 @@ mod rustc { type Ref = layout::rustc::Ref<'tcx>; type Scope = Ty<'tcx>; - - fn min_align(&self, reference: Self::Ref) -> usize { - unimplemented!() - } } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 509727cdeab..902b76e8c1e 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -126,6 +126,43 @@ fn layout_of_uncached<'tcx>( debug_assert!(!ty.has_non_region_infer()); Ok(match *ty.kind() { + ty::Pat(ty, pat) => { + let layout = cx.layout_of(ty)?.layout; + let mut layout = LayoutS::clone(&layout.0); + match *pat { + ty::PatternKind::Range { start, end, include_end } => { + if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { + if let Some(start) = start { + scalar.valid_range_mut().start = start + .try_eval_bits(tcx, param_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + } + if let Some(end) = end { + let mut end = end + .try_eval_bits(tcx, param_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + if !include_end { + end = end.wrapping_sub(1); + } + scalar.valid_range_mut().end = end; + } + + let niche = Niche { + offset: Size::ZERO, + value: scalar.primitive(), + valid_range: scalar.valid_range(cx), + }; + + layout.largest_niche = Some(niche); + + tcx.mk_layout(layout) + } else { + bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}") + } + } + } + } + // Basic scalars. ty::Bool => tcx.mk_layout(LayoutS::scalar( cx, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 48339e6120a..ee930a78e77 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -221,6 +221,7 @@ where | ty::Ref(..) | ty::RawPtr(..) | ty::FnDef(..) + | ty::Pat(..) | ty::FnPtr(..) | ty::Tuple(_) | ty::Bound(..) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 547a3cb5a8c..f33234122c9 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -36,6 +36,8 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<' // these are never sized Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty), + Pat(ty, _) => sized_constraint_for_ty(tcx, *ty), + Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), // recursive case diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index ad18ef24984..06a5051956a 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -16,6 +16,8 @@ use crate::{Interner, PlaceholderLike, UniverseIndex}; pub struct Canonical<I: Interner, V> { pub value: V, pub max_universe: UniverseIndex, + // FIXME(lcnr, oli-obk): try moving this into the query inputs instead + pub defining_opaque_types: I::DefiningOpaqueTypes, pub variables: I::CanonicalVars, } @@ -44,8 +46,8 @@ impl<I: Interner, V> Canonical<I, V> { /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty)); /// ``` pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } + let Canonical { defining_opaque_types, max_universe, variables, value } = self; + Canonical { defining_opaque_types, max_universe, variables, value: map_op(value) } } /// Allows you to map the `value` of a canonical while keeping the same set of @@ -54,8 +56,8 @@ impl<I: Interner, V> Canonical<I, V> { /// **WARNING:** This function is very easy to mis-use, hence the name! See /// the comment of [Canonical::unchecked_map] for more details. pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> { - let Canonical { max_universe, variables, value: _ } = self; - Canonical { max_universe, variables, value } + let Canonical { defining_opaque_types, max_universe, variables, value: _ } = self; + Canonical { defining_opaque_types, max_universe, variables, value } } } @@ -63,28 +65,32 @@ impl<I: Interner, V: Eq> Eq for Canonical<I, V> {} impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> { fn eq(&self, other: &Self) -> bool { - self.value == other.value - && self.max_universe == other.max_universe - && self.variables == other.variables + let Self { value, max_universe, variables, defining_opaque_types } = self; + *value == other.value + && *max_universe == other.max_universe + && *variables == other.variables + && *defining_opaque_types == other.defining_opaque_types } } impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { value, max_universe, variables, defining_opaque_types } = self; write!( f, - "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", - self.value, self.max_universe, self.variables + "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?}, defining_opaque_types: {defining_opaque_types:?} }}", ) } } impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { value, max_universe, variables, defining_opaque_types } = self; f.debug_struct("Canonical") - .field("value", &self.value) - .field("max_universe", &self.max_universe) - .field("variables", &self.variables) + .field("value", &value) + .field("max_universe", &max_universe) + .field("variables", &variables) + .field("defining_opaque_types", &defining_opaque_types) .finish() } } @@ -100,6 +106,7 @@ where value: self.value.try_fold_with(folder)?, max_universe: self.max_universe.try_fold_with(folder)?, variables: self.variables.try_fold_with(folder)?, + defining_opaque_types: self.defining_opaque_types, }) } } @@ -109,9 +116,11 @@ where I::CanonicalVars: TypeVisitable<I>, { fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> F::Result { - try_visit!(self.value.visit_with(folder)); - try_visit!(self.max_universe.visit_with(folder)); - self.variables.visit_with(folder) + let Self { value, max_universe, variables, defining_opaque_types } = self; + try_visit!(value.visit_with(folder)); + try_visit!(max_universe.visit_with(folder)); + try_visit!(defining_opaque_types.visit_with(folder)); + variables.visit_with(folder) } } diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 9c8e45b4338..9298360f749 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -43,6 +43,10 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> { fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> { None } + + fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes { + Default::default() + } } pub trait DebugWithInfcx<I: Interner>: fmt::Debug { diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 28b71f0ea13..a53287c1987 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -37,4 +37,6 @@ pub trait InferCtxtLike { /// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type. fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>; + + fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7a2885dd3bb..70f7e58be19 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,6 +11,7 @@ use crate::{ pub trait Interner: Sized + Copy { type DefId: Copy + Debug + Hash + Eq; + type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: Copy @@ -49,6 +50,7 @@ pub trait Interner: Sized + Copy { type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq; type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq; type AllocId: Copy + Debug + Hash + Eq; + type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>; // Kinds of consts type Const: Copy @@ -100,6 +102,7 @@ pub trait Interner: Sized + Copy { type SubtypePredicate: Copy + Debug + Hash + Eq; type CoercePredicate: Copy + Debug + Hash + Eq; type ClosureKind: Copy + Debug + Hash + Eq; + type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars; } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index fad67fe3cbb..397e104512f 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -100,6 +100,13 @@ pub enum TyKind<I: Interner> { /// An array with the given length. Written as `[T; N]`. Array(I::Ty, I::Const), + /// A pattern newtype. Takes any type and restricts its valid values to its pattern. + /// This will also change the layout to take advantage of this restriction. + /// Only `Copy` and `Clone` will automatically get implemented for pattern types. + /// Auto-traits treat this as if it were an aggregate with a single nested type. + /// Only supports integer range patterns for now. + Pat(I::Ty, I::Pat), + /// The pointee of an array slice. Written as `[T]`. Slice(I::Ty), @@ -174,9 +181,9 @@ pub enum TyKind<I: Interner> { /// Looking at the following example, the witness for this coroutine /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`: /// - /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?) + /// ``` /// #![feature(coroutines)] - /// |a| { + /// static |a| { /// let x = &vec![3]; /// yield a; /// yield x[0]; @@ -273,12 +280,13 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize { CoroutineWitness(_, _) => 18, Never => 19, Tuple(_) => 20, - Alias(_, _) => 21, - Param(_) => 22, - Bound(_, _) => 23, - Placeholder(_) => 24, - Infer(_) => 25, - Error(_) => 26, + Pat(_, _) => 21, + Alias(_, _) => 22, + Param(_) => 23, + Bound(_, _) => 24, + Placeholder(_) => 25, + Infer(_) => 26, + Error(_) => 27, } } @@ -299,6 +307,7 @@ impl<I: Interner> PartialEq for TyKind<I> { (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s, (Foreign(a_d), Foreign(b_d)) => a_d == b_d, (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c, + (Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c, (Slice(a_t), Slice(b_t)) => a_t == b_t, (RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m, (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m, @@ -322,7 +331,7 @@ impl<I: Interner> PartialEq for TyKind<I> { _ => { debug_assert!( tykind_discriminant(self) != tykind_discriminant(other), - "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}" + "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}" ); false } @@ -362,18 +371,10 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { Foreign(d) => f.debug_tuple("Foreign").field(d).finish(), Str => write!(f, "str"), Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), + Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)), Slice(t) => write!(f, "[{:?}]", &this.wrap(t)), - RawPtr(ty, mutbl) => { - match mutbl { - Mutability::Mut => write!(f, "*mut "), - Mutability::Not => write!(f, "*const "), - }?; - write!(f, "{:?}", &this.wrap(ty)) - } - Ref(r, t, m) => match m { - Mutability::Mut => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)), - Mutability::Not => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)), - }, + RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), this.wrap(ty)), + Ref(r, t, m) => write!(f, "&{:?} {}{:?}", this.wrap(r), m.prefix_str(), this.wrap(t)), FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(), FnPtr(s) => write!(f, "{:?}", &this.wrap(s)), Dynamic(p, r, repr) => match repr { diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index d6a3f9f0749..2f588c67f56 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -110,6 +110,10 @@ pub trait TypeVisitor<I: Interner>: Sized { fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { p.super_visit_with(self) } + + fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result { + p.super_visit_with(self) + } } /////////////////////////////////////////////////////////////////////////// @@ -423,6 +427,16 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { ControlFlow::Continue(()) } } + + #[inline] + fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result { + // Note: no `super_visit_with` call. + if clauses.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -515,6 +529,15 @@ impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor { ControlFlow::Continue(()) } } + + #[inline] + fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result { + if clauses.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) + } + } } struct HasErrorVisitor; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 8ed34fab54d..94c552199bc 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; -use crate::mir::{Body, Place}; +use crate::mir::{BinOp, Body, Place}; use crate::target::MachineInfo; use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -211,6 +211,9 @@ pub trait Context { /// Get a debug string representation of a place. fn place_pretty(&self, place: &Place) -> String; + + /// Get the resulting type of binary operation. + fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 8f77a19fc0e..1ad05633d62 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,3 +1,4 @@ +use crate::compiler_interface::with; use crate::mir::pretty::function_body; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, @@ -337,42 +338,7 @@ impl BinOp { /// Return the type of this operation for the given input Ty. /// This function does not perform type checking, and it currently doesn't handle SIMD. pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty { - match self { - BinOp::Add - | BinOp::AddUnchecked - | BinOp::Sub - | BinOp::SubUnchecked - | BinOp::Mul - | BinOp::MulUnchecked - | BinOp::Div - | BinOp::Rem - | BinOp::BitXor - | BinOp::BitAnd - | BinOp::BitOr => { - assert_eq!(lhs_ty, rhs_ty); - assert!(lhs_ty.kind().is_primitive()); - lhs_ty - } - BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => { - assert!(lhs_ty.kind().is_primitive()); - assert!(rhs_ty.kind().is_primitive()); - lhs_ty - } - BinOp::Offset => { - assert!(lhs_ty.kind().is_raw_ptr()); - assert!(rhs_ty.kind().is_integral()); - lhs_ty - } - BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { - assert_eq!(lhs_ty, rhs_ty); - let lhs_kind = lhs_ty.kind(); - assert!(lhs_kind.is_primitive() || lhs_kind.is_raw_ptr() || lhs_kind.is_fn_ptr()); - Ty::bool_ty() - } - BinOp::Cmp => { - unimplemented!("Should cmp::Ordering be a RigidTy?"); - } - } + with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty)) } } @@ -993,7 +959,7 @@ pub enum NullOp { AlignOf, /// Returns the offset of a field. OffsetOf(Vec<(VariantIdx, FieldIdx)>), - /// cfg!(debug_assertions), but at codegen time + /// cfg!(ub_checks), but at codegen time UbChecks, } diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index aafa89c03e0..a032a180fcf 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -41,13 +41,22 @@ impl Instance { with(|cx| cx.instance_args(self.def)) } - /// Get the body of an Instance. The body will be eagerly monomorphized. + /// Get the body of an Instance. + /// + /// The body will be eagerly monomorphized and all constants will already be evaluated. + /// + /// This method will return the intrinsic fallback body if one was defined. pub fn body(&self) -> Option<Body> { with(|context| context.instance_body(self.def)) } /// Check whether this instance has a body available. /// + /// For intrinsics with fallback body, this will return `true`. It is up to the user to decide + /// whether to specialize the intrinsic or to use its fallback body. + /// + /// For more information on fallback body, see <https://github.com/rust-lang/rust/issues/93145>. + /// /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build /// the StableMIR body. pub fn has_body(&self) -> bool { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 3e8d186b97e..bc6fb34493a 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -99,6 +99,12 @@ impl Ty { } } +/// Represents a pattern in the type system +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Pattern { + Range { start: Option<Const>, end: Option<Const>, include_end: bool }, +} + /// Represents a constant in MIR or from the Type system. #[derive(Clone, Debug, Eq, PartialEq)] pub struct Const { @@ -481,6 +487,7 @@ pub enum RigidTy { Foreign(ForeignDef), Str, Array(Ty, Const), + Pat(Ty, Pattern), Slice(Ty), RawPtr(Ty, Mutability), Ref(Region, Ty, Mutability), diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index 65e42879d61..2d7159f87fe 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -139,6 +139,7 @@ impl Visitable for RigidTy { t.visit(visitor)?; c.visit(visitor) } + RigidTy::Pat(t, _p) => t.visit(visitor), RigidTy::Slice(inner) => inner.visit(visitor), RigidTy::RawPtr(ty, _) => ty.visit(visitor), RigidTy::Ref(reg, ty, _) => { diff --git a/config.example.toml b/config.example.toml index b8cdc2ec848..0d4b4e9e7e0 100644 --- a/config.example.toml +++ b/config.example.toml @@ -50,7 +50,7 @@ # # Note that many of the LLVM options are not currently supported for # downloading. Currently only the "assertions" option can be toggled. -#download-ci-llvm = if rust.channel == "dev" { "if-unchanged" } else { false } +#download-ci-llvm = if rust.channel == "dev" || rust.download-rustc != false { "if-unchanged" } else { false } # Indicates whether the LLVM build is a Release or Debug build #optimize = true @@ -302,7 +302,7 @@ # Set the bootstrap/download cache path. It is useful when building rust # repeatedly in a CI invironment. -# bootstrap-cache-path = /shared/cache +#bootstrap-cache-path = /path/to/shared/cache # Enable a build of the extended Rust tool set which is not only the compiler # but also tools such as Cargo. This will also produce "combined installers" diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index 638f343fb24..0561f49c967 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -1,6 +1,8 @@ // Disabling on android for the time being // See https://github.com/rust-lang/rust/issues/73535#event-3477699747 #![cfg(not(target_os = "android"))] +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] #![feature(btree_extract_if)] #![feature(iter_next_chunk)] #![feature(repr_simd)] diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 0421a12b3a9..8b145b67bf1 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -4,10 +4,14 @@ use crate::alloc::{self, Layout, LayoutError}; use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; +#[cfg(not(no_global_oom_handling))] +use core::intrinsics::const_allocate; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; -use core::mem::{self, SizedTypeProperties}; +use core::mem; +#[cfg(not(no_global_oom_handling))] +use core::mem::SizedTypeProperties; use core::ops::{Deref, DerefMut}; use core::ptr::Pointee; use core::ptr::{self, NonNull}; @@ -109,9 +113,14 @@ impl<Dyn: ?Sized> ThinBox<Dyn> { where T: Unsize<Dyn>, { - let meta = ptr::metadata(&value as &Dyn); - let ptr = WithOpaqueHeader::new(meta, value); - ThinBox { ptr, _marker: PhantomData } + if mem::size_of::<T>() == 0 { + let ptr = WithOpaqueHeader::new_unsize_zst::<Dyn, T>(value); + ThinBox { ptr, _marker: PhantomData } + } else { + let meta = ptr::metadata(&value as &Dyn); + let ptr = WithOpaqueHeader::new(meta, value); + ThinBox { ptr, _marker: PhantomData } + } } } @@ -200,6 +209,16 @@ impl WithOpaqueHeader { Self(ptr.0) } + #[cfg(not(no_global_oom_handling))] + fn new_unsize_zst<Dyn, T>(value: T) -> Self + where + Dyn: ?Sized, + T: Unsize<Dyn>, + { + let ptr = WithHeader::<<Dyn as Pointee>::Metadata>::new_unsize_zst::<Dyn, T>(value); + Self(ptr.0) + } + fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> { WithHeader::try_new(header, value).map(|ptr| Self(ptr.0)) } @@ -288,6 +307,58 @@ impl<H> WithHeader<H> { } } + // `Dyn` is `?Sized` type like `[u32]`, and `T` is ZST type like `[u32; 0]`. + #[cfg(not(no_global_oom_handling))] + fn new_unsize_zst<Dyn, T>(value: T) -> WithHeader<H> + where + Dyn: Pointee<Metadata = H> + ?Sized, + T: Unsize<Dyn>, + { + assert!(mem::size_of::<T>() == 0); + + const fn max(a: usize, b: usize) -> usize { + if a > b { a } else { b } + } + + // Compute a pointer to the right metadata. This will point to the beginning + // of the header, past the padding, so the assigned type makes sense. + // It also ensures that the address at the end of the header is sufficiently + // aligned for T. + let alloc: &<Dyn as Pointee>::Metadata = const { + // FIXME: just call `WithHeader::alloc_layout` with size reset to 0. + // Currently that's blocked on `Layout::extend` not being `const fn`. + + let alloc_align = + max(mem::align_of::<T>(), mem::align_of::<<Dyn as Pointee>::Metadata>()); + + let alloc_size = + max(mem::align_of::<T>(), mem::size_of::<<Dyn as Pointee>::Metadata>()); + + unsafe { + // SAFETY: align is power of two because it is the maximum of two alignments. + let alloc: *mut u8 = const_allocate(alloc_size, alloc_align); + + let metadata_offset = + alloc_size.checked_sub(mem::size_of::<<Dyn as Pointee>::Metadata>()).unwrap(); + // SAFETY: adding offset within the allocation. + let metadata_ptr: *mut <Dyn as Pointee>::Metadata = + alloc.add(metadata_offset).cast(); + // SAFETY: `*metadata_ptr` is within the allocation. + metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn)); + + // SAFETY: we have just written the metadata. + &*(metadata_ptr) + } + }; + + // SAFETY: `alloc` points to `<Dyn as Pointee>::Metadata`, so addition stays in-bounds. + let value_ptr = + unsafe { (alloc as *const <Dyn as Pointee>::Metadata).add(1) }.cast::<T>().cast_mut(); + debug_assert!(value_ptr.is_aligned()); + mem::forget(value); + WithHeader(NonNull::new(value_ptr.cast()).unwrap(), PhantomData) + } + // Safety: // - Assumes that either `value` can be dereferenced, or is the // `NonNull::dangling()` we use when both `T` and `H` are ZSTs. @@ -300,20 +371,19 @@ impl<H> WithHeader<H> { impl<H> Drop for DropGuard<H> { fn drop(&mut self) { + // All ZST are allocated statically. + if self.value_layout.size() == 0 { + return; + } + unsafe { // SAFETY: Layout must have been computable if we're in drop let (layout, value_offset) = WithHeader::<H>::alloc_layout(self.value_layout).unwrap_unchecked(); - // Note: Don't deallocate if the layout size is zero, because the pointer - // didn't come from the allocator. - if layout.size() != 0 { - alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout); - } else { - debug_assert!( - value_offset == 0 && H::IS_ZST && self.value_layout.size() == 0 - ); - } + // Since we only allocate for non-ZSTs, the layout size cannot be zero. + debug_assert!(layout.size() != 0); + alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout); } } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index e2fc320f280..693ecb0b6b4 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1614,7 +1614,10 @@ impl<T, A: Allocator> VecDeque<T, A> { let old_head = self.head; self.head = self.to_physical_idx(1); self.len -= 1; - Some(unsafe { self.buffer_read(old_head) }) + unsafe { + core::hint::assert_unchecked(self.len < self.capacity()); + Some(self.buffer_read(old_head)) + } } } @@ -1638,7 +1641,10 @@ impl<T, A: Allocator> VecDeque<T, A> { None } else { self.len -= 1; - Some(unsafe { self.buffer_read(self.to_physical_idx(self.len)) }) + unsafe { + core::hint::assert_unchecked(self.len < self.capacity()); + Some(self.buffer_read(self.to_physical_idx(self.len))) + } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cafd59cb0d9..dec04d7e421 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,11 +56,6 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell -// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be -// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no effect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -71,7 +66,6 @@ #![doc(cfg_hide( not(test), not(any(test, bootstrap)), - any(not(feature = "miri-test-libstd"), test, doctest), no_global_oom_handling, not(no_global_oom_handling), not(no_rc), @@ -114,8 +108,10 @@ #![feature(const_box)] #![feature(const_cow_is_borrowed)] #![feature(const_eval_select)] +#![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_write)] +#![feature(const_option)] #![feature(const_pin)] #![feature(const_refs_to_cell)] #![feature(const_size_of_val)] @@ -155,7 +151,6 @@ #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] #![feature(slice_ptr_get)] -#![feature(slice_ptr_len)] #![feature(slice_range)] #![feature(std_internals)] #![feature(str_internals)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 0883080d735..1134c7f833e 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -259,6 +259,17 @@ impl<T, A: Allocator> RawVec<T, A> { Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc } } + /// A convenience method for hoisting the non-null precondition out of [`RawVec::from_raw_parts_in`]. + /// + /// # Safety + /// + /// See [`RawVec::from_raw_parts_in`]. + #[inline] + pub(crate) unsafe fn from_nonnull_in(ptr: NonNull<T>, capacity: usize, alloc: A) -> Self { + let cap = if T::IS_ZST { Cap::ZERO } else { unsafe { Cap(capacity) } }; + Self { ptr: Unique::from(ptr), cap, alloc } + } + /// Gets a raw pointer to the start of the allocation. Note that this is /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 569db54b137..a320a244abd 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -884,7 +884,10 @@ impl<T, A: Allocator> Rc<T, A> { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn pin_in(value: T, alloc: A) -> Pin<Self> { + pub fn pin_in(value: T, alloc: A) -> Pin<Self> + where + A: 'static, + { unsafe { Pin::new_unchecked(Rc::new_in(value, alloc)) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4dea27221b7..297a273d274 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -807,7 +807,10 @@ impl<T, A: Allocator> Arc<T, A> { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn pin_in(data: T, alloc: A) -> Pin<Arc<T, A>> { + pub fn pin_in(data: T, alloc: A) -> Pin<Arc<T, A>> + where + A: 'static, + { unsafe { Pin::new_unchecked(Arc::new_in(data, alloc)) } } @@ -815,7 +818,10 @@ impl<T, A: Allocator> Arc<T, A> { /// fails. #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_pin_in(data: T, alloc: A) -> Result<Pin<Arc<T, A>>, AllocError> { + pub fn try_pin_in(data: T, alloc: A) -> Result<Pin<Arc<T, A>>, AllocError> + where + A: 'static, + { unsafe { Ok(Pin::new_unchecked(Arc::try_new_in(data, alloc)?)) } } @@ -1062,7 +1068,9 @@ impl<T, A: Allocator> Arc<T, A> { /// /// // Create a long list and clone it /// let mut x = LinkedList::new(); - /// for i in 0..100000 { + /// let size = 100000; + /// # let size = if cfg!(miri) { 100 } else { size }; + /// for i in 0..size { /// x.push(i); // Adds i to the front of x /// } /// let y = x.clone(); diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 4907a45e881..88aa1b1b0e0 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -161,7 +161,7 @@ use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, SizedTypeProperties}; use core::num::NonZero; -use core::ptr::{self, NonNull}; +use core::ptr; use super::{InPlaceDrop, InPlaceDstDataSrcBufDrop, SpecFromIter, SpecFromIterNested, Vec}; @@ -254,28 +254,30 @@ where let (src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe { let inner = iterator.as_inner().as_into_iter(); ( - inner.buf.as_ptr(), + inner.buf, inner.ptr, inner.cap, - inner.buf.as_ptr() as *mut T, + inner.buf.cast::<T>(), inner.end as *const T, inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(), ) }; // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer. - let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) }; + let len = unsafe { + SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf.as_ptr() as *mut T, dst_end) + }; let src = unsafe { iterator.as_inner().as_into_iter() }; // check if SourceIter contract was upheld // caveat: if they weren't we might not even make it to this point - debug_assert_eq!(src_buf, src.buf.as_ptr()); + debug_assert_eq!(src_buf, src.buf); // check InPlaceIterable contract. This is only possible if the iterator advanced the // source pointer at all. If it uses unchecked access via TrustedRandomAccess // then the source pointer will stay in its initial position and we can't use it as reference if src.ptr != src_ptr { debug_assert!( - unsafe { dst_buf.add(len) as *const _ } <= src.ptr.as_ptr(), + unsafe { dst_buf.add(len).cast() } <= src.ptr, "InPlaceIterable contract violation, write pointer advanced beyond read pointer" ); } @@ -315,10 +317,9 @@ where let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap); let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align); - let result = - alloc.shrink(NonNull::new_unchecked(dst_buf as *mut u8), old_layout, new_layout); + let result = alloc.shrink(dst_buf.cast(), old_layout, new_layout); let Ok(reallocated) = result else { handle_alloc_error(new_layout) }; - dst_buf = reallocated.as_ptr() as *mut T; + dst_buf = reallocated.cast::<T>(); } } else { debug_assert_eq!(src_cap * mem::size_of::<I::Src>(), dst_cap * mem::size_of::<T>()); @@ -326,7 +327,7 @@ where mem::forget(dst_guard); - let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) }; + let vec = unsafe { Vec::from_nonnull(dst_buf, len, dst_cap) }; vec } diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 40a540b57fc..4050c250130 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -1,4 +1,5 @@ use core::marker::PhantomData; +use core::ptr::NonNull; use core::ptr::{self, drop_in_place}; use core::slice::{self}; @@ -31,7 +32,7 @@ impl<T> Drop for InPlaceDrop<T> { // the source allocation - i.e. before the reallocation happened - to avoid leaking them // if some other destructor panics. pub(super) struct InPlaceDstDataSrcBufDrop<Src, Dest> { - pub(super) ptr: *mut Dest, + pub(super) ptr: NonNull<Dest>, pub(super) len: usize, pub(super) src_cap: usize, pub(super) src: PhantomData<Src>, @@ -42,8 +43,8 @@ impl<Src, Dest> Drop for InPlaceDstDataSrcBufDrop<Src, Dest> { fn drop(&mut self) { unsafe { let _drop_allocation = - RawVec::<Src>::from_raw_parts_in(self.ptr.cast::<Src>(), self.src_cap, Global); - drop_in_place(core::ptr::slice_from_raw_parts_mut::<Dest>(self.ptr, self.len)); + RawVec::<Src>::from_nonnull_in(self.ptr.cast::<Src>(), self.src_cap, Global); + drop_in_place(core::ptr::slice_from_raw_parts_mut::<Dest>(self.ptr.as_ptr(), self.len)); }; } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index dfd42ca0619..b0226c84833 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -433,7 +433,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> { // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec let alloc = ManuallyDrop::take(&mut self.0.alloc); // RawVec handles deallocation - let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); + let _ = RawVec::from_nonnull_in(self.0.buf, self.0.cap, alloc); } } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7e3463bc082..465da39f184 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -603,6 +603,17 @@ impl<T> Vec<T> { pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) } } + + /// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts`]. + /// + /// # Safety + /// + /// See [`Vec::from_raw_parts`]. + #[inline] + #[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling + pub(crate) unsafe fn from_nonnull(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { + unsafe { Self::from_nonnull_in(ptr, length, capacity, Global) } + } } impl<T, A: Allocator> Vec<T, A> { @@ -820,6 +831,22 @@ impl<T, A: Allocator> Vec<T, A> { unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } + /// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts_in`]. + /// + /// # Safety + /// + /// See [`Vec::from_raw_parts_in`]. + #[inline] + #[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling + pub(crate) unsafe fn from_nonnull_in( + ptr: NonNull<T>, + length: usize, + capacity: usize, + alloc: A, + ) -> Self { + unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } + } + /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`. /// /// Returns the raw pointer to the underlying data, the length of diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index 33dd4139bc0..6646ae7bccb 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -51,7 +51,7 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> { if has_advanced { ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len()); } - return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); + return Vec::from_nonnull(it.buf, it.len(), it.cap); } } diff --git a/library/backtrace b/library/backtrace -Subproject 6fa4b85b9962c3e1be8c2e5cc605cd078134152 +Subproject e15130618237eb3e2d4b622549f9647b4c1d9ca diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index 4d14b930e41..32d15c386cb 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -1,5 +1,7 @@ // wasm32 does not support benches (no time). #![cfg(not(target_arch = "wasm32"))] +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] #![feature(flt2dec)] #![feature(test)] #![feature(trusted_random_access)] diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index 489f95bbf10..a0ffb6d4750 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -116,6 +116,7 @@ where impl<T> Poll<Option<T>> { /// A helper function for internal desugaring -- produces `Ready(Some(t))`, /// which corresponds to the async iterator yielding a value. + #[doc(hidden)] #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenReady"] pub fn async_gen_ready(t: T) -> Self { @@ -124,6 +125,7 @@ impl<T> Poll<Option<T>> { /// A helper constant for internal desugaring -- produces `Pending`, /// which corresponds to the async iterator pending on an `.await`. + #[doc(hidden)] #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenPending"] // FIXME(gen_blocks): This probably could be deduplicated. @@ -131,6 +133,7 @@ impl<T> Poll<Option<T>> { /// A helper constant for internal desugaring -- produces `Ready(None)`, /// which corresponds to the async iterator finishing its iteration. + #[doc(hidden)] #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenFinished"] pub const FINISHED: Self = Poll::Ready(None); diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 0e719e169de..58b9ba4accb 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2071,6 +2071,7 @@ impl<T> UnsafeCell<T> { /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] + // When this is const stabilized, please remove `primitive_into_inner` below. #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] pub const fn into_inner(self) -> T { self.value @@ -2217,6 +2218,47 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {} +// Special cases of UnsafeCell::into_inner where T is a primitive. These are +// used by Atomic*::into_inner. +// +// The real UnsafeCell::into_inner cannot be used yet in a stable const function. +// That is blocked on a "precise drop analysis" unstable const feature. +// https://github.com/rust-lang/rust/issues/73255 +macro_rules! unsafe_cell_primitive_into_inner { + ($($primitive:ident $atomic:literal)*) => { + $( + #[cfg(target_has_atomic_load_store = $atomic)] + impl UnsafeCell<$primitive> { + pub(crate) const fn primitive_into_inner(self) -> $primitive { + self.value + } + } + )* + }; +} + +unsafe_cell_primitive_into_inner! { + i8 "8" + u8 "8" + i16 "16" + u16 "16" + i32 "32" + u32 "32" + i64 "64" + u64 "64" + i128 "128" + u128 "128" + isize "ptr" + usize "ptr" +} + +#[cfg(target_has_atomic_load_store = "ptr")] +impl<T> UnsafeCell<*mut T> { + pub(crate) const fn primitive_into_inner(self) -> *mut T { + self.value + } +} + /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 3877a0c48cb..a7c3dfc982d 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -164,6 +164,42 @@ impl<T> OnceCell<T> { } } + /// Gets the mutable reference of the contents of the cell, + /// initializing it with `f` if the cell was empty. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell = OnceCell::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::<T, !>(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -200,16 +236,55 @@ impl<T> OnceCell<T> { if let Some(val) = self.get() { return Ok(val); } - /// Avoid inlining the initialization closure into the common path that fetches - /// the already initialized value - #[cold] - fn outlined_call<F, T, E>(f: F) -> Result<T, E> - where - F: FnOnce() -> Result<T, E>, - { - f() + self.try_init(f) + } + + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell: OnceCell<u32> = OnceCell::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result<T, E>, + { + if self.get().is_none() { + self.try_init(f)?; } - let val = outlined_call(f)?; + Ok(self.get_mut().unwrap()) + } + + // Avoid inlining the initialization closure into the common path that fetches + // the already initialized value + #[cold] + fn try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + let val = f()?; // Note that *some* forms of reentrant initialization might lead to // UB (see `reentrant_init` test). I believe that just removing this // `panic`, while keeping `try_insert` would be sound, but it seems diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 44ae72bcd26..d448c5338fc 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -227,13 +227,10 @@ mod impls { impl_clone! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } - #[cfg(not(bootstrap))] - impl_clone! { f16 f128 } - #[unstable(feature = "never_type", issue = "35121")] impl Clone for ! { #[inline] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 81bba927554..fa218600ed9 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1497,12 +1497,9 @@ mod impls { } partial_eq_impl! { - bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 + bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } - #[cfg(not(bootstrap))] - partial_eq_impl! { f16 f128 } - macro_rules! eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -1553,10 +1550,7 @@ mod impls { } } - partial_ord_impl! { f32 f64 } - - #[cfg(not(bootstrap))] - partial_ord_impl! { f16 f128 } + partial_ord_impl! { f16 f32 f64 f128 } macro_rules! ord_impl { ($($t:ty)*) => ($( diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 0167d04c413..935ead2699a 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -34,8 +34,10 @@ macro_rules! impl_float_to_int { } } +impl_float_to_int!(f16 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +impl_float_to_int!(f128 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); // Conversion traits for primitive integer and float types // Conversions T -> T are covered by a blanket impl and therefore excluded @@ -163,7 +165,12 @@ impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); // float -> float +// FIXME(f16_f128): adding additional `From` impls for existing types breaks inference. See +// <https://github.com/rust-lang/rust/issues/123824> +impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); macro_rules! impl_float_from_bool { ($float:ty) => { diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index dbdbaccb535..f4f33f8584b 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -517,8 +517,6 @@ impl CStr { /// # Examples /// /// ``` - /// #![feature(cstr_count_bytes)] - /// /// use std::ffi::CStr; /// /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); @@ -530,7 +528,7 @@ impl CStr { #[inline] #[must_use] #[doc(alias("len", "strlen"))] - #[unstable(feature = "cstr_count_bytes", issue = "114441")] + #[stable(feature = "cstr_count_bytes", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] pub const fn count_bytes(&self) -> usize { self.inner.len() - 1 diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 3627e844222..cbdae2ac766 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -609,3 +609,13 @@ extern "rust-intrinsic" { #[rustc_nounwind] fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T; } + +// Link the MSVC default lib +#[cfg(all(windows, target_env = "msvc"))] +#[link( + name = "/defaultlib:msvcrt", + modifiers = "+verbatim", + cfg(not(target_feature = "crt-static")) +)] +#[link(name = "/defaultlib:libcmt", modifiers = "+verbatim", cfg(target_feature = "crt-static"))] +extern "C" {} diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 3bbf5d8770b..7f23d3c0956 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -228,3 +228,19 @@ macro_rules! floating { floating! { f32 } floating! { f64 } + +#[stable(feature = "rust1", since = "1.0.0")] +impl Debug for f16 { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{:#06x}", self.to_bits()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Debug for f128 { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{:#034x}", self.to_bits()) + } +} diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 287f6c23c89..ce0643a3f5e 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -860,10 +860,10 @@ pub trait Binary { /// Basic usage with `i32`: /// /// ``` -/// let x = 42; // 42 is '2a' in hex +/// let y = 42; // 42 is '2a' in hex /// -/// assert_eq!(format!("{x:x}"), "2a"); -/// assert_eq!(format!("{x:#x}"), "0x2a"); +/// assert_eq!(format!("{y:x}"), "2a"); +/// assert_eq!(format!("{y:#x}"), "0x2a"); /// /// assert_eq!(format!("{:x}", -16), "fffffff0"); /// ``` @@ -915,10 +915,10 @@ pub trait LowerHex { /// Basic usage with `i32`: /// /// ``` -/// let x = 42; // 42 is '2A' in hex +/// let y = 42; // 42 is '2A' in hex /// -/// assert_eq!(format!("{x:X}"), "2A"); -/// assert_eq!(format!("{x:#X}"), "0x2A"); +/// assert_eq!(format!("{y:X}"), "2A"); +/// assert_eq!(format!("{y:#X}"), "0x2A"); /// /// assert_eq!(format!("{:X}", -16), "FFFFFFF0"); /// ``` @@ -1150,7 +1150,12 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { if !piece.is_empty() { formatter.buf.write_str(*piece)?; } - arg.fmt(&mut formatter)?; + + // SAFETY: There are no formatting parameters and hence no + // count arguments. + unsafe { + arg.fmt(&mut formatter)?; + } idx += 1; } } @@ -1198,7 +1203,8 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume let value = unsafe { args.get_unchecked(arg.position) }; // Then actually do some printing - value.fmt(fmt) + // SAFETY: this is a placeholder argument. + unsafe { value.fmt(fmt) } } unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<usize> { diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs index cfb94cd9de5..a36e7efcd95 100644 --- a/library/core/src/fmt/nofloat.rs +++ b/library/core/src/fmt/nofloat.rs @@ -11,5 +11,7 @@ macro_rules! floating { }; } +floating! { f16 } floating! { f32 } floating! { f64 } +floating! { f128 } diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 5bf221b429f..5e4dac8f49b 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -4,6 +4,7 @@ //! These are the lang items used by format_args!(). use super::*; +use crate::hint::unreachable_unchecked; #[lang = "format_placeholder"] #[derive(Copy, Clone)] @@ -63,18 +64,26 @@ pub(super) enum Flag { DebugUpperHex, } -/// This struct represents the generic "argument" which is taken by format_args!(). -/// It contains a function to format the given value. At compile time it is ensured that the -/// function and the value have the correct types, and then this struct is used to canonicalize -/// arguments to one type. +#[derive(Copy, Clone)] +enum ArgumentType<'a> { + Placeholder { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result }, + Count(usize), +} + +/// This struct represents a generic "argument" which is taken by format_args!(). /// -/// Argument is essentially an optimized partially applied formatting function, -/// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. +/// This can be either a placeholder argument or a count argument. +/// * A placeholder argument contains a function to format the given value. At +/// compile time it is ensured that the function and the value have the correct +/// types, and then this struct is used to canonicalize arguments to one type. +/// Placeholder arguments are essentially an optimized partially applied formatting +/// function, equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. +/// * A count argument contains a count for dynamic formatting parameters like +/// precision and width. #[lang = "format_argument"] #[derive(Copy, Clone)] pub struct Argument<'a> { - value: &'a Opaque, - formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, + ty: ArgumentType<'a>, } #[rustc_diagnostic_item = "ArgumentMethods"] @@ -89,7 +98,14 @@ impl<'a> Argument<'a> { // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result` // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI // (as long as `T` is `Sized`) - unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } } + unsafe { + Argument { + ty: ArgumentType::Placeholder { + formatter: mem::transmute(f), + value: mem::transmute(x), + }, + } + } } #[inline(always)] @@ -130,30 +146,33 @@ impl<'a> Argument<'a> { } #[inline(always)] pub fn from_usize(x: &usize) -> Argument<'_> { - Self::new(x, USIZE_MARKER) + Argument { ty: ArgumentType::Count(*x) } } + /// Format this placeholder argument. + /// + /// # Safety + /// + /// This argument must actually be a placeholer argument. + /// // FIXME: Transmuting formatter in new and indirectly branching to/calling // it here is an explicit CFI violation. #[allow(inline_no_sanitize)] #[no_sanitize(cfi, kcfi)] #[inline(always)] - pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result { - (self.formatter)(self.value, f) + pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self.ty { + ArgumentType::Placeholder { formatter, value } => formatter(value, f), + // SAFETY: the caller promised this. + ArgumentType::Count(_) => unsafe { unreachable_unchecked() }, + } } #[inline(always)] pub(super) fn as_usize(&self) -> Option<usize> { - // We are type punning a bit here: USIZE_MARKER only takes an &usize but - // formatter takes an &Opaque. Rust understandably doesn't think we should compare - // the function pointers if they don't have the same signature, so we cast to - // usizes to tell it that we just want to compare addresses. - if self.formatter as usize == USIZE_MARKER as usize { - // SAFETY: The `formatter` field is only set to USIZE_MARKER if - // the value is a usize, so this is safe - Some(unsafe { *(self.value as *const _ as *const usize) }) - } else { - None + match self.ty { + ArgumentType::Count(count) => Some(count), + ArgumentType::Placeholder { .. } => None, } } @@ -193,24 +212,3 @@ impl UnsafeArg { extern "C" { type Opaque; } - -// This guarantees a single stable value for the function pointer associated with -// indices/counts in the formatting infrastructure. -// -// Note that a function defined as such would not be correct as functions are -// always tagged unnamed_addr with the current lowering to LLVM IR, so their -// address is not considered important to LLVM and as such the as_usize cast -// could have been miscompiled. In practice, we never call as_usize on non-usize -// containing data (as a matter of static generation of the formatting -// arguments), so this is merely an additional check. -// -// We primarily want to ensure that the function pointer at `USIZE_MARKER` has -// an address corresponding *only* to functions that also take `&usize` as their -// first argument. The read_volatile here ensures that we can safely ready out a -// usize from the passed reference and that this address does not point at a -// non-usize taking function. -static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { - // SAFETY: ptr is a reference - let _v: usize = unsafe { crate::ptr::read_volatile(ptr) }; - loop {} -}; diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 6dd3069034d..f965afc8a59 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -81,7 +81,7 @@ pub trait Future { /// An implementation of `poll` should strive to return quickly, and should /// not block. Returning quickly prevents unnecessarily clogging up /// threads or event loops. If it is known ahead of time that a call to - /// `poll` may end up taking awhile, the work should be offloaded to a + /// `poll` may end up taking a while, the work should be offloaded to a /// thread pool (or something similar) to ensure that `poll` can return /// quickly. /// diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b09d9fab8a7..9406efd7ab2 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1128,7 +1128,7 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -2704,17 +2704,17 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) { } /// Returns whether we should perform some UB-checking at runtime. This eventually evaluates to -/// `cfg!(debug_assertions)`, but behaves different from `cfg!` when mixing crates built with different -/// flags: if the crate has debug assertions enabled or carries the `#[rustc_preserve_ub_checks]` +/// `cfg!(ub_checks)`, but behaves different from `cfg!` when mixing crates built with different +/// flags: if the crate has UB checks enabled or carries the `#[rustc_preserve_ub_checks]` /// attribute, evaluation is delayed until monomorphization (or until the call gets inlined into /// a crate that does not delay evaluation further); otherwise it can happen any time. /// -/// The common case here is a user program built with debug_assertions linked against the distributed -/// sysroot which is built without debug_assertions but with `#[rustc_preserve_ub_checks]`. +/// The common case here is a user program built with ub_checks linked against the distributed +/// sysroot which is built without ub_checks but with `#[rustc_preserve_ub_checks]`. /// For code that gets monomorphized in the user crate (i.e., generic functions and functions with -/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(debug_assertions)` means that -/// assertions are enabled whenever the *user crate* has debug assertions enabled. However if the -/// user has debug assertions disabled, the checks will still get optimized out. This intrinsic is +/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that +/// assertions are enabled whenever the *user crate* has UB checks enabled. However if the +/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] #[unstable(feature = "core_intrinsics", issue = "none")] diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 778d38b1537..81371708b51 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -249,9 +249,10 @@ impl<'a> BorrowedCursor<'a> { /// Panics if there are less than `n` bytes initialized. #[inline] pub fn advance(&mut self, n: usize) -> &mut Self { - assert!(self.buf.init >= self.buf.filled + n); + let filled = self.buf.filled.strict_add(n); + assert!(filled <= self.buf.init); - self.buf.filled += n; + self.buf.filled = filled; self } diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index b8b96417d13..616dd0afc51 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,6 +1,7 @@ use crate::{ intrinsics, iter::{from_fn, TrustedLen, TrustedRandomAccess}, + num::NonZeroUsize, ops::{Range, Try}, }; @@ -22,7 +23,11 @@ pub struct StepBy<I> { /// Additionally this type-dependent preprocessing means specialized implementations /// cannot be used interchangeably. iter: I, - step: usize, + /// This field is `step - 1`, aka the correct amount to pass to `nth` when iterating. + /// It MUST NOT be `usize::MAX`, as `unsafe` code depends on being able to add one + /// without the risk of overflow. (This is important so that length calculations + /// don't need to check for division-by-zero, for example.) + step_minus_one: usize, first_take: bool, } @@ -31,7 +36,16 @@ impl<I> StepBy<I> { pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> { assert!(step != 0); let iter = <I as SpecRangeSetup<I>>::setup(iter, step); - StepBy { iter, step: step - 1, first_take: true } + StepBy { iter, step_minus_one: step - 1, first_take: true } + } + + /// The `step` that was originally passed to `Iterator::step_by(step)`, + /// aka `self.step_minus_one + 1`. + #[inline] + fn original_step(&self) -> NonZeroUsize { + // SAFETY: By type invariant, `step_minus_one` cannot be `MAX`, which + // means the addition cannot overflow and the result cannot be zero. + unsafe { NonZeroUsize::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) } } } @@ -81,8 +95,8 @@ where // The zero-based index starting from the end of the iterator of the // last element. Used in the `DoubleEndedIterator` implementation. fn next_back_index(&self) -> usize { - let rem = self.iter.len() % (self.step + 1); - if self.first_take { if rem == 0 { self.step } else { rem - 1 } } else { rem } + let rem = self.iter.len() % self.original_step(); + if self.first_take { if rem == 0 { self.step_minus_one } else { rem - 1 } } else { rem } } } @@ -209,7 +223,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { #[inline] default fn spec_next(&mut self) -> Option<I::Item> { - let step_size = if self.first_take { 0 } else { self.step }; + let step_size = if self.first_take { 0 } else { self.step_minus_one }; self.first_take = false; self.iter.nth(step_size) } @@ -217,22 +231,22 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { #[inline] default fn spec_size_hint(&self) -> (usize, Option<usize>) { #[inline] - fn first_size(step: usize) -> impl Fn(usize) -> usize { - move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } + fn first_size(step: NonZeroUsize) -> impl Fn(usize) -> usize { + move |n| if n == 0 { 0 } else { 1 + (n - 1) / step } } #[inline] - fn other_size(step: usize) -> impl Fn(usize) -> usize { - move |n| n / (step + 1) + fn other_size(step: NonZeroUsize) -> impl Fn(usize) -> usize { + move |n| n / step } let (low, high) = self.iter.size_hint(); if self.first_take { - let f = first_size(self.step); + let f = first_size(self.original_step()); (f(low), high.map(f)) } else { - let f = other_size(self.step); + let f = other_size(self.original_step()); (f(low), high.map(f)) } } @@ -247,10 +261,9 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { } n -= 1; } - // n and self.step are indices, we need to add 1 to get the amount of elements + // n and self.step_minus_one are indices, we need to add 1 to get the amount of elements // When calling `.nth`, we need to subtract 1 again to convert back to an index - // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` - let mut step = self.step + 1; + let mut step = self.original_step().get(); // n + 1 could overflow // thus, if n is usize::MAX, instead of adding one, we call .nth(step) if n == usize::MAX { @@ -288,8 +301,11 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { R: Try<Output = Acc>, { #[inline] - fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth(step) + fn nth<I: Iterator>( + iter: &mut I, + step_minus_one: usize, + ) -> impl FnMut() -> Option<I::Item> + '_ { + move || iter.nth(step_minus_one) } if self.first_take { @@ -299,7 +315,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { Some(x) => acc = f(acc, x)?, } } - from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) + from_fn(nth(&mut self.iter, self.step_minus_one)).try_fold(acc, f) } default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc @@ -307,8 +323,11 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { F: FnMut(Acc, Self::Item) -> Acc, { #[inline] - fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth(step) + fn nth<I: Iterator>( + iter: &mut I, + step_minus_one: usize, + ) -> impl FnMut() -> Option<I::Item> + '_ { + move || iter.nth(step_minus_one) } if self.first_take { @@ -318,7 +337,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { Some(x) => acc = f(acc, x), } } - from_fn(nth(&mut self.iter, self.step)).fold(acc, f) + from_fn(nth(&mut self.iter, self.step_minus_one)).fold(acc, f) } } @@ -336,7 +355,7 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St // is out of bounds because the length of `self.iter` does not exceed // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is // zero-indexed - let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index()); + let n = n.saturating_mul(self.original_step().get()).saturating_add(self.next_back_index()); self.iter.nth_back(n) } @@ -348,16 +367,16 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St #[inline] fn nth_back<I: DoubleEndedIterator>( iter: &mut I, - step: usize, + step_minus_one: usize, ) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth_back(step) + move || iter.nth_back(step_minus_one) } match self.next_back() { None => try { init }, Some(x) => { let acc = f(init, x)?; - from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) + from_fn(nth_back(&mut self.iter, self.step_minus_one)).try_fold(acc, f) } } } @@ -371,16 +390,16 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St #[inline] fn nth_back<I: DoubleEndedIterator>( iter: &mut I, - step: usize, + step_minus_one: usize, ) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth_back(step) + move || iter.nth_back(step_minus_one) } match self.next_back() { None => init, Some(x) => { let acc = f(init, x); - from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f) + from_fn(nth_back(&mut self.iter, self.step_minus_one)).fold(acc, f) } } } @@ -424,8 +443,7 @@ macro_rules! spec_int_ranges { fn spec_next(&mut self) -> Option<$t> { // if a step size larger than the type has been specified fall back to // t::MAX, in which case remaining will be at most 1. - // The `+ 1` can't overflow since the constructor substracted 1 from the original value. - let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX); let remaining = self.iter.end; if remaining > 0 { let val = self.iter.start; @@ -474,7 +492,7 @@ macro_rules! spec_int_ranges { { // if a step size larger than the type has been specified fall back to // t::MAX, in which case remaining will be at most 1. - let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX); let remaining = self.iter.end; let mut acc = init; let mut val = self.iter.start; @@ -500,7 +518,7 @@ macro_rules! spec_int_ranges_r { fn spec_next_back(&mut self) -> Option<Self::Item> where Range<$t>: DoubleEndedIterator + ExactSizeIterator, { - let step = (self.step + 1) as $t; + let step = self.original_step().get() as $t; let remaining = self.iter.end; if remaining > 0 { let start = self.iter.start; diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index d89801bce2b..2ebbe2bf274 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -150,6 +150,39 @@ pub trait FromIterator<A>: Sized { fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self; } +/// This implementation turns an iterator of tuples into a tuple of types which implement +/// [`Default`] and [`Extend`]. +/// +/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`] +/// implementations: +/// +/// ```rust +/// # fn main() -> Result<(), core::num::ParseIntError> { +/// let string = "1,2,123,4"; +/// +/// let (numbers, lengths): (Vec<_>, Vec<_>) = string +/// .split(',') +/// .map(|s| s.parse().map(|n: u32| (n, s.len()))) +/// .collect::<Result<_, _>>()?; +/// +/// assert_eq!(numbers, [1, 2, 123, 4]); +/// assert_eq!(lengths, [1, 1, 3, 1]); +/// # Ok(()) } +/// ``` +#[stable(feature = "from_iterator_for_tuple", since = "CURRENT_RUSTC_VERSION")] +impl<A, B, AE, BE> FromIterator<(AE, BE)> for (A, B) +where + A: Default + Extend<AE>, + B: Default + Extend<BE>, +{ + fn from_iter<I: IntoIterator<Item = (AE, BE)>>(iter: I) -> Self { + let mut res = <(A, B)>::default(); + res.extend(iter); + + res + } +} + /// Conversion into an [`Iterator`]. /// /// By implementing `IntoIterator` for a type, you define how it will be diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d2c9e1554b4..95c03043e3e 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1572,7 +1572,7 @@ pub trait Iterator { /// /// The returned iterator implements [`FusedIterator`], because once `self` /// returns `None`, even if it returns a `Some(T)` again in the next iterations, - /// we cannot put it into a contigious array buffer, and thus the returned iterator + /// we cannot put it into a contiguous array buffer, and thus the returned iterator /// should be fused. /// /// [`slice::windows()`]: slice::windows diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ba19ca1f45d..154565b6fee 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -57,10 +57,7 @@ // // This cfg won't affect doc tests. #![cfg(not(test))] -// To run core tests without x.py without ending up with two copies of core, Miri needs to be -// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no effect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// #![stable(feature = "core", since = "1.6.0")] #![doc( html_playground_url = "https://play.rust-lang.org/", @@ -71,7 +68,6 @@ #![doc(rust_logo)] #![doc(cfg_hide( not(test), - any(not(feature = "miri-test-libstd"), test, doctest), no_fp_fmt_parse, target_pointer_width = "16", target_pointer_width = "32", @@ -115,6 +111,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(array_ptr_get)] +#![feature(asm_experimental_arch)] #![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] @@ -125,7 +122,6 @@ #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_from_u32_unchecked)] #![feature(const_eval_select)] @@ -163,7 +159,6 @@ #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_from_ref)] #![feature(const_slice_index)] -#![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_strict_overflow_ops)] @@ -183,6 +178,7 @@ #![feature(ip_bits)] #![feature(is_ascii_octdigit)] #![feature(isqrt)] +#![feature(link_cfg)] #![feature(maybe_uninit_uninit_array)] #![feature(non_null_convenience)] #![feature(offset_of_enum)] @@ -205,8 +201,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(not(bootstrap), feature(f128))] -#![cfg_attr(not(bootstrap), feature(f16))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -231,6 +225,8 @@ #![feature(doc_notable_trait)] #![feature(effects)] #![feature(extern_types)] +#![feature(f128)] +#![feature(f16)] #![feature(freeze_impls)] #![feature(fundamental)] #![feature(generic_arg_infer)] @@ -352,6 +348,10 @@ pub mod u8; #[path = "num/shells/usize.rs"] pub mod usize; +#[path = "num/f128.rs"] +pub mod f128; +#[path = "num/f16.rs"] +pub mod f16; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] @@ -401,6 +401,9 @@ pub mod net; pub mod option; pub mod panic; pub mod panicking; +#[cfg(not(bootstrap))] +#[unstable(feature = "core_pattern_types", issue = "none")] +pub mod pat; pub mod pin; pub mod result; pub mod sync; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index fb97b3bfa09..1d073a6d649 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -422,17 +422,11 @@ marker_impls! { Copy for usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, - f32, f64, + f16, f32, f64, f128, bool, char, {T: ?Sized} *const T, {T: ?Sized} *mut T, -} -#[cfg(not(bootstrap))] -marker_impls! { - #[stable(feature = "rust1", since = "1.0.0")] - Copy for - f16, f128, } #[unstable(feature = "never_type", issue = "35121")] diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 55116285842..c24d8f55195 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -591,7 +591,7 @@ impl fmt::Display for SocketAddrV4 { if f.precision().is_none() && f.width().is_none() { write!(f, "{}:{}", self.ip(), self.port()) } else { - const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536"; + const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65535"; let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new(); // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail. @@ -621,7 +621,7 @@ impl fmt::Display for SocketAddrV6 { } } else { const LONGEST_IPV6_SOCKET_ADDR: &str = - "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536"; + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967295]:65535"; let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new(); match self.scope_id() { diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs new file mode 100644 index 00000000000..8a94964c8c5 --- /dev/null +++ b/library/core/src/num/f128.rs @@ -0,0 +1,120 @@ +//! Constants for the `f128` quadruple-precision floating point type. +//! +//! *[See also the `f128` primitive type][f128].* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. +//! +//! For the constants defined directly in this module +//! (as distinct from those defined in the `consts` sub-module), +//! new code should instead use the associated constants +//! defined directly on the `f128` type. + +#![unstable(feature = "f128", issue = "116909")] + +use crate::mem; + +/// Basic mathematical constants. +#[unstable(feature = "f128", issue = "116909")] +pub mod consts {} + +#[cfg(not(test))] +impl f128 { + // FIXME(f16_f128): almost everything in this `impl` is missing examples and a const + // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE. + + /// Returns `true` if this value is NaN. + #[inline] + #[must_use] + #[unstable(feature = "f128", issue = "116909")] + #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :) + pub const fn is_nan(self) -> bool { + self != self + } + + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with + /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. + #[inline] + #[must_use] + #[unstable(feature = "f128", issue = "116909")] + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + + /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with + /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. + #[inline] + #[must_use] + #[unstable(feature = "f128", issue = "116909")] + pub fn is_sign_negative(self) -> bool { + // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus + // applies to zeros and NaNs as well. + // SAFETY: This is just transmuting to get the sign bit, it's fine. + (self.to_bits() & (1 << 127)) != 0 + } + + /// Raw transmutation to `u128`. + /// + /// This is currently identical to `transmute::<f128, u128>(self)` on all platforms. + /// + /// See [`from_bits`](#method.from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + #[inline] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn to_bits(self) -> u128 { + // SAFETY: `u128` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(self) } + } + + /// Raw transmutation from `u128`. + /// + /// This is currently identical to `transmute::<u128, f128>(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE 754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE 754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favors preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + #[inline] + #[must_use] + #[unstable(feature = "f128", issue = "116909")] + pub fn from_bits(v: u128) -> Self { + // SAFETY: `u128 is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(v) } + } +} diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs new file mode 100644 index 00000000000..039f5188ba4 --- /dev/null +++ b/library/core/src/num/f16.rs @@ -0,0 +1,120 @@ +//! Constants for the `f16` half-precision floating point type. +//! +//! *[See also the `f16` primitive type][f16].* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. +//! +//! For the constants defined directly in this module +//! (as distinct from those defined in the `consts` sub-module), +//! new code should instead use the associated constants +//! defined directly on the `f16` type. + +#![unstable(feature = "f16", issue = "116909")] + +use crate::mem; + +/// Basic mathematical constants. +#[unstable(feature = "f16", issue = "116909")] +pub mod consts {} + +#[cfg(not(test))] +impl f16 { + // FIXME(f16_f128): almost everything in this `impl` is missing examples and a const + // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE. + + /// Returns `true` if this value is NaN. + #[inline] + #[must_use] + #[unstable(feature = "f16", issue = "116909")] + #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :) + pub const fn is_nan(self) -> bool { + self != self + } + + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with + /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. + #[inline] + #[must_use] + #[unstable(feature = "f128", issue = "116909")] + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + + /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with + /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. + #[inline] + #[must_use] + #[unstable(feature = "f128", issue = "116909")] + pub fn is_sign_negative(self) -> bool { + // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus + // applies to zeros and NaNs as well. + // SAFETY: This is just transmuting to get the sign bit, it's fine. + (self.to_bits() & (1 << 15)) != 0 + } + + /// Raw transmutation to `u16`. + /// + /// This is currently identical to `transmute::<f16, u16>(self)` on all platforms. + /// + /// See [`from_bits`](#method.from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + #[inline] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn to_bits(self) -> u16 { + // SAFETY: `u16` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(self) } + } + + /// Raw transmutation from `u16`. + /// + /// This is currently identical to `transmute::<u16, f16>(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE 754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE 754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favors preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + #[inline] + #[must_use] + #[unstable(feature = "f16", issue = "116909")] + pub fn from_bits(v: u16) -> Self { + // SAFETY: `u16` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(v) } + } +} diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index fd50f804748..5e77788d8ea 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -109,7 +109,7 @@ macro_rules! add_impl { )*) } -add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The subtraction operator `-`. /// @@ -218,7 +218,7 @@ macro_rules! sub_impl { )*) } -sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The multiplication operator `*`. /// @@ -348,7 +348,7 @@ macro_rules! mul_impl { )*) } -mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The division operator `/`. /// @@ -506,7 +506,7 @@ macro_rules! div_impl_float { )*) } -div_impl_float! { f32 f64 } +div_impl_float! { f16 f32 f64 f128 } /// The remainder operator `%`. /// @@ -623,7 +623,7 @@ macro_rules! rem_impl_float { )*) } -rem_impl_float! { f32 f64 } +rem_impl_float! { f16 f32 f64 f128 } /// The unary negation operator `-`. /// @@ -698,7 +698,7 @@ macro_rules! neg_impl { )*) } -neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } +neg_impl! { isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The addition assignment operator `+=`. /// @@ -765,7 +765,7 @@ macro_rules! add_assign_impl { )+) } -add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The subtraction assignment operator `-=`. /// @@ -832,7 +832,7 @@ macro_rules! sub_assign_impl { )+) } -sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The multiplication assignment operator `*=`. /// @@ -890,7 +890,7 @@ macro_rules! mul_assign_impl { )+) } -mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The division assignment operator `/=`. /// @@ -947,7 +947,7 @@ macro_rules! div_assign_impl { )+) } -div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } /// The remainder assignment operator `%=`. /// @@ -1008,4 +1008,4 @@ macro_rules! rem_assign_impl { )+) } -rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 3f8c8efd416..483f55b2070 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -310,7 +310,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// This should be implemented consistently with the `branch` method such /// that applying the `?` operator will get back an equivalent residual: /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`. - /// (It must not be an *identical* residual when interconversion is involved.) + /// (The residual is not mandated to be *identical* when interconversion is involved.) /// /// # Examples /// diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 6dcf23dde87..4ad507d8b86 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -81,7 +81,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] #[track_caller] #[inline] pub const fn caller() -> &'static Location<'static> { @@ -123,7 +123,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn file(&self) -> &str { self.file @@ -148,7 +148,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn line(&self) -> u32 { self.line @@ -173,7 +173,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_col", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn column(&self) -> u32 { self.col diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs new file mode 100644 index 00000000000..a10c4593342 --- /dev/null +++ b/library/core/src/pat.rs @@ -0,0 +1,14 @@ +//! Helper module for exporting the `pattern_type` macro + +/// Creates a pattern type. +/// ```ignore (cannot test this from within core yet) +/// type Positive = std::pat::pattern_type!(i32 is 1..); +/// ``` +#[macro_export] +#[rustc_builtin_macro(pattern_type)] +#[unstable(feature = "core_pattern_type", issue = "none")] +macro_rules! pattern_type { + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index e843a5d5790..efd525aeb3b 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -379,11 +379,11 @@ //! //! Exposing access to the inner field which you want to remain pinned must then be carefully //! considered as well! Remember, exposing a method that gives access to a -//! <code>[Pin]<[&mut] InnerT>></code> where `InnerT: [Unpin]` would allow safe code to trivially -//! move the inner value out of that pinning pointer, which is precisely what you're seeking to -//! prevent! Exposing a field of a pinned value through a pinning pointer is called "projecting" -//! a pin, and the more general case of deciding in which cases a pin should be able to be -//! projected or not is called "structural pinning." We will go into more detail about this +//! <code>[Pin]<[&mut] InnerT>></code> where <code>InnerT: [Unpin]</code> would allow safe code to +//! trivially move the inner value out of that pinning pointer, which is precisely what you're +//! seeking to prevent! Exposing a field of a pinned value through a pinning pointer is called +//! "projecting" a pin, and the more general case of deciding in which cases a pin should be able +//! to be projected or not is called "structural pinning." We will go into more detail about this //! [below][structural-pinning]. //! //! # Examples of address-sensitive types @@ -1198,7 +1198,7 @@ impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> { /// Unwraps this `Pin<Ptr>`, returning the underlying pointer. /// /// Doing this operation safely requires that the data pointed at by this pinning pointer - /// implemts [`Unpin`] so that we can ignore the pinning invariants when unwrapping it. + /// implements [`Unpin`] so that we can ignore the pinning invariants when unwrapping it. /// /// # Examples /// diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 15da4171bda..e8e23f2a7ec 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1074,7 +1074,22 @@ mod prim_tuple {} #[doc(hidden)] impl<T> (T,) {} +#[rustc_doc_primitive = "f16"] +#[doc(alias = "half")] +/// A 16-bit floating point type (specifically, the "binary16" type defined in IEEE 754-2008). +/// +/// This type is very similar to [`prim@f32`] but has decreased precision because it uses half as many +/// bits. Please see [the documentation for [`prim@f32`] or [Wikipedia on +/// half-precision values][wikipedia] for more information. +/// +/// *[See also the `std::f16::consts` module](crate::f16::consts).* +/// +/// [wikipedia]: https://en.wikipedia.org/wiki/Half-precision_floating-point_format +#[unstable(feature = "f16", issue = "116909")] +mod prim_f16 {} + #[rustc_doc_primitive = "f32"] +#[doc(alias = "single")] /// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008). /// /// This type can represent a wide range of decimal numbers, like `3.5`, `27`, @@ -1143,6 +1158,7 @@ impl<T> (T,) {} mod prim_f32 {} #[rustc_doc_primitive = "f64"] +#[doc(alias = "double")] /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008). /// /// This type is very similar to [`f32`], but has increased @@ -1157,6 +1173,20 @@ mod prim_f32 {} #[stable(feature = "rust1", since = "1.0.0")] mod prim_f64 {} +#[rustc_doc_primitive = "f128"] +#[doc(alias = "quad")] +/// A 128-bit floating point type (specifically, the "binary128" type defined in IEEE 754-2008). +/// +/// This type is very similar to [`prim@f32`] and [`prim@f64`], but has increased precision by using twice +/// as many bits as `f64`. Please see [the documentation for [`prim@f32`] or [Wikipedia on +/// quad-precision values][wikipedia] for more information. +/// +/// *[See also the `std::f128::consts` module](crate::f128::consts).* +/// +/// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format +#[unstable(feature = "f128", issue = "116909")] +mod prim_f128 {} + #[rustc_doc_primitive = "i8"] // /// The 8-bit signed integer type. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 01db050e666..9737fb8816e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1647,16 +1647,15 @@ impl<T> *const [T] { /// # Examples /// /// ```rust - /// #![feature(slice_ptr_len)] - /// /// use std::ptr; /// /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); /// assert_eq!(slice.len(), 3); /// ``` #[inline] - #[unstable(feature = "slice_ptr_len", issue = "71146")] - #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) } @@ -1666,15 +1665,14 @@ impl<T> *const [T] { /// # Examples /// /// ``` - /// #![feature(slice_ptr_len)] /// use std::ptr; /// /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); /// assert!(!slice.is_empty()); /// ``` #[inline(always)] - #[unstable(feature = "slice_ptr_len", issue = "71146")] - #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(self) -> bool { self.len() == 0 } @@ -1804,7 +1802,7 @@ impl<T, const N: usize> *const [T; N] { /// # Examples /// /// ``` - /// #![feature(array_ptr_get, slice_ptr_len)] + /// #![feature(array_ptr_get)] /// /// let arr: *const [i32; 3] = &[1, 2, 4] as *const [i32; 3]; /// let slice: *const [i32] = arr.as_slice(); diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 41e5ba67458..d8f91f1996b 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -464,8 +464,8 @@ impl<T: ?Sized> *mut T { /// let ptr: *mut u32 = s.as_mut_ptr(); /// /// unsafe { - /// println!("{}", *ptr.offset(1)); - /// println!("{}", *ptr.offset(2)); + /// assert_eq!(2, *ptr.offset(1)); + /// assert_eq!(3, *ptr.offset(2)); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1027,8 +1027,8 @@ impl<T: ?Sized> *mut T { /// let ptr: *const u8 = s.as_ptr(); /// /// unsafe { - /// println!("{}", *ptr.add(1) as char); - /// println!("{}", *ptr.add(2) as char); + /// assert_eq!('2', *ptr.add(1) as char); + /// assert_eq!('3', *ptr.add(2) as char); /// } /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] @@ -1111,8 +1111,8 @@ impl<T: ?Sized> *mut T { /// /// unsafe { /// let end: *const u8 = s.as_ptr().add(3); - /// println!("{}", *end.sub(1) as char); - /// println!("{}", *end.sub(2) as char); + /// assert_eq!('3', *end.sub(1) as char); + /// assert_eq!('2', *end.sub(2) as char); /// } /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] @@ -1909,15 +1909,15 @@ impl<T> *mut [T] { /// # Examples /// /// ```rust - /// #![feature(slice_ptr_len)] /// use std::ptr; /// /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); /// assert_eq!(slice.len(), 3); /// ``` #[inline(always)] - #[unstable(feature = "slice_ptr_len", issue = "71146")] - #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) } @@ -1927,15 +1927,14 @@ impl<T> *mut [T] { /// # Examples /// /// ``` - /// #![feature(slice_ptr_len)] /// use std::ptr; /// /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); /// assert!(!slice.is_empty()); /// ``` #[inline(always)] - #[unstable(feature = "slice_ptr_len", issue = "71146")] - #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(self) -> bool { self.len() == 0 } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index f0e4b958bc6..96ce3cd3a3f 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1562,7 +1562,6 @@ impl<T> NonNull<[T]> { /// ``` #[stable(feature = "slice_ptr_len_nonnull", since = "1.63.0")] #[rustc_const_stable(feature = "const_slice_ptr_len_nonnull", since = "1.63.0")] - #[rustc_allow_const_fn_unstable(const_slice_ptr_len)] #[must_use] #[inline] pub const fn len(self) -> usize { @@ -1574,14 +1573,16 @@ impl<T> NonNull<[T]> { /// # Examples /// /// ```rust - /// #![feature(slice_ptr_is_empty_nonnull)] /// use std::ptr::NonNull; /// /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); /// assert!(!slice.is_empty()); /// ``` - #[unstable(feature = "slice_ptr_is_empty_nonnull", issue = "71146")] - #[rustc_const_unstable(feature = "const_slice_ptr_is_empty_nonnull", issue = "71146")] + #[stable(feature = "slice_ptr_is_empty_nonnull", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable( + feature = "const_slice_ptr_is_empty_nonnull", + since = "CURRENT_RUSTC_VERSION" + )] #[must_use] #[inline] pub const fn is_empty(self) -> bool { diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 672af752149..ba2d6f64496 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -1,6 +1,7 @@ //! Trait implementations for `str`. use crate::cmp::Ordering; +use crate::intrinsics::unchecked_sub; use crate::ops; use crate::ptr; use crate::slice::SliceIndex; @@ -210,9 +211,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> { // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. - let ptr = unsafe { slice.as_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts(ptr, len) as *const str + unsafe { + let new_len = unchecked_sub(self.end, self.start); + ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str + } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { @@ -229,9 +231,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> { ); // SAFETY: see comments for `get_unchecked`. - let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts_mut(ptr, len) as *mut str + unsafe { + let new_len = unchecked_sub(self.end, self.start); + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str + } } #[inline] fn index(self, slice: &str) -> &Self::Output { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0a749fcb8f9..c8fd997a5da 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -578,9 +578,9 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] pub const fn into_inner(self) -> bool { - self.v.into_inner() != 0 + self.v.primitive_into_inner() != 0 } /// Loads a value from the bool. @@ -1397,9 +1397,9 @@ impl<T> AtomicPtr<T> { /// ``` #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] pub const fn into_inner(self) -> *mut T { - self.p.into_inner() + self.p.primitive_into_inner() } /// Loads a value from the pointer. @@ -2378,9 +2378,9 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable_access] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] pub const fn into_inner(self) -> $int_type { - self.v.into_inner() + self.v.primitive_into_inner() } /// Loads a value from the atomic integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8c5e5ecf5fe..e741149e7ce 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -11,7 +11,6 @@ #![feature(const_align_offset)] #![feature(const_align_of_val_raw)] #![feature(const_black_box)] -#![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] @@ -25,7 +24,6 @@ #![cfg_attr(not(bootstrap), feature(const_three_way_compare))] #![feature(const_trait_impl)] #![feature(const_likely)] -#![feature(const_location_fields)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] @@ -56,7 +54,6 @@ #![feature(sort_internals)] #![feature(slice_take)] #![feature(slice_from_ptr_range)] -#![feature(slice_ptr_len)] #![feature(slice_split_once)] #![feature(split_as_slice)] #![feature(maybe_uninit_fill)] diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index e6ea2b1849b..a9d1f53761c 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -15,5 +15,7 @@ doc = false alloc = { path = "../alloc" } cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } core = { path = "../core" } -libc = { version = "0.2", default-features = false } compiler_builtins = "0.1.0" + +[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +libc = { version = "0.2", default-features = false } diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index 85386976d63..dce2da31644 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -14,7 +14,9 @@ doc = false [dependencies] alloc = { path = "../alloc" } core = { path = "../core" } -libc = { version = "0.2", default-features = false } unwind = { path = "../unwind" } compiler_builtins = "0.1.0" cfg-if = "1.0" + +[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +libc = { version = "0.2", default-features = false } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index dde1c64c6f1..b0245de501e 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -19,6 +19,8 @@ #![feature(panic_unwind)] #![feature(staged_api)] #![feature(std_internals)] +#![feature(strict_provenance)] +#![feature(exposed_provenance)] #![feature(rustc_attrs)] #![panic_runtime] #![feature(panic_runtime)] diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index e63749c77ce..04c3d3bf9c3 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -48,9 +48,9 @@ use alloc::boxed::Box; use core::any::Any; +use core::ffi::{c_int, c_uint, c_void}; use core::mem::{self, ManuallyDrop}; use core::ptr::{addr_of, addr_of_mut}; -use libc::{c_int, c_uint, c_void}; // NOTE(nbdd0121): The `canary` field is part of stable ABI. #[repr(C)] @@ -109,58 +109,88 @@ struct Exception { // [1]: https://www.geoffchappell.com/studies/msvc/language/predefined/ #[cfg(target_arch = "x86")] -#[macro_use] mod imp { - pub type ptr_t = *mut u8; - - macro_rules! ptr { - (0) => { - core::ptr::null_mut() - }; - ($e:expr) => { - $e as *mut u8 - }; + #[repr(transparent)] + #[derive(Copy, Clone)] + pub struct ptr_t(*mut u8); + + impl ptr_t { + pub const fn null() -> Self { + Self(core::ptr::null_mut()) + } + + pub const fn new(ptr: *mut u8) -> Self { + Self(ptr) + } + + pub const fn raw(self) -> *mut u8 { + self.0 + } } } #[cfg(not(target_arch = "x86"))] -#[macro_use] mod imp { - pub type ptr_t = u32; + use core::ptr::addr_of; + + // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`. + #[repr(transparent)] + #[derive(Copy, Clone)] + pub struct ptr_t(u32); extern "C" { pub static __ImageBase: u8; } - macro_rules! ptr { - (0) => (0); - ($e:expr) => { - (($e as usize) - (addr_of!(imp::__ImageBase) as usize)) as u32 + impl ptr_t { + pub const fn null() -> Self { + Self(0) + } + + pub fn new(ptr: *mut u8) -> Self { + // We need to expose the provenance of the pointer because it is not carried by + // the `u32`, while the FFI needs to have this provenance to excess our statics. + // + // NOTE(niluxv): we could use `MaybeUninit<u32>` instead to leak the provenance + // into the FFI. In theory then the other side would need to do some processing + // to get a pointer with correct provenance, but these system functions aren't + // going to be cross-lang LTOed anyway. However, using expose is shorter and + // requires less unsafe. + let addr: usize = ptr.expose_provenance(); + let image_base = unsafe { addr_of!(__ImageBase) }.addr(); + let offset: usize = addr - image_base; + Self(offset as u32) + } + + pub const fn raw(self) -> u32 { + self.0 } } } +use imp::ptr_t; + #[repr(C)] pub struct _ThrowInfo { pub attributes: c_uint, - pub pmfnUnwind: imp::ptr_t, - pub pForwardCompat: imp::ptr_t, - pub pCatchableTypeArray: imp::ptr_t, + pub pmfnUnwind: ptr_t, + pub pForwardCompat: ptr_t, + pub pCatchableTypeArray: ptr_t, } #[repr(C)] pub struct _CatchableTypeArray { pub nCatchableTypes: c_int, - pub arrayOfCatchableTypes: [imp::ptr_t; 1], + pub arrayOfCatchableTypes: [ptr_t; 1], } #[repr(C)] pub struct _CatchableType { pub properties: c_uint, - pub pType: imp::ptr_t, + pub pType: ptr_t, pub thisDisplacement: _PMD, pub sizeOrOffset: c_int, - pub copyFunction: imp::ptr_t, + pub copyFunction: ptr_t, } #[repr(C)] @@ -186,20 +216,20 @@ const TYPE_NAME: [u8; 11] = *b"rust_panic\0"; static mut THROW_INFO: _ThrowInfo = _ThrowInfo { attributes: 0, - pmfnUnwind: ptr!(0), - pForwardCompat: ptr!(0), - pCatchableTypeArray: ptr!(0), + pmfnUnwind: ptr_t::null(), + pForwardCompat: ptr_t::null(), + pCatchableTypeArray: ptr_t::null(), }; static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = - _CatchableTypeArray { nCatchableTypes: 1, arrayOfCatchableTypes: [ptr!(0)] }; + _CatchableTypeArray { nCatchableTypes: 1, arrayOfCatchableTypes: [ptr_t::null()] }; static mut CATCHABLE_TYPE: _CatchableType = _CatchableType { properties: 0, - pType: ptr!(0), + pType: ptr_t::null(), thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 }, sizeOrOffset: mem::size_of::<Exception>() as c_int, - copyFunction: ptr!(0), + copyFunction: ptr_t::null(), }; extern "C" { @@ -246,9 +276,9 @@ macro_rules! define_cleanup { super::__rust_drop_panic(); } } - unsafe extern $abi2 fn exception_copy(_dest: *mut Exception, - _src: *mut Exception) - -> *mut Exception { + unsafe extern $abi2 fn exception_copy( + _dest: *mut Exception, _src: *mut Exception + ) -> *mut Exception { panic!("Rust panics cannot be copied"); } } @@ -296,24 +326,24 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pmfnUnwind) as *mut u32, - ptr!(exception_cleanup) as u32, + addr_of_mut!(THROW_INFO.pmfnUnwind).cast(), + ptr_t::new(exception_cleanup as *mut u8).raw(), ); atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pCatchableTypeArray) as *mut u32, - ptr!(addr_of!(CATCHABLE_TYPE_ARRAY)) as u32, + addr_of_mut!(THROW_INFO.pCatchableTypeArray).cast(), + ptr_t::new(addr_of_mut!(CATCHABLE_TYPE_ARRAY).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]) as *mut u32, - ptr!(addr_of!(CATCHABLE_TYPE)) as u32, + addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), + ptr_t::new(addr_of_mut!(CATCHABLE_TYPE).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.pType) as *mut u32, - ptr!(addr_of!(TYPE_DESCRIPTOR)) as u32, + addr_of_mut!(CATCHABLE_TYPE.pType).cast(), + ptr_t::new(addr_of_mut!(TYPE_DESCRIPTOR).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.copyFunction) as *mut u32, - ptr!(exception_copy) as u32, + addr_of_mut!(CATCHABLE_TYPE.copyFunction).cast(), + ptr_t::new(exception_copy as *mut u8).raw(), ); extern "system-unwind" { diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index f3cfc41bac7..faca745e56f 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -283,7 +283,11 @@ fn maybe_install_panic_hook(force_show_panics: bool) { HIDE_PANICS_DURING_EXPANSION.call_once(|| { let prev = panic::take_hook(); panic::set_hook(Box::new(move |info| { - if force_show_panics || !is_available() { + // We normally report panics by catching unwinds and passing the payload from the + // unwind back to the compiler, but if the panic doesn't unwind we'll abort before + // the compiler has a chance to print an error. So we special-case PanicInfo where + // can_unwind is false. + if force_show_panics || !is_available() || !info.can_unwind() { prev(info) } })); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 01c449563ee..a3ebef45c88 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -30,6 +30,7 @@ #![feature(maybe_uninit_write_slice)] #![feature(negative_impls)] #![feature(new_uninit)] +#![feature(panic_can_unwind)] #![feature(restricted_std)] #![feature(rustc_attrs)] #![feature(min_specialization)] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d2804b4d20a..cba9ff4485d 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,6 @@ 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.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" } @@ -31,6 +30,12 @@ rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.21.0", optional = true, default-features = false } +[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true } + +[target.'cfg(all(windows, target_env = "msvc"))'.dependencies] +libc = { version = "0.2.153", default-features = false } + [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] } diff --git a/library/std/benches/lib.rs b/library/std/benches/lib.rs index 4d1cf7fab7b..1b21c230a0b 100644 --- a/library/std/benches/lib.rs +++ b/library/std/benches/lib.rs @@ -1,3 +1,5 @@ +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] #![feature(test)] extern crate test; diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs new file mode 100644 index 00000000000..4710d7c50b4 --- /dev/null +++ b/library/std/src/f128.rs @@ -0,0 +1,11 @@ +//! Constants for the `f128` double-precision floating point type. +//! +//! *[See also the `f128` primitive type](primitive@f128).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. + +#[cfg(test)] +mod tests; + +#[unstable(feature = "f128", issue = "116909")] +pub use core::f128::consts; diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs new file mode 100644 index 00000000000..b64c7f856a1 --- /dev/null +++ b/library/std/src/f128/tests.rs @@ -0,0 +1,40 @@ +#![allow(dead_code)] // FIXME(f16_f128): remove once constants are used + +/// Smallest number +const TINY_BITS: u128 = 0x1; +/// Next smallest number +const TINY_UP_BITS: u128 = 0x2; +/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 +const MAX_DOWN_BITS: u128 = 0x7ffeffffffffffffffffffffffffffff; +/// Zeroed exponent, full significant +const LARGEST_SUBNORMAL_BITS: u128 = 0x0000ffffffffffffffffffffffffffff; +/// Exponent = 0b1, zeroed significand +const SMALLEST_NORMAL_BITS: u128 = 0x00010000000000000000000000000000; +/// First pattern over the mantissa +const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; +/// Second pattern over the mantissa +const NAN_MASK2: u128 = 0x00005555555555555555555555555555; + +/// Compare by value +#[allow(unused_macros)] +macro_rules! assert_f128_eq { + ($a:expr, $b:expr) => { + let (l, r): (&f128, &f128) = (&$a, &$b); + assert_eq!(*l, *r, "\na: {:#0130x}\nb: {:#0130x}", l.to_bits(), r.to_bits()) + }; +} + +/// Compare by representation +#[allow(unused_macros)] +macro_rules! assert_f128_biteq { + ($a:expr, $b:expr) => { + let (l, r): (&f128, &f128) = (&$a, &$b); + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!( + lb, rb, + "float {:?} is not bitequal to {:?}.\na: {:#0130x}\nb: {:#0130x}", + *l, *r, lb, rb + ); + }; +} diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs new file mode 100644 index 00000000000..c36f9f5d4c6 --- /dev/null +++ b/library/std/src/f16.rs @@ -0,0 +1,11 @@ +//! Constants for the `f16` double-precision floating point type. +//! +//! *[See also the `f16` primitive type](primitive@f16).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. + +#[cfg(test)] +mod tests; + +#[unstable(feature = "f16", issue = "116909")] +pub use core::f16::consts; diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs new file mode 100644 index 00000000000..d65c43eca4b --- /dev/null +++ b/library/std/src/f16/tests.rs @@ -0,0 +1,46 @@ +#![allow(dead_code)] // FIXME(f16_f128): remove once constants are used + +// We run out of precision pretty quickly with f16 +const F16_APPROX_L1: f16 = 0.001; +const F16_APPROX_L2: f16 = 0.01; +const F16_APPROX_L3: f16 = 0.1; +const F16_APPROX_L4: f16 = 0.5; + +/// Smallest number +const TINY_BITS: u16 = 0x1; +/// Next smallest number +const TINY_UP_BITS: u16 = 0x2; +/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 +const MAX_DOWN_BITS: u16 = 0x7bfe; +/// Zeroed exponent, full significant +const LARGEST_SUBNORMAL_BITS: u16 = 0x03ff; +/// Exponent = 0b1, zeroed significand +const SMALLEST_NORMAL_BITS: u16 = 0x0400; +/// First pattern over the mantissa +const NAN_MASK1: u16 = 0x02aa; +/// Second pattern over the mantissa +const NAN_MASK2: u16 = 0x0155; + +/// Compare by value +#[allow(unused_macros)] +macro_rules! assert_f16_eq { + ($a:expr, $b:expr) => { + let (l, r): (&f16, &f16) = (&$a, &$b); + assert_eq!(*l, *r, "\na: {:#018x}\nb: {:#018x}", l.to_bits(), r.to_bits()) + }; +} + +/// Compare by representation +#[allow(unused_macros)] +macro_rules! assert_f16_biteq { + ($a:expr, $b:expr) => { + let (l, r): (&f16, &f16) = (&$a, &$b); + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!( + lb, rb, + "float {:?} is not bitequal to {:?}.\na: {:#018x}\nb: {:#018x}", + *l, *r, lb, rb + ); + }; +} diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b1102b440e0..8a24949631c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -465,14 +465,20 @@ impl File { OpenOptions::new() } - /// Attempts to sync all OS-internal metadata to disk. + /// Attempts to sync all OS-internal file content and metadata to disk. /// /// This function will attempt to ensure that all in-memory data reaches the /// filesystem before returning. /// /// This can be used to handle errors that would otherwise only be caught - /// when the `File` is closed. Dropping a file will ignore errors in - /// synchronizing this in-memory data. + /// when the `File` is closed, as dropping a `File` will ignore all errors. + /// Note, however, that `sync_all` is generally more expensive than closing + /// a file by dropping it, because the latter is not required to block until + /// the data has been written to the filesystem. + /// + /// If synchronizing the metadata is not required, use [`sync_data`] instead. + /// + /// [`sync_data`]: File::sync_data /// /// # Examples /// @@ -489,6 +495,7 @@ impl File { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "fsync")] pub fn sync_all(&self) -> io::Result<()> { self.inner.fsync() } @@ -520,6 +527,7 @@ impl File { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "fdatasync")] pub fn sync_data(&self) -> io::Result<()> { self.inner.datasync() } @@ -985,7 +993,7 @@ impl OpenOptions { /// If a file is opened with both read and append access, beware that after /// opening, and after every write, the position for reading may be set at the /// end of the file. So, before writing, save the current position (using - /// <code>[seek]\([SeekFrom]::[Current]\(0))</code>), and restore it before the next read. + /// <code>[Seek]::[stream_position]</code>), and restore it before the next read. /// /// ## Note /// @@ -994,8 +1002,7 @@ impl OpenOptions { /// /// [`write()`]: Write::write "io::Write::write" /// [`flush()`]: Write::flush "io::Write::flush" - /// [seek]: Seek::seek "io::Seek::seek" - /// [Current]: SeekFrom::Current "io::SeekFrom::Current" + /// [stream_position]: Seek::stream_position "io::Seek::stream_position" /// /// # Examples /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 6a92832fcdb..ff399a0acd5 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -187,9 +187,9 @@ fn file_test_io_seek_and_tell_smoke_test() { { let mut read_stream = check!(File::open(filename)); check!(read_stream.seek(SeekFrom::Start(set_cursor))); - tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); + tell_pos_pre_read = check!(read_stream.stream_position()); check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); + tell_pos_post_read = check!(read_stream.stream_position()); } check!(fs::remove_file(filename)); let read_str = str::from_utf8(&read_mem).unwrap(); @@ -284,42 +284,42 @@ fn file_test_io_read_write_at() { let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); let mut rw = check!(oo.open(&filename)); assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.stream_position()), 0); assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.stream_position()), 0); assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.stream_position()), 0); assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.stream_position()), 5); assert_eq!(check!(rw.read(&mut buf)), write1.len()); assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.stream_position()), 9); assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.stream_position()), 9); assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.stream_position()), 9); } { let mut read = check!(File::open(&filename)); assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(read.stream_position()), 0); assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(read.stream_position()), 9); assert_eq!(check!(read.read(&mut buf)), write3.len()); assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); assert_eq!(check!(read.read_at(&mut buf, 14)), 0); assert_eq!(check!(read.read_at(&mut buf, 15)), 0); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); } check!(fs::remove_file(&filename)); } @@ -362,38 +362,38 @@ fn file_test_io_seek_read_write() { let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); let mut rw = check!(oo.open(&filename)); assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.stream_position()), 9); assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.stream_position()), 9); assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.stream_position()), 5); assert_eq!(check!(rw.read(&mut buf)), write1.len()); assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.stream_position()), 9); assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.stream_position()), 5); assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(rw.stream_position()), 14); } { let mut read = check!(File::open(&filename)); assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); assert_eq!(check!(read.read(&mut buf)), write3.len()); assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.stream_position()), 14); assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index acaa7e9228e..0cdc49c87d8 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -322,6 +322,14 @@ impl<R: ?Sized + Read> Read for BufReader<R> { crate::io::default_read_exact(self, buf) } + fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + if self.buf.consume_with(cursor.capacity(), |claimed| cursor.append(claimed)) { + return Ok(()); + } + + crate::io::default_read_buf_exact(self, cursor) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); if self.buf.pos() == self.buf.filled() && total_len >= self.capacity() { @@ -375,12 +383,7 @@ impl<R: ?Sized + Read> Read for BufReader<R> { // buffer. let mut bytes = Vec::new(); self.read_to_end(&mut bytes)?; - let string = crate::str::from_utf8(&bytes).map_err(|_| { - io::const_io_error!( - io::ErrorKind::InvalidData, - "stream did not contain valid UTF-8", - ) - })?; + let string = crate::str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?; *buf += string; Ok(string.len()) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 35a5291a347..ee0db30e22c 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -114,7 +114,7 @@ fn test_buffered_reader_seek() { assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); + assert_eq!(reader.stream_position().ok(), Some(3)); assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); @@ -230,6 +230,9 @@ fn test_buffered_reader_seek_underflow() { Ok(len) } } + // note: this implementation of `Seek` is "broken" due to position + // wrapping, so calling `reader.seek(Current(0))` is semantically different + // than `reader.stream_position()` impl Seek for PositionReader { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { match pos { @@ -374,7 +377,7 @@ fn test_buffered_writer_seek() { let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); w.write_all(&[6, 7]).unwrap(); - assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); + assert_eq!(w.stream_position().ok(), Some(8)); assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); w.write_all(&[8, 9]).unwrap(); diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 4ef1f1b695e..49dde828c1f 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -357,6 +357,13 @@ where self.pos += n as u64; Ok(()) } + + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + let n = cursor.capacity(); + Read::read_buf_exact(&mut self.remaining_slice(), cursor)?; + self.pos += n as u64; + Ok(()) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 85625116d02..21ae7b91207 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -75,6 +75,30 @@ impl fmt::Debug for Error { } } +/// Common errors constants for use in std +#[allow(dead_code)] +impl Error { + pub(crate) const INVALID_UTF8: Self = + const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); + + pub(crate) const READ_EXACT_EOF: Self = + const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); + + pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_io_error!( + ErrorKind::NotFound, + "The number of hardware threads is not known for the target platform" + ); + + pub(crate) const UNSUPPORTED_PLATFORM: Self = + const_io_error!(ErrorKind::Unsupported, "operation not supported on this platform"); + + pub(crate) const WRITE_ALL_EOF: Self = + const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"); + + pub(crate) const ZERO_TIMEOUT: Self = + const_io_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); +} + #[stable(feature = "rust1", since = "1.0.0")] impl From<alloc::ffi::NulError> for Error { /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. @@ -828,15 +852,19 @@ impl Error { } } - /// Attempt to downcast the inner error to `E` if any. + /// Attempt to downcast the custom boxed error to `E`. /// - /// If this [`Error`] was constructed via [`new`] then this function will - /// attempt to perform downgrade on it, otherwise it will return [`Err`]. + /// If this [`Error`] contains a custom boxed error, + /// then it would attempt downcasting on the boxed error, + /// otherwise it will return [`Err`]. /// - /// If the downcast succeeds, it will return [`Ok`], otherwise it will also - /// return [`Err`]. + /// If the custom boxed error has the same type as `E`, it will return [`Ok`], + /// otherwise it will also return [`Err`]. + /// + /// This method is meant to be a convenience routine for calling + /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by + /// [`Error::into_inner`]. /// - /// [`new`]: Error::new /// /// # Examples /// diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index cb972abd2b8..dd7e0725176 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -5,9 +5,7 @@ use crate::alloc::Allocator; use crate::cmp; use crate::collections::VecDeque; use crate::fmt; -use crate::io::{ - self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write, -}; +use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::mem; use crate::str; @@ -50,6 +48,10 @@ impl<R: Read + ?Sized> Read for &mut R { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { (**self).read_exact(buf) } + #[inline] + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf_exact(cursor) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<W: Write + ?Sized> Write for &mut W { @@ -154,6 +156,10 @@ impl<R: Read + ?Sized> Read for Box<R> { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { (**self).read_exact(buf) } + #[inline] + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf_exact(cursor) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<W: Write + ?Sized> Write for Box<W> { @@ -281,10 +287,7 @@ impl Read for &[u8] { #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { if buf.len() > self.len() { - return Err(io::const_io_error!( - ErrorKind::UnexpectedEof, - "failed to fill whole buffer" - )); + return Err(io::Error::READ_EXACT_EOF); } let (a, b) = self.split_at(buf.len()); @@ -302,6 +305,19 @@ impl Read for &[u8] { } #[inline] + fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + if cursor.capacity() > self.len() { + return Err(io::Error::READ_EXACT_EOF); + } + let (a, b) = self.split_at(cursor.capacity()); + + cursor.append(a); + + *self = b; + Ok(()) + } + + #[inline] fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { let len = self.len(); buf.try_reserve(len)?; @@ -312,9 +328,7 @@ impl Read for &[u8] { #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { - let content = str::from_utf8(self).map_err(|_| { - io::const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8") - })?; + let content = str::from_utf8(self).map_err(|_| io::Error::INVALID_UTF8)?; buf.push_str(content); let len = self.len(); *self = &self[len..]; @@ -375,11 +389,7 @@ impl Write for &mut [u8] { #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? == data.len() { - Ok(()) - } else { - Err(io::const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer")) - } + if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) } } #[inline] @@ -467,9 +477,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> { // middle of an UTF-8 character. let len = self.len(); let content = self.make_contiguous(); - let string = str::from_utf8(content).map_err(|_| { - io::const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8") - })?; + let string = str::from_utf8(content).map_err(|_| io::Error::INVALID_UTF8)?; buf.push_str(string); self.clear(); Ok(len) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 10bf9c51d16..98973a43e1d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -311,14 +311,14 @@ pub use self::buffered::WriterPanicked; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use self::error::RawOsError; pub(crate) use self::stdio::attempt_print_to_stderr; -#[unstable(feature = "internal_output_capture", issue = "none")] -#[doc(no_inline, hidden)] -pub use self::stdio::set_output_capture; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; #[unstable(feature = "print_internals", issue = "none")] #[doc(hidden)] pub use self::stdio::{_eprint, _print}; +#[unstable(feature = "internal_output_capture", issue = "none")] +#[doc(no_inline, hidden)] +pub use self::stdio::{set_output_capture, try_set_output_capture}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::{ buffered::{BufReader, BufWriter, IntoInnerError, LineWriter}, @@ -385,12 +385,7 @@ where let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; let ret = f(g.buf); if str::from_utf8(&g.buf[g.len..]).is_err() { - ret.and_then(|_| { - Err(error::const_io_error!( - ErrorKind::InvalidData, - "stream did not contain valid UTF-8" - )) - }) + ret.and_then(|_| Err(Error::INVALID_UTF8)) } else { g.len = g.buf.len(); ret @@ -566,11 +561,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ Err(e) => return Err(e), } } - if !buf.is_empty() { - Err(error::const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer")) - } else { - Ok(()) - } + if !buf.is_empty() { Err(Error::READ_EXACT_EOF) } else { Ok(()) } } pub(crate) fn default_read_buf<F>(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()> @@ -582,6 +573,26 @@ where Ok(()) } +pub(crate) fn default_read_buf_exact<R: Read + ?Sized>( + this: &mut R, + mut cursor: BorrowedCursor<'_>, +) -> Result<()> { + while cursor.capacity() > 0 { + let prev_written = cursor.written(); + match this.read_buf(cursor.reborrow()) { + Ok(()) => {} + Err(e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + } + + if cursor.written() == prev_written { + return Err(Error::READ_EXACT_EOF); + } + } + + Ok(()) +} + /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -978,24 +989,8 @@ pub trait Read { /// /// If this function returns an error, all bytes read will be appended to `cursor`. #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> { - while cursor.capacity() > 0 { - let prev_written = cursor.written(); - match self.read_buf(cursor.reborrow()) { - Ok(()) => {} - Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - } - - if cursor.written() == prev_written { - return Err(error::const_io_error!( - ErrorKind::UnexpectedEof, - "failed to fill whole buffer" - )); - } - } - - Ok(()) + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { + default_read_buf_exact(self, cursor) } /// Creates a "by reference" adaptor for this instance of `Read`. @@ -1702,10 +1697,7 @@ pub trait Write { while !buf.is_empty() { match self.write(buf) { Ok(0) => { - return Err(error::const_io_error!( - ErrorKind::WriteZero, - "failed to write whole buffer", - )); + return Err(Error::WRITE_ALL_EOF); } Ok(n) => buf = &buf[n..], Err(ref e) if e.is_interrupted() => {} @@ -1770,10 +1762,7 @@ pub trait Write { while !bufs.is_empty() { match self.write_vectored(bufs) { Ok(0) => { - return Err(error::const_io_error!( - ErrorKind::WriteZero, - "failed to write whole buffer", - )); + return Err(Error::WRITE_ALL_EOF); } Ok(n) => IoSlice::advance_slices(&mut bufs, n), Err(ref e) if e.is_interrupted() => {} diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 8f60b3b1535..07fa9259e0b 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -15,6 +15,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard}; use crate::sys::stdio; +use crate::thread::AccessError; type LocalStream = Arc<Mutex<Vec<u8>>>; @@ -451,6 +452,9 @@ impl Read for Stdin { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.lock().read_exact(buf) } + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.lock().read_buf_exact(cursor) + } } #[stable(feature = "read_shared_stdin", since = "1.78.0")] @@ -477,6 +481,9 @@ impl Read for &Stdin { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.lock().read_exact(buf) } + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.lock().read_buf_exact(cursor) + } } // only used by platform-dependent io::copy specializations, i.e. unused on some platforms @@ -517,6 +524,10 @@ impl Read for StdinLock<'_> { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.inner.read_exact(buf) } + + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf_exact(cursor) + } } impl SpecReadByte for StdinLock<'_> { @@ -1054,12 +1065,31 @@ impl fmt::Debug for StderrLock<'_> { )] #[doc(hidden)] pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> { + try_set_output_capture(sink).expect( + "cannot access a Thread Local Storage value \ + during or after destruction", + ) +} + +/// Tries to set the thread-local output capture buffer and returns the old one. +/// This may fail once thread-local destructors are called. It's used in panic +/// handling instead of `set_output_capture`. +#[unstable( + feature = "internal_output_capture", + reason = "this function is meant for use in the test crate \ + and may disappear in the future", + issue = "none" +)] +#[doc(hidden)] +pub fn try_set_output_capture( + sink: Option<LocalStream>, +) -> Result<Option<LocalStream>, AccessError> { if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) { // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false. - return None; + return Ok(None); } OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed); - OUTPUT_CAPTURE.with(move |slot| slot.replace(sink)) + OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink)) } /// Write `args` to the capture buffer if enabled and possible, or `global_s` diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index eb5d5988768..090a091b09a 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -210,6 +210,15 @@ fn read_buf_exact() { } #[test] +#[should_panic] +fn borrowed_cursor_advance_overflow() { + let mut buf = [0; 512]; + let mut buf = BorrowedBuf::from(&mut buf[..]); + buf.unfilled().advance(1); + buf.unfilled().advance(usize::MAX); +} + +#[test] fn take_eof() { struct R; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 31a8711e0eb..72ae38cfa20 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -212,15 +212,18 @@ //! [rust-discord]: https://discord.gg/rust-lang //! [array]: prim@array //! [slice]: prim@slice -// To run std tests without x.py without ending up with two copies of std, Miri needs to be -// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no effect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. -#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] -// + #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] -#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] +#![cfg_attr( + feature = "restricted-std", + unstable( + feature = "restricted_std", + issue = "none", + reason = "You have attempted to use a standard library built for a platform that it doesn't \ + know how to support. Consider building it for a known environment, disabling it with \ + `#![no_std]` or overriding this warning by enabling this feature." + ) +)] #![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)] #![doc( html_playground_url = "https://play.rust-lang.org/", @@ -262,7 +265,6 @@ feature(slice_index_methods, coerce_unsized, sgx_platform) )] #![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))] #![cfg_attr( all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"), @@ -289,6 +291,8 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] +#![feature(f128)] +#![feature(f16)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(lang_items)] @@ -427,6 +431,9 @@ extern crate test; #[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] extern crate alloc as alloc_crate; + +// Many compiler tests depend on libc being pulled in by std +// so include it here even if it's unused. #[doc(masked)] #[allow(unused_extern_crates)] extern crate libc; @@ -564,6 +571,10 @@ pub use core::u8; #[allow(deprecated, deprecated_in_future)] pub use core::usize; +#[unstable(feature = "f128", issue = "116909")] +pub mod f128; +#[unstable(feature = "f16", issue = "116909")] +pub mod f16; pub mod f32; pub mod f64; @@ -582,6 +593,9 @@ pub mod net; pub mod num; pub mod os; pub mod panic; +#[cfg(not(bootstrap))] +#[unstable(feature = "core_pattern_types", issue = "none")] +pub mod pat; pub mod path; pub mod process; pub mod sync; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 0b3c5153871..010ce4e5076 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -117,10 +117,7 @@ impl BorrowedFd<'_> { #[cfg(any(target_arch = "wasm32", target_os = "hermit"))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { - Err(crate::io::const_io_error!( - crate::io::ErrorKind::Unsupported, - "operation not supported on this platform", - )) + Err(crate::io::Error::UNSUPPORTED_PLATFORM) } } diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 058e9b90cc7..970023d8cf1 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -127,11 +127,7 @@ pub trait FileExt { Err(e) => return Err(e), } } - if !buf.is_empty() { - Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",)) - } else { - Ok(()) - } + if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } } /// Writes a number of bytes starting from a given offset. @@ -249,10 +245,7 @@ pub trait FileExt { while !buf.is_empty() { match self.write_at(buf, offset) { Ok(0) => { - return Err(io::const_io_error!( - io::ErrorKind::WriteZero, - "failed to write whole buffer", - )); + return Err(io::Error::WRITE_ALL_EOF); } Ok(n) => { buf = &buf[n..]; diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 9757653e02c..79f2c365025 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -11,7 +11,7 @@ use crate::{fmt, io, mem, ptr}; #[cfg(not(unix))] #[allow(non_camel_case_types)] mod libc { - pub use libc::c_int; + pub use core::ffi::c_int; pub type socklen_t = u32; pub struct sockaddr; #[derive(Clone)] @@ -107,6 +107,16 @@ impl SocketAddr { addr: libc::sockaddr_un, mut len: libc::socklen_t, ) -> io::Result<SocketAddr> { + if cfg!(target_os = "openbsd") { + // on OpenBSD, getsockname(2) returns the actual size of the socket address, + // and not the len of the content. Figure out the length for ourselves. + // https://marc.info/?l=openbsd-bugs&m=170105481926736&w=2 + let sun_path: &[u8] = + unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) }; + len = core::slice::memchr::memchr(0, sun_path) + .map_or(len, |new_len| (new_len + sun_path_offset(&addr)) as libc::socklen_t); + } + if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 1d279d6adbc..0597fdcbd72 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -20,7 +20,7 @@ use crate::sys::net::Socket; ))] #[allow(non_camel_case_types)] mod libc { - pub use libc::c_int; + pub use core::ffi::c_int; pub struct ucred; pub struct cmsghdr; pub struct sockcred2; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index df698c17f6c..b29f9099a11 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -34,7 +34,7 @@ use libc::MSG_NOSIGNAL; target_os = "haiku", target_os = "nto", )))] -const MSG_NOSIGNAL: libc::c_int = 0x0; +const MSG_NOSIGNAL: core::ffi::c_int = 0x0; /// A Unix datagram socket. /// @@ -317,7 +317,7 @@ impl UnixDatagram { fn recv_from_flags( &self, buf: &mut [u8], - flags: libc::c_int, + flags: core::ffi::c_int, ) -> io::Result<(usize, SocketAddr)> { let mut count = 0; let addr = SocketAddr::new(|addr, len| unsafe { diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 31286a906ea..7e53acbc387 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -79,14 +79,14 @@ impl UnixListener { target_os = "espidf", target_os = "horizon" ))] - const backlog: libc::c_int = 128; + const backlog: core::ffi::c_int = 128; #[cfg(any( target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "macos" ))] - const backlog: libc::c_int = -1; + const backlog: core::ffi::c_int = -1; #[cfg(not(any( target_os = "windows", target_os = "redox", @@ -138,9 +138,9 @@ impl UnixListener { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; #[cfg(target_os = "linux")] - const backlog: libc::c_int = -1; + const backlog: core::ffi::c_int = -1; #[cfg(not(target_os = "linux"))] - const backlog: libc::c_int = 128; + const backlog: core::ffi::c_int = 128; cvt(libc::bind( inner.as_raw_fd(), core::ptr::addr_of!(socket_addr.addr) as *const _, diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 4525c3aa914..46fc2a50de9 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -86,11 +86,7 @@ pub trait FileExt { Err(e) => return Err(e), } } - if !buf.is_empty() { - Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")) - } else { - Ok(()) - } + if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } } /// Writes a number of bytes starting from a given offset. @@ -153,10 +149,7 @@ pub trait FileExt { while !buf.is_empty() { match self.write_at(buf, offset) { Ok(0) => { - return Err(io::const_io_error!( - io::ErrorKind::WriteZero, - "failed to write whole buffer", - )); + return Err(io::Error::WRITE_ALL_EOF); } Ok(n) => { buf = &buf[n..]; diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 1be3acf5d43..15ab2250122 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -199,8 +199,60 @@ pub trait CommandExt: Sealed { /// Append literal text to the command line without any quoting or escaping. /// - /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow - /// `CommandLineToArgvW` escaping rules. + /// This is useful for passing arguments to applications which doesn't follow + /// the standard C run-time escaping rules, such as `cmd.exe /c`. + /// + /// # Bat files + /// + /// Note the `cmd /c` command line has slightly different escaping rules then bat files + /// themselves. If possible, it may be better to write complex arguments to a temporary + /// .bat file, with appropriate escaping, and simply run that using: + /// + /// ```no_run + /// # use std::process::Command; + /// # let temp_bat_file = ""; + /// # #[allow(unused)] + /// let output = Command::new("cmd").args(["/c", &format!("\"{temp_bat_file}\"")]).output(); + /// ``` + /// + /// # Example + /// + /// Run a bat script using both trusted and untrusted arguments. + /// + /// ```no_run + /// #[cfg(windows)] + /// // `my_script_path` is a path to known bat file. + /// // `user_name` is an untrusted name given by the user. + /// fn run_script( + /// my_script_path: &str, + /// user_name: &str, + /// ) -> Result<std::process::Output, std::io::Error> { + /// use std::io::{Error, ErrorKind}; + /// use std::os::windows::process::CommandExt; + /// use std::process::Command; + /// + /// // Create the command line, making sure to quote the script path. + /// // This assumes the fixed arguments have been tested to work with the script we're using. + /// let mut cmd_args = format!(r#""{my_script_path}" "--features=[a,b,c]""#); + /// + /// // Make sure the user name is safe. In particular we need to be + /// // cautious of ascii symbols that cmd may interpret specially. + /// // Here we only allow alphanumeric characters. + /// if !user_name.chars().all(|c| c.is_alphanumeric()) { + /// return Err(Error::new(ErrorKind::InvalidInput, "invalid user name")); + /// } + /// // now we've checked the user name, let's add that too. + /// cmd_args.push(' '); + /// cmd_args.push_str(&format!("--user {user_name}")); + /// + /// // call cmd.exe and return the output + /// Command::new("cmd.exe") + /// .arg("/c") + /// // surround the entire command in an extra pair of quotes, as required by cmd.exe. + /// .raw_arg(&format!("\"{cmd_args}\"")) + /// .output() + /// } + /// ```` #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")] fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command; diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index f46e1e171d2..0052fcbb94a 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -24,11 +24,11 @@ use crate::sys_common::backtrace; use crate::thread; #[cfg(not(test))] -use crate::io::set_output_capture; +use crate::io::try_set_output_capture; // make sure to use the stderr output configured // by libtest in the real copy of std #[cfg(test)] -use realstd::io::set_output_capture; +use realstd::io::try_set_output_capture; // Binary interface to the panic runtime that the standard library depends on. // @@ -284,9 +284,9 @@ fn default_hook(info: &PanicInfo<'_>) { } }; - if let Some(local) = set_output_capture(None) { + if let Ok(Some(local)) = try_set_output_capture(None) { write(&mut *local.lock().unwrap_or_else(|e| e.into_inner())); - set_output_capture(Some(local)); + try_set_output_capture(Some(local)).ok(); } else if let Some(mut out) = panic_output() { write(&mut out); } diff --git a/library/std/src/pat.rs b/library/std/src/pat.rs new file mode 100644 index 00000000000..aeddd84c2cb --- /dev/null +++ b/library/std/src/pat.rs @@ -0,0 +1,3 @@ +//! Helper module for exporting the `pattern_type` macro + +pub use core::pattern_type; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 56ea51226f9..5f43d63bf84 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2143,10 +2143,10 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::Path; + /// use std::path::{Path, PathBuf}; /// /// let path_buf = Path::new("foo.txt").to_path_buf(); - /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt")); + /// assert_eq!(path_buf, PathBuf::from("foo.txt")); /// ``` #[rustc_conversion_suggestion] #[must_use = "this returns the result of the operation, \ @@ -2278,10 +2278,9 @@ impl Path { /// Produces an iterator over `Path` and its ancestors. /// /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero - /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`, - /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns - /// [`None`], the iterator will do likewise. The iterator will always yield at least one value, - /// namely `&self`. + /// or more times. If the [`parent`] method returns [`None`], the iterator will do likewise. + /// The iterator will always yield at least one value, namely `Some(&self)`. Next it will yield + /// `&self.parent()`, `&self.parent().and_then(Path::parent)` and so on. /// /// # Examples /// diff --git a/library/std/src/process.rs b/library/std/src/process.rs index b84d5f11954..69cc61b30ef 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -88,6 +88,47 @@ //! assert_eq!(b"test", output.stdout.as_slice()); //! ``` //! +//! # Windows argument splitting +//! +//! On Unix systems arguments are passed to a new process as an array of strings +//! but on Windows arguments are passed as a single commandline string and it's +//! up to the child process to parse it into an array. Therefore the parent and +//! child processes must agree on how the commandline string is encoded. +//! +//! Most programs use the standard C run-time `argv`, which in practice results +//! in consistent argument handling. However some programs have their own way of +//! parsing the commandline string. In these cases using [`arg`] or [`args`] may +//! result in the child process seeing a different array of arguments then the +//! parent process intended. +//! +//! Two ways of mitigating this are: +//! +//! * Validate untrusted input so that only a safe subset is allowed. +//! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping +//! rules used by [`arg`] so should be used with due caution. +//! +//! `cmd.exe` and `.bat` use non-standard argument parsing and are especially +//! vulnerable to malicious input as they may be used to run arbitrary shell +//! commands. Untrusted arguments should be restricted as much as possible. +//! For examples on handling this see [`raw_arg`]. +//! +//! ### Bat file special handling +//! +//! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to +//! spawn new processes. An undocumented feature of this function is that, +//! when given a `.bat` file as the application to run, it will automatically +//! convert that into running `cmd.exe /c` with the bat file as the next argument. +//! +//! For historical reasons Rust currently preserves this behaviour when using +//! [`Command::new`], and escapes the arguments according to `cmd.exe` rules. +//! Due to the complexity of `cmd.exe` argument handling, it might not be +//! possible to safely escape some special chars, and using them will result +//! in an error being returned at process spawn. The set of unescapeable +//! special chars might change between releases. +//! +//! Also note that running `.bat` scripts in this way may be removed in the +//! future and so should not be relied upon. +//! //! [`spawn`]: Command::spawn //! [`output`]: Command::output //! @@ -97,6 +138,12 @@ //! //! [`Write`]: io::Write //! [`Read`]: io::Read +//! +//! [`arg`]: Command::arg +//! [`args`]: Command::args +//! [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg +//! +//! [`CreateProcessW`]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw #![stable(feature = "process", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] @@ -611,6 +658,22 @@ impl Command { /// escaped characters, word splitting, glob patterns, variable substitution, etc. /// have no effect. /// + /// <div class="warning"> + /// + /// On Windows use caution with untrusted inputs. Most applications use the + /// standard convention for decoding arguments passed to them. These are safe to use with `arg`. + /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments + /// and are therefore vulnerable to malicious input. + /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands. + /// + /// See [Windows argument splitting][windows-args] for more details + /// or [`raw_arg`] for manually implementing non-standard argument encoding. + /// + /// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg + /// [windows-args]: crate::process#windows-argument-splitting + /// + /// </div> + /// /// # Examples /// /// Basic usage: @@ -641,6 +704,22 @@ impl Command { /// escaped characters, word splitting, glob patterns, variable substitution, etc. /// have no effect. /// + /// <div class="warning"> + /// + /// On Windows use caution with untrusted inputs. Most applications use the + /// standard convention for decoding arguments passed to them. These are safe to use with `args`. + /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments + /// and are therefore vulnerable to malicious input. + /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands. + /// + /// See [Windows argument splitting][windows-args] for more details + /// or [`raw_arg`] for manually implementing non-standard argument encoding. + /// + /// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg + /// [windows-args]: crate::process#windows-argument-splitting + /// + /// </div> + /// /// # Examples /// /// Basic usage: diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 6d068613f8f..fc830bacced 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -252,6 +252,46 @@ impl<T> OnceLock<T> { } } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. + /// + /// Many threads may call `get_mut_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell = OnceLock::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::<T, !>(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -303,6 +343,47 @@ impl<T> OnceLock<T> { Ok(unsafe { self.get_unchecked() }) } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell: OnceLock<u32> = OnceLock::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result<T, E>, + { + if self.get().is_none() { + self.initialize(f)?; + } + debug_assert!(self.is_initialized()); + // SAFETY: The inner value has been initialized + Ok(unsafe { self.get_unchecked_mut() }) + } + /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs index 5eb828fea1f..962577bb1ed 100644 --- a/library/std/src/sys/pal/hermit/fd.rs +++ b/library/std/src/sys/pal/hermit/fd.rs @@ -48,6 +48,11 @@ impl FileDesc { pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { unsupported() } + + pub fn fstat(&self, stat: *mut abi::stat) -> io::Result<()> { + cvt(unsafe { abi::fstat(self.fd.as_raw_fd(), stat) })?; + Ok(()) + } } impl<'a> Read for &'a FileDesc { diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index d4da53fd3df..6519cc22f1f 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -1,12 +1,17 @@ -use super::abi::{self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY}; +use super::abi::{ + self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, + O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, +}; use super::fd::FileDesc; -use crate::ffi::{CStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; -use crate::hash::{Hash, Hasher}; use crate::io::{self, Error, ErrorKind}; use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem; +use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; +use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::cvt; use crate::sys::time::SystemTime; @@ -14,16 +19,53 @@ use crate::sys::unsupported; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; pub use crate::sys_common::fs::{copy, try_exists}; -//pub use crate::sys_common::fs::remove_dir_all; #[derive(Debug)] pub struct File(FileDesc); +#[derive(Clone)] +pub struct FileAttr { + stat_val: stat_struct, +} -pub struct FileAttr(!); +impl FileAttr { + fn from_stat(stat_val: stat_struct) -> Self { + Self { stat_val } + } +} -pub struct ReadDir(!); +// all DirEntry's will have a reference to this struct +struct InnerReadDir { + root: PathBuf, + dir: Vec<u8>, +} -pub struct DirEntry(!); +impl InnerReadDir { + pub fn new(root: PathBuf, dir: Vec<u8>) -> Self { + Self { root, dir } + } +} + +pub struct ReadDir { + inner: Arc<InnerReadDir>, + pos: i64, +} + +impl ReadDir { + fn new(inner: InnerReadDir) -> Self { + Self { inner: Arc::new(inner), pos: 0 } + } +} + +pub struct DirEntry { + /// path to the entry + root: PathBuf, + /// 64-bit inode number + ino: u64, + /// File type + type_: u32, + /// name of the entry + name: OsString, +} #[derive(Clone, Debug)] pub struct OpenOptions { @@ -41,72 +83,87 @@ pub struct OpenOptions { #[derive(Copy, Clone, Debug, Default)] pub struct FileTimes {} -pub struct FilePermissions(!); - -pub struct FileType(!); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions { + mode: u32, +} -#[derive(Debug)] -pub struct DirBuilder {} +#[derive(Copy, Clone, Eq, Debug)] +pub struct FileType { + mode: u32, +} -impl FileAttr { - pub fn size(&self) -> u64 { - self.0 +impl PartialEq for FileType { + fn eq(&self, other: &Self) -> bool { + self.mode == other.mode } +} - pub fn perm(&self) -> FilePermissions { - self.0 +impl core::hash::Hash for FileType { + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + self.mode.hash(state); } +} - pub fn file_type(&self) -> FileType { - self.0 - } +#[derive(Debug)] +pub struct DirBuilder { + mode: u32, +} +impl FileAttr { pub fn modified(&self) -> io::Result<SystemTime> { - self.0 + Ok(SystemTime::new( + self.stat_val.st_mtime.try_into().unwrap(), + self.stat_val.st_mtime_nsec.try_into().unwrap(), + )) } pub fn accessed(&self) -> io::Result<SystemTime> { - self.0 + Ok(SystemTime::new( + self.stat_val.st_atime.try_into().unwrap(), + self.stat_val.st_atime_nsec.try_into().unwrap(), + )) } pub fn created(&self) -> io::Result<SystemTime> { - self.0 + Ok(SystemTime::new( + self.stat_val.st_ctime.try_into().unwrap(), + self.stat_val.st_ctime_nsec.try_into().unwrap(), + )) } -} -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - self.0 + pub fn size(&self) -> u64 { + self.stat_val.st_size as u64 } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - self.0 + pub fn perm(&self) -> FilePermissions { + FilePermissions { mode: (self.stat_val.st_mode) } } - pub fn set_readonly(&mut self, _readonly: bool) { - self.0 + pub fn file_type(&self) -> FileType { + let masked_mode = self.stat_val.st_mode & S_IFMT; + let mode = match masked_mode { + S_IFDIR => DT_DIR, + S_IFLNK => DT_LNK, + S_IFREG => DT_REG, + _ => DT_UNKNOWN, + }; + FileType { mode: mode } } } -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - self.0 +impl FilePermissions { + pub fn readonly(&self) -> bool { + // check if any class (owner, group, others) has write permission + self.mode & 0o222 == 0 } -} -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - self.0 + pub fn set_readonly(&mut self, _readonly: bool) { + unimplemented!() } -} - -impl Eq for FilePermissions {} -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + #[allow(dead_code)] + pub fn mode(&self) -> u32 { + self.mode as u32 } } @@ -117,49 +174,21 @@ impl FileTimes { impl FileType { pub fn is_dir(&self) -> bool { - self.0 + self.mode == DT_DIR } - pub fn is_file(&self) -> bool { - self.0 + self.mode == DT_REG } - pub fn is_symlink(&self) -> bool { - self.0 - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - self.0 - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - self.0 - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash<H: Hasher>(&self, _h: &mut H) { - self.0 - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + self.mode == DT_LNK } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e.g. 'ReadDir("/home")' + fmt::Debug::fmt(&*self.inner.root, f) } } @@ -167,25 +196,78 @@ impl Iterator for ReadDir { type Item = io::Result<DirEntry>; fn next(&mut self) -> Option<io::Result<DirEntry>> { - self.0 + let mut counter: usize = 0; + let mut offset: i64 = 0; + + // loop over all directory entries and search the entry for the current position + loop { + // leave function, if the loop reaches the of the buffer (with all entries) + if offset >= self.inner.dir.len().try_into().unwrap() { + return None; + } + + let dir = unsafe { + &*(self.inner.dir.as_ptr().offset(offset.try_into().unwrap()) as *const dirent64) + }; + + if counter == self.pos.try_into().unwrap() { + self.pos += 1; + + // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 + // plus the length of the file name. Consequently, file name has a size of d_reclen minus + // the size of dirent64. The file name is always a C string and terminated by `\0`. + // Consequently, we are able to ignore the last byte. + let name_bytes = unsafe { + core::slice::from_raw_parts( + &dir.d_name as *const _ as *const u8, + dir.d_reclen as usize - core::mem::size_of::<dirent64>() - 1, + ) + .to_vec() + }; + let entry = DirEntry { + root: self.inner.root.clone(), + ino: dir.d_ino, + type_: dir.d_type as u32, + name: OsString::from_vec(name_bytes), + }; + + return Some(Ok(entry)); + } + + counter += 1; + + // move to the next dirent64, which is directly stored after the previous one + offset = offset + dir.d_off; + } } } impl DirEntry { pub fn path(&self) -> PathBuf { - self.0 + self.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { - self.0 + self.file_name_os_str().to_os_string() } pub fn metadata(&self) -> io::Result<FileAttr> { - self.0 + let mut path = self.path(); + path.set_file_name(self.file_name_os_str()); + lstat(&path) } pub fn file_type(&self) -> io::Result<FileType> { - self.0 + Ok(FileType { mode: self.type_ as u32 }) + } + + #[allow(dead_code)] + pub fn ino(&self) -> u64 { + self.ino + } + + pub fn file_name_os_str(&self) -> &OsStr { + self.name.as_os_str() } } @@ -288,7 +370,9 @@ impl File { } pub fn file_attr(&self) -> io::Result<FileAttr> { - Err(Error::from_raw_os_error(22)) + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + self.0.fstat(&mut stat_val)?; + Ok(FileAttr::from_stat(stat_val)) } pub fn fsync(&self) -> io::Result<()> { @@ -357,11 +441,18 @@ impl File { impl DirBuilder { pub fn new() -> DirBuilder { - DirBuilder {} + DirBuilder { mode: 0o777 } } - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() + pub fn mkdir(&self, path: &Path) -> io::Result<()> { + run_path_with_cstr(path, &|path| { + cvt(unsafe { abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ()) + }) + } + + #[allow(dead_code)] + pub fn set_mode(&mut self, mode: u32) { + self.mode = mode as u32; } } @@ -416,8 +507,43 @@ impl FromRawFd for File { } } -pub fn readdir(_p: &Path) -> io::Result<ReadDir> { - unsupported() +pub fn readdir(path: &Path) -> io::Result<ReadDir> { + let fd_raw = run_path_with_cstr(path, &|path| cvt(unsafe { abi::opendir(path.as_ptr()) }))?; + let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; + let root = path.to_path_buf(); + + // read all director entries + let mut vec: Vec<u8> = Vec::new(); + let mut sz = 512; + loop { + // reserve memory to receive all directory entries + vec.resize(sz, 0); + + let readlen = + unsafe { abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) }; + if readlen > 0 { + // shrink down to the minimal size + vec.resize(readlen.try_into().unwrap(), 0); + break; + } + + // if the buffer is too small, getdents64 returns EINVAL + // otherwise, getdents64 returns an error number + if readlen != (-abi::errno::EINVAL).into() { + return Err(Error::from_raw_os_error(readlen.try_into().unwrap())); + } + + // we don't have enough memory => try to increase the vector size + sz = sz * 2; + + // 1 MB for directory entries should be enough + // stop here to avoid an endless loop + if sz > 0x100000 { + return Err(Error::from(ErrorKind::Uncategorized)); + } + } + + Ok(ReadDir::new(InnerReadDir::new(root, vec))) } pub fn unlink(path: &Path) -> io::Result<()> { @@ -428,17 +554,16 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { unsupported() } -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + Err(Error::from_raw_os_error(22)) } -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() +pub fn rmdir(path: &Path) -> io::Result<()> { + run_path_with_cstr(path, &|path| cvt(unsafe { abi::rmdir(path.as_ptr()) }).map(|_| ())) } pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - //unsupported() - Ok(()) + unsupported() } pub fn readlink(_p: &Path) -> io::Result<PathBuf> { @@ -453,12 +578,20 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { unsupported() } -pub fn stat(_p: &Path) -> io::Result<FileAttr> { - unsupported() +pub fn stat(path: &Path) -> io::Result<FileAttr> { + run_path_with_cstr(path, &|path| { + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + cvt(unsafe { abi::stat(path.as_ptr(), &mut stat_val) })?; + Ok(FileAttr::from_stat(stat_val)) + }) } -pub fn lstat(_p: &Path) -> io::Result<FileAttr> { - unsupported() +pub fn lstat(path: &Path) -> io::Result<FileAttr> { + run_path_with_cstr(path, &|path| { + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + cvt(unsafe { abi::lstat(path.as_ptr(), &mut stat_val) })?; + Ok(FileAttr::from_stat(stat_val)) + }) } pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 1c53796f5d4..23ac71cb9f2 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -80,10 +80,7 @@ impl Socket { let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let start = Instant::now(); @@ -245,10 +242,7 @@ impl Socket { let timeout = match dur { Some(dur) => { if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let secs = if dur.as_secs() > netc::time_t::MAX as u64 { diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 319b835a768..d6f9e4c1476 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -18,6 +18,12 @@ impl Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } + const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec { + assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64); + // SAFETY: The assert above checks tv_nsec is within the valid range + Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } } + } + fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { if self >= other { Ok(if self.t.tv_nsec >= other.t.tv_nsec { @@ -195,6 +201,10 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { + pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { + SystemTime(Timespec::new(tv_sec, tv_nsec)) + } + pub fn now() -> SystemTime { let mut time: Timespec = Timespec::zero(); let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) }; diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs index edb28e2300f..68a2d5eded2 100644 --- a/library/std/src/sys/pal/sgx/net.rs +++ b/library/std/src/sys/pal/sgx/net.rs @@ -97,10 +97,7 @@ impl TcpStream { pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> { if dur == Duration::default() { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } Self::connect(Ok(addr)) // FIXME: ignoring timeout } @@ -108,10 +105,7 @@ impl TcpStream { pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { match dur { Some(dur) if dur == Duration::default() => { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } _ => sgx_ineffective(()), } @@ -120,10 +114,7 @@ impl TcpStream { pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { match dur { Some(dur) if dur == Duration::default() => { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } _ => sgx_ineffective(()), } diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 109ee1a0ab6..3f6ff37903a 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -50,10 +50,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> { } pub fn unsupported_err() -> crate::io::Error { - crate::io::const_io_error!( - crate::io::ErrorKind::Unsupported, - "operation not supported on this platform", - ) + crate::io::Error::UNSUPPORTED_PLATFORM } #[inline] diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/pal/solid/net.rs index 6ea874e509e..5bd339849e9 100644 --- a/library/std/src/sys/pal/solid/net.rs +++ b/library/std/src/sys/pal/solid/net.rs @@ -154,10 +154,7 @@ impl Socket { } if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let mut timeout = @@ -306,10 +303,7 @@ impl Socket { let timeout = match dur { Some(dur) => { if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let secs = if dur.as_secs() > netc::c_long::MAX as u64 { diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index ae2f58ca08e..f4723b2ea46 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -141,10 +141,7 @@ impl Drop for Thread { // Note: Both `sched_getaffinity` and `sysconf` are available but not functional on // teeos, so this function always returns an Error! pub fn available_parallelism() -> io::Result<NonZero<usize>> { - Err(io::Error::new( - io::ErrorKind::NotFound, - "The number of hardware threads is not known for the target platform", - )) + Err(io::Error::UNKNOWN_THREAD_COUNT) } fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 96f64051cda..3456155509e 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1,10 +1,13 @@ // miri has some special hacks here that make things unused. #![cfg_attr(miri, allow(unused))] +#[cfg(test)] +mod tests; + use crate::os::unix::prelude::*; use crate::ffi::{CStr, OsStr, OsString}; -use crate::fmt; +use crate::fmt::{self, Write as _}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; @@ -195,20 +198,17 @@ cfg_has_statx! {{ return Some(Err(err)); } - // Availability not checked yet. + // `ENOSYS` might come from a faulty FUSE driver. // - // First try the cheap way. - if err.raw_os_error() == Some(libc::ENOSYS) { - STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed); - return None; - } - - // Error other than `ENOSYS` is not a good enough indicator -- it is + // Other errors are not a good enough indicator either -- it is // known that `EPERM` can be returned as a result of using seccomp to // block the syscall. + // // Availability is checked by performing a call which expects `EFAULT` // if the syscall is usable. + // // See: https://github.com/rust-lang/rust/issues/65662 + // // FIXME this can probably just do the call if `EPERM` was received, but // previous iteration of the code checked it for all errors and for now // this is retained. @@ -356,7 +356,7 @@ pub struct DirEntry { entry: dirent64, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct OpenOptions { // generic read: bool, @@ -370,7 +370,7 @@ pub struct OpenOptions { mode: mode_t, } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq)] pub struct FilePermissions { mode: mode_t, } @@ -389,7 +389,7 @@ pub struct FileTimes { created: Option<SystemTime>, } -#[derive(Copy, Clone, Eq, Debug)] +#[derive(Copy, Clone, Eq)] pub struct FileType { mode: mode_t, } @@ -406,11 +406,13 @@ impl core::hash::Hash for FileType { } } -#[derive(Debug)] pub struct DirBuilder { mode: mode_t, } +#[derive(Copy, Clone)] +struct Mode(mode_t); + cfg_has_statx! {{ impl FileAttr { fn from_stat64(stat: stat64) -> Self { @@ -689,12 +691,26 @@ impl FileType { } } +impl fmt::Debug for FileType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let FileType { mode } = self; + f.debug_struct("FileType").field("mode", &Mode(*mode)).finish() + } +} + impl FromInner<u32> for FilePermissions { fn from_inner(mode: u32) -> FilePermissions { FilePermissions { mode: mode as mode_t } } } +impl fmt::Debug for FilePermissions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let FilePermissions { mode } = self; + f.debug_struct("FilePermissions").field("mode", &Mode(*mode)).finish() + } +} + impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. @@ -1135,6 +1151,23 @@ impl OpenOptions { } } +impl fmt::Debug for OpenOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let OpenOptions { read, write, append, truncate, create, create_new, custom_flags, mode } = + self; + f.debug_struct("OpenOptions") + .field("read", read) + .field("write", write) + .field("append", append) + .field("truncate", truncate) + .field("create", create) + .field("create_new", create_new) + .field("custom_flags", custom_flags) + .field("mode", &Mode(*mode)) + .finish() + } +} + impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { run_path_with_cstr(path, &|path| File::open_c(path, opts)) @@ -1425,6 +1458,13 @@ impl DirBuilder { } } +impl fmt::Debug for DirBuilder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let DirBuilder { mode } = self; + f.debug_struct("DirBuilder").field("mode", &Mode(*mode)).finish() + } +} + impl AsInner<FileDesc> for File { #[inline] fn as_inner(&self) -> &FileDesc { @@ -1597,6 +1637,73 @@ impl fmt::Debug for File { } } +// Format in octal, followed by the mode format used in `ls -l`. +// +// References: +// https://pubs.opengroup.org/onlinepubs/009696899/utilities/ls.html +// https://www.gnu.org/software/libc/manual/html_node/Testing-File-Type.html +// https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html +// +// Example: +// 0o100664 (-rw-rw-r--) +impl fmt::Debug for Mode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(mode) = *self; + write!(f, "0o{mode:06o}")?; + + let entry_type = match mode & libc::S_IFMT { + libc::S_IFDIR => 'd', + libc::S_IFBLK => 'b', + libc::S_IFCHR => 'c', + libc::S_IFLNK => 'l', + libc::S_IFIFO => 'p', + libc::S_IFREG => '-', + _ => return Ok(()), + }; + + f.write_str(" (")?; + f.write_char(entry_type)?; + + // Owner permissions + f.write_char(if mode & libc::S_IRUSR != 0 { 'r' } else { '-' })?; + f.write_char(if mode & libc::S_IWUSR != 0 { 'w' } else { '-' })?; + let owner_executable = mode & libc::S_IXUSR != 0; + let setuid = mode as c_int & libc::S_ISUID as c_int != 0; + f.write_char(match (owner_executable, setuid) { + (true, true) => 's', // executable and setuid + (false, true) => 'S', // setuid + (true, false) => 'x', // executable + (false, false) => '-', + })?; + + // Group permissions + f.write_char(if mode & libc::S_IRGRP != 0 { 'r' } else { '-' })?; + f.write_char(if mode & libc::S_IWGRP != 0 { 'w' } else { '-' })?; + let group_executable = mode & libc::S_IXGRP != 0; + let setgid = mode as c_int & libc::S_ISGID as c_int != 0; + f.write_char(match (group_executable, setgid) { + (true, true) => 's', // executable and setgid + (false, true) => 'S', // setgid + (true, false) => 'x', // executable + (false, false) => '-', + })?; + + // Other permissions + f.write_char(if mode & libc::S_IROTH != 0 { 'r' } else { '-' })?; + f.write_char(if mode & libc::S_IWOTH != 0 { 'w' } else { '-' })?; + let other_executable = mode & libc::S_IXOTH != 0; + let sticky = mode as c_int & libc::S_ISVTX as c_int != 0; + f.write_char(match (entry_type, other_executable, sticky) { + ('d', true, true) => 't', // searchable and restricted deletion + ('d', false, true) => 'T', // restricted deletion + (_, true, _) => 'x', // executable + (_, false, _) => '-', + })?; + + f.write_char(')') + } +} + pub fn readdir(path: &Path) -> io::Result<ReadDir> { let ptr = run_path_with_cstr(path, &|p| unsafe { Ok(libc::opendir(p.as_ptr())) })?; if ptr.is_null() { @@ -1847,39 +1954,9 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { use crate::sync::atomic::{AtomicBool, Ordering}; - const COPYFILE_ACL: u32 = 1 << 0; - const COPYFILE_STAT: u32 = 1 << 1; - const COPYFILE_XATTR: u32 = 1 << 2; - const COPYFILE_DATA: u32 = 1 << 3; - - const COPYFILE_SECURITY: u32 = COPYFILE_STAT | COPYFILE_ACL; - const COPYFILE_METADATA: u32 = COPYFILE_SECURITY | COPYFILE_XATTR; - const COPYFILE_ALL: u32 = COPYFILE_METADATA | COPYFILE_DATA; - - const COPYFILE_STATE_COPIED: u32 = 8; - - #[allow(non_camel_case_types)] - type copyfile_state_t = *mut libc::c_void; - #[allow(non_camel_case_types)] - type copyfile_flags_t = u32; - - extern "C" { - fn fcopyfile( - from: libc::c_int, - to: libc::c_int, - state: copyfile_state_t, - flags: copyfile_flags_t, - ) -> libc::c_int; - fn copyfile_state_alloc() -> copyfile_state_t; - fn copyfile_state_free(state: copyfile_state_t) -> libc::c_int; - fn copyfile_state_get( - state: copyfile_state_t, - flag: u32, - dst: *mut libc::c_void, - ) -> libc::c_int; - } - - struct FreeOnDrop(copyfile_state_t); + const COPYFILE_ALL: libc::copyfile_flags_t = libc::COPYFILE_METADATA | libc::COPYFILE_DATA; + + struct FreeOnDrop(libc::copyfile_state_t); impl Drop for FreeOnDrop { fn drop(&mut self) { // The code below ensures that `FreeOnDrop` is never a null pointer @@ -1887,7 +1964,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // `copyfile_state_free` returns -1 if the `to` or `from` files // cannot be closed. However, this is not considered this an // error. - copyfile_state_free(self.0); + libc::copyfile_state_free(self.0); } } } @@ -1896,6 +1973,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // We store the availability in a global to avoid unnecessary syscalls static HAS_FCLONEFILEAT: AtomicBool = AtomicBool::new(true); syscall! { + // Mirrors `libc::fclonefileat` fn fclonefileat( srcfd: libc::c_int, dst_dirfd: libc::c_int, @@ -1932,22 +2010,22 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // We ensure that `FreeOnDrop` never contains a null pointer so it is // always safe to call `copyfile_state_free` let state = unsafe { - let state = copyfile_state_alloc(); + let state = libc::copyfile_state_alloc(); if state.is_null() { return Err(crate::io::Error::last_os_error()); } FreeOnDrop(state) }; - let flags = if writer_metadata.is_file() { COPYFILE_ALL } else { COPYFILE_DATA }; + let flags = if writer_metadata.is_file() { COPYFILE_ALL } else { libc::COPYFILE_DATA }; - cvt(unsafe { fcopyfile(reader.as_raw_fd(), writer.as_raw_fd(), state.0, flags) })?; + cvt(unsafe { libc::fcopyfile(reader.as_raw_fd(), writer.as_raw_fd(), state.0, flags) })?; let mut bytes_copied: libc::off_t = 0; cvt(unsafe { - copyfile_state_get( + libc::copyfile_state_get( state.0, - COPYFILE_STATE_COPIED, + libc::COPYFILE_STATE_COPIED as u32, core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void, ) })?; diff --git a/library/std/src/sys/pal/unix/fs/tests.rs b/library/std/src/sys/pal/unix/fs/tests.rs new file mode 100644 index 00000000000..71be3472148 --- /dev/null +++ b/library/std/src/sys/pal/unix/fs/tests.rs @@ -0,0 +1,71 @@ +use crate::sys::pal::unix::fs::FilePermissions; + +#[test] +fn test_debug_permissions() { + for (expected, mode) in [ + // typical directory + ("FilePermissions { mode: 0o040775 (drwxrwxr-x) }", 0o04_0775), + // typical text file + ("FilePermissions { mode: 0o100664 (-rw-rw-r--) }", 0o10_0664), + // setuid executable (/usr/bin/doas) + ("FilePermissions { mode: 0o104755 (-rwsr-xr-x) }", 0o10_4755), + // char device (/dev/zero) + ("FilePermissions { mode: 0o020666 (crw-rw-rw-) }", 0o02_0666), + // block device (/dev/vda) + ("FilePermissions { mode: 0o060660 (brw-rw----) }", 0o06_0660), + // symbolic link + ("FilePermissions { mode: 0o120777 (lrwxrwxrwx) }", 0o12_0777), + // fifo + ("FilePermissions { mode: 0o010664 (prw-rw-r--) }", 0o01_0664), + // none + ("FilePermissions { mode: 0o100000 (----------) }", 0o10_0000), + // unrecognized + ("FilePermissions { mode: 0o000001 }", 1), + ] { + assert_eq!(format!("{:?}", FilePermissions { mode }), expected); + } + + for (expected, mode) in [ + // owner readable + ("FilePermissions { mode: 0o100400 (-r--------) }", libc::S_IRUSR), + // owner writable + ("FilePermissions { mode: 0o100200 (--w-------) }", libc::S_IWUSR), + // owner executable + ("FilePermissions { mode: 0o100100 (---x------) }", libc::S_IXUSR), + // setuid + ("FilePermissions { mode: 0o104000 (---S------) }", libc::S_ISUID), + // owner executable and setuid + ("FilePermissions { mode: 0o104100 (---s------) }", libc::S_IXUSR | libc::S_ISUID), + // group readable + ("FilePermissions { mode: 0o100040 (----r-----) }", libc::S_IRGRP), + // group writable + ("FilePermissions { mode: 0o100020 (-----w----) }", libc::S_IWGRP), + // group executable + ("FilePermissions { mode: 0o100010 (------x---) }", libc::S_IXGRP), + // setgid + ("FilePermissions { mode: 0o102000 (------S---) }", libc::S_ISGID), + // group executable and setgid + ("FilePermissions { mode: 0o102010 (------s---) }", libc::S_IXGRP | libc::S_ISGID), + // other readable + ("FilePermissions { mode: 0o100004 (-------r--) }", libc::S_IROTH), + // other writeable + ("FilePermissions { mode: 0o100002 (--------w-) }", libc::S_IWOTH), + // other executable + ("FilePermissions { mode: 0o100001 (---------x) }", libc::S_IXOTH), + // sticky + ("FilePermissions { mode: 0o101000 (----------) }", libc::S_ISVTX), + // other executable and sticky + ("FilePermissions { mode: 0o101001 (---------x) }", libc::S_IXOTH | libc::S_ISVTX), + ] { + assert_eq!(format!("{:?}", FilePermissions { mode: libc::S_IFREG | mode }), expected); + } + + for (expected, mode) in [ + // restricted deletion ("sticky") flag is set, and search permission is not granted to others + ("FilePermissions { mode: 0o041000 (d--------T) }", libc::S_ISVTX), + // sticky and searchable + ("FilePermissions { mode: 0o041001 (d--------t) }", libc::S_ISVTX | libc::S_IXOTH), + ] { + assert_eq!(format!("{:?}", FilePermissions { mode: libc::S_IFDIR | mode }), expected); + } +} diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 4ae76518c4f..3ef43a923a3 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -433,6 +433,6 @@ mod unsupported { } pub fn unsupported_err() -> io::Error { - io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",) + io::Error::UNSUPPORTED_PLATFORM } } diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 9a0a1b18aee..7237989c905 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -175,10 +175,7 @@ impl Socket { let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let start = Instant::now(); @@ -360,10 +357,7 @@ impl Socket { let timeout = match dur { Some(dur) => { if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let secs = if dur.as_secs() > libc::time_t::MAX as u64 { diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index f56e64c3505..6a6bfc77a85 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -356,7 +356,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { } match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { -1 => Err(io::Error::last_os_error()), - 0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")), + 0 => Err(io::Error::UNKNOWN_THREAD_COUNT), cpus => { let count = cpus as usize; // Cover the unusual situation where we were able to get the quota but not the affinity mask @@ -439,7 +439,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { if res == -1 { return Err(io::Error::last_os_error()); } else if cpus == 0 { - return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")); + return Err(io::Error::UNKNOWN_THREAD_COUNT); } } @@ -452,13 +452,13 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { } else { let cpus = (*_syspage_ptr).num_cpu; NonZero::new(cpus as usize) - .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")) + .ok_or(io::Error::UNKNOWN_THREAD_COUNT) } } } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { let mut cpus = 0u32; if unsafe { libc::pset_info(libc::PS_MYID, core::ptr::null_mut(), &mut cpus, core::ptr::null_mut()) } != 0 { - return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")); + return Err(io::Error::UNKNOWN_THREAD_COUNT); } Ok(unsafe { NonZero::new_unchecked(cpus as usize) }) } else if #[cfg(target_os = "haiku")] { @@ -469,7 +469,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { let res = libc::get_system_info(&mut sinfo); if res != libc::B_OK { - return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")); + return Err(io::Error::UNKNOWN_THREAD_COUNT); } Ok(NonZero::new_unchecked(sinfo.cpu_count as usize)) @@ -709,7 +709,7 @@ mod cgroups { // is created in an application with big thread-local storage requirements. // See #6233 for rationale and details. #[cfg(all(target_os = "linux", target_env = "gnu"))] -fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { +unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628) // We shouldn't really be using such an internal symbol, but there's currently // no other way to account for the TLS size. @@ -723,11 +723,11 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { // No point in looking up __pthread_get_minstack() on non-glibc platforms. #[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))] -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { +unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { libc::PTHREAD_STACK_MIN } #[cfg(target_os = "netbsd")] -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { +unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { 2048 // just a guess } diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs index 4f44db610af..76f80291f0e 100644 --- a/library/std/src/sys/pal/unsupported/common.rs +++ b/library/std/src/sys/pal/unsupported/common.rs @@ -13,10 +13,7 @@ pub fn unsupported<T>() -> std_io::Result<T> { } pub fn unsupported_err() -> std_io::Error { - std_io::const_io_error!( - std_io::ErrorKind::Unsupported, - "operation not supported on this platform", - ) + std_io::Error::UNSUPPORTED_PLATFORM } pub fn is_interrupted(_code: i32) -> bool { diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/pal/unsupported/process.rs index 6a989dd3e76..2445d9073db 100644 --- a/library/std/src/sys/pal/unsupported/process.rs +++ b/library/std/src/sys/pal/unsupported/process.rs @@ -1,7 +1,6 @@ -use crate::ffi::OsStr; +use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io; -use crate::marker::PhantomData; use crate::num::NonZero; use crate::path::Path; use crate::sys::fs::File; @@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// pub struct Command { + program: OsString, + args: Vec<OsString>, env: CommandEnv, + + cwd: Option<OsString>, + stdin: Option<Stdio>, + stdout: Option<Stdio>, + stderr: Option<Stdio>, } // passed back to std::process with the pipes connected to the child, if any @@ -27,39 +33,62 @@ pub struct StdioPipes { pub stderr: Option<AnonPipe>, } -// FIXME: This should be a unit struct, so we can always construct it -// The value here should be never used, since we cannot spawn processes. +#[derive(Debug)] pub enum Stdio { Inherit, Null, MakePipe, + ParentStdout, + ParentStderr, + #[allow(dead_code)] // This variant exists only for the Debug impl + InheritFile(File), } impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } + pub fn new(program: &OsStr) -> Command { + Command { + program: program.to_owned(), + args: vec![program.to_owned()], + env: Default::default(), + cwd: None, + stdin: None, + stdout: None, + stderr: None, + } } - pub fn arg(&mut self, _arg: &OsStr) {} + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_owned()); + } pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } - pub fn cwd(&mut self, _dir: &OsStr) {} + pub fn cwd(&mut self, dir: &OsStr) { + self.cwd = Some(dir.to_owned()); + } - pub fn stdin(&mut self, _stdin: Stdio) {} + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); + } - pub fn stdout(&mut self, _stdout: Stdio) {} + pub fn stdout(&mut self, stdout: Stdio) { + self.stdout = Some(stdout); + } - pub fn stderr(&mut self, _stderr: Stdio) {} + pub fn stderr(&mut self, stderr: Stdio) { + self.stderr = Some(stderr); + } pub fn get_program(&self) -> &OsStr { - panic!("unsupported") + &self.program } pub fn get_args(&self) -> CommandArgs<'_> { - CommandArgs { _p: PhantomData } + let mut iter = self.args.iter(); + iter.next(); + CommandArgs { iter } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -67,7 +96,7 @@ impl Command { } pub fn get_current_dir(&self) -> Option<&Path> { - None + self.cwd.as_ref().map(|cs| Path::new(cs)) } pub fn spawn( @@ -91,31 +120,83 @@ impl From<AnonPipe> for Stdio { impl From<io::Stdout> for Stdio { fn from(_: io::Stdout) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + Stdio::ParentStdout } } impl From<io::Stderr> for Stdio { fn from(_: io::Stderr) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + Stdio::ParentStderr } } impl From<File> for Stdio { - fn from(_file: File) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + fn from(file: File) -> Stdio { + Stdio::InheritFile(file) } } impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) + // show all attributes + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + let mut debug_command = f.debug_struct("Command"); + debug_command.field("program", &self.program).field("args", &self.args); + if !self.env.is_unchanged() { + debug_command.field("env", &self.env); + } + + if self.cwd.is_some() { + debug_command.field("cwd", &self.cwd); + } + + if self.stdin.is_some() { + debug_command.field("stdin", &self.stdin); + } + if self.stdout.is_some() { + debug_command.field("stdout", &self.stdout); + } + if self.stderr.is_some() { + debug_command.field("stderr", &self.stderr); + } + + debug_command.finish() + } else { + if let Some(ref cwd) = self.cwd { + write!(f, "cd {cwd:?} && ")?; + } + if self.env.does_clear() { + write!(f, "env -i ")?; + // Altered env vars will be printed next, that should exactly work as expected. + } else { + // Removed env vars need the command to be wrapped in `env`. + let mut any_removed = false; + for (key, value_opt) in self.get_envs() { + if value_opt.is_none() { + if !any_removed { + write!(f, "env ")?; + any_removed = true; + } + write!(f, "-u {} ", key.to_string_lossy())?; + } + } + } + // Altered env vars can just be added in front of the program. + for (key, value_opt) in self.get_envs() { + if let Some(value) = value_opt { + write!(f, "{}={value:?} ", key.to_string_lossy())?; + } + } + if self.program != self.args[0] { + write!(f, "[{:?}] ", self.program)?; + } + write!(f, "{:?}", self.args[0])?; + + for arg in &self.args[1..] { + write!(f, " {:?}", arg)?; + } + Ok(()) + } } } @@ -217,23 +298,30 @@ impl Process { } pub struct CommandArgs<'a> { - _p: PhantomData<&'a ()>, + iter: crate::slice::Iter<'a, OsString>, } impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; fn next(&mut self) -> Option<&'a OsStr> { - None + self.iter.next().map(|os| &**os) } fn size_hint(&self) -> (usize, Option<usize>) { - (0, Some(0)) + self.iter.size_hint() } } -impl<'a> ExactSizeIterator for CommandArgs<'a> {} +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} impl<'a> fmt::Debug for CommandArgs<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().finish() + f.debug_list().entries(self.iter.clone()).finish() } } diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 90e1bff52a3..555ad581b85 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -34,6 +34,102 @@ use core::ptr::addr_of; use super::c; +/// Creates a null-terminated UTF-16 string from a str. +pub macro wide_str($str:literal) {{ + const _: () = { + if core::slice::memchr::memchr(0, $str.as_bytes()).is_some() { + panic!("null terminated strings cannot contain interior nulls"); + } + }; + crate::sys::pal::windows::api::utf16!(concat!($str, '\0')) +}} + +/// Creates a UTF-16 string from a str without null termination. +pub macro utf16($str:expr) {{ + const UTF8: &str = $str; + const UTF16_LEN: usize = crate::sys::pal::windows::api::utf16_len(UTF8); + const UTF16: [u16; UTF16_LEN] = crate::sys::pal::windows::api::to_utf16(UTF8); + &UTF16 +}} + +#[cfg(test)] +mod tests; + +/// Gets the UTF-16 length of a UTF-8 string, for use in the wide_str macro. +pub const fn utf16_len(s: &str) -> usize { + let s = s.as_bytes(); + let mut i = 0; + let mut len = 0; + while i < s.len() { + // the length of a UTF-8 encoded code-point is given by the number of + // leading ones, except in the case of ASCII. + let utf8_len = match s[i].leading_ones() { + 0 => 1, + n => n as usize, + }; + i += utf8_len; + // Note that UTF-16 surrogates (U+D800 to U+DFFF) are not encodable as UTF-8, + // so (unlike with WTF-8) we don't have to worry about how they'll get re-encoded. + len += if utf8_len < 4 { 1 } else { 2 }; + } + len +} + +/// Const convert UTF-8 to UTF-16, for use in the wide_str macro. +/// +/// Note that this is designed for use in const contexts so is not optimized. +pub const fn to_utf16<const UTF16_LEN: usize>(s: &str) -> [u16; UTF16_LEN] { + let mut output = [0_u16; UTF16_LEN]; + let mut pos = 0; + let s = s.as_bytes(); + let mut i = 0; + while i < s.len() { + match s[i].leading_ones() { + // Decode UTF-8 based on its length. + // See https://en.wikipedia.org/wiki/UTF-8 + 0 => { + // ASCII is the same in both encodings + output[pos] = s[i] as u16; + i += 1; + pos += 1; + } + 2 => { + // Bits: 110xxxxx 10xxxxxx + output[pos] = ((s[i] as u16 & 0b11111) << 6) | (s[i + 1] as u16 & 0b111111); + i += 2; + pos += 1; + } + 3 => { + // Bits: 1110xxxx 10xxxxxx 10xxxxxx + output[pos] = ((s[i] as u16 & 0b1111) << 12) + | ((s[i + 1] as u16 & 0b111111) << 6) + | (s[i + 2] as u16 & 0b111111); + i += 3; + pos += 1; + } + 4 => { + // Bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + let mut c = ((s[i] as u32 & 0b111) << 18) + | ((s[i + 1] as u32 & 0b111111) << 12) + | ((s[i + 2] as u32 & 0b111111) << 6) + | (s[i + 3] as u32 & 0b111111); + // re-encode as UTF-16 (see https://en.wikipedia.org/wiki/UTF-16) + // - Subtract 0x10000 from the code point + // - For the high surrogate, shift right by 10 then add 0xD800 + // - For the low surrogate, take the low 10 bits then add 0xDC00 + c -= 0x10000; + output[pos] = ((c >> 10) + 0xD800) as u16; + output[pos + 1] = ((c & 0b1111111111) + 0xDC00) as u16; + i += 4; + pos += 2; + } + // valid UTF-8 cannot have any other values + _ => unreachable!(), + } + } + output +} + /// Helper method for getting the size of `T` as a u32. /// Errors at compile time if the size would overflow. /// diff --git a/library/std/src/sys/pal/windows/api/tests.rs b/library/std/src/sys/pal/windows/api/tests.rs new file mode 100644 index 00000000000..fab022c7b93 --- /dev/null +++ b/library/std/src/sys/pal/windows/api/tests.rs @@ -0,0 +1,16 @@ +use crate::sys::pal::windows::api::{utf16, wide_str}; + +macro_rules! check_utf16 { + ($str:literal) => {{ + assert!(wide_str!($str).iter().copied().eq($str.encode_utf16().chain([0]))); + assert!(utf16!($str).iter().copied().eq($str.encode_utf16())); + }}; +} + +#[test] +fn test_utf16_macros() { + check_utf16!("hello world"); + check_utf16!("€4.50"); + check_utf16!("𨉟呐㗂越"); + check_utf16!("Pchnąć w tę łódź jeża lub ośm skrzyń fig"); +} diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs index 2ecfe088d10..5098c05196e 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/pal/windows/args.rs @@ -7,7 +7,7 @@ mod tests; use super::os::current_exe; -use crate::ffi::OsString; +use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io; use crate::num::NonZero; @@ -17,6 +17,7 @@ use crate::sys::path::get_long_path; use crate::sys::process::ensure_no_nuls; use crate::sys::{c, to_u16s}; use crate::sys_common::wstr::WStrUnits; +use crate::sys_common::AsInner; use crate::vec; use crate::iter; @@ -262,16 +263,92 @@ pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> i Ok(()) } +fn append_bat_arg(cmd: &mut Vec<u16>, arg: &OsStr, mut quote: bool) -> io::Result<()> { + ensure_no_nuls(arg)?; + // If an argument has 0 characters then we need to quote it to ensure + // that it actually gets passed through on the command line or otherwise + // it will be dropped entirely when parsed on the other end. + // + // We also need to quote the argument if it ends with `\` to guard against + // bat usage such as `"%~2"` (i.e. force quote arguments) otherwise a + // trailing slash will escape the closing quote. + if arg.is_empty() || arg.as_encoded_bytes().last() == Some(&b'\\') { + quote = true; + } + for cp in arg.as_inner().inner.code_points() { + if let Some(cp) = cp.to_char() { + // Rather than trying to find every ascii symbol that must be quoted, + // we assume that all ascii symbols must be quoted unless they're known to be good. + // We also quote Unicode control blocks for good measure. + // Note an unquoted `\` is fine so long as the argument isn't otherwise quoted. + static UNQUOTED: &str = r"#$*+-./:?@\_"; + let ascii_needs_quotes = + cp.is_ascii() && !(cp.is_ascii_alphanumeric() || UNQUOTED.contains(cp)); + if ascii_needs_quotes || cp.is_control() { + quote = true; + } + } + } + + if quote { + cmd.push('"' as u16); + } + // Loop through the string, escaping `\` only if followed by `"`. + // And escaping `"` by doubling them. + let mut backslashes: usize = 0; + for x in arg.encode_wide() { + if x == '\\' as u16 { + backslashes += 1; + } else { + if x == '"' as u16 { + // Add n backslashes to total 2n before internal `"`. + cmd.extend((0..backslashes).map(|_| '\\' as u16)); + // Appending an additional double-quote acts as an escape. + cmd.push(b'"' as u16) + } else if x == '%' as u16 || x == '\r' as u16 { + // yt-dlp hack: replaces `%` with `%%cd:~,%` to stop %VAR% being expanded as an environment variable. + // + // # Explanation + // + // cmd supports extracting a substring from a variable using the following syntax: + // %variable:~start_index,end_index% + // + // In the above command `cd` is used as the variable and the start_index and end_index are left blank. + // `cd` is a built-in variable that dynamically expands to the current directory so it's always available. + // Explicitly omitting both the start and end index creates a zero-length substring. + // + // Therefore it all resolves to nothing. However, by doing this no-op we distract cmd.exe + // from potentially expanding %variables% in the argument. + cmd.extend_from_slice(&[ + '%' as u16, '%' as u16, 'c' as u16, 'd' as u16, ':' as u16, '~' as u16, + ',' as u16, + ]); + } + backslashes = 0; + } + cmd.push(x); + } + if quote { + // Add n backslashes to total 2n before ending `"`. + cmd.extend((0..backslashes).map(|_| '\\' as u16)); + cmd.push('"' as u16); + } + Ok(()) +} + pub(crate) fn make_bat_command_line( script: &[u16], args: &[Arg], force_quotes: bool, ) -> io::Result<Vec<u16>> { + const INVALID_ARGUMENT_ERROR: io::Error = + io::const_io_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); // Set the start of the command line to `cmd.exe /c "` // It is necessary to surround the command in an extra pair of quotes, // hence the trailing quote here. It will be closed after all arguments // have been added. - let mut cmd: Vec<u16> = "cmd.exe /d /c \"".encode_utf16().collect(); + // Using /e:ON enables "command extensions" which is essential for the `%` hack to work. + let mut cmd: Vec<u16> = "cmd.exe /e:ON /v:OFF /d /c \"".encode_utf16().collect(); // Push the script name surrounded by its quote pair. cmd.push(b'"' as u16); @@ -291,18 +368,22 @@ pub(crate) fn make_bat_command_line( // reconstructed by the batch script by default. for arg in args { cmd.push(' ' as u16); - // Make sure to always quote special command prompt characters, including: - // * Characters `cmd /?` says require quotes. - // * `%` for environment variables, as in `%TMP%`. - // * `|<>` pipe/redirect characters. - const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>"; - let force_quotes = match arg { - Arg::Regular(arg) if !force_quotes => { - arg.as_encoded_bytes().iter().any(|c| SPECIAL.contains(c)) + match arg { + Arg::Regular(arg_os) => { + let arg_bytes = arg_os.as_encoded_bytes(); + // Disallow \r and \n as they may truncate the arguments. + const DISALLOWED: &[u8] = b"\r\n"; + if arg_bytes.iter().any(|c| DISALLOWED.contains(c)) { + return Err(INVALID_ARGUMENT_ERROR); + } + append_bat_arg(&mut cmd, arg_os, force_quotes)?; + } + _ => { + // Raw arguments are passed on as-is. + // It's the user's responsibility to properly handle arguments in this case. + append_arg(&mut cmd, arg, force_quotes)?; } - _ => force_quotes, }; - append_arg(&mut cmd, arg, force_quotes)?; } // Close the quote we left opened earlier. diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 6a561518fad..a734c2bd4c7 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -5,6 +5,7 @@ use crate::io::ErrorKind; use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::path::PathBuf; +use crate::sys::pal::windows::api::wide_str; use crate::time::Duration; pub use self::rand::hashmap_random_keys; @@ -12,6 +13,8 @@ pub use self::rand::hashmap_random_keys; #[macro_use] pub mod compat; +mod api; + pub mod alloc; pub mod args; pub mod c; @@ -41,8 +44,6 @@ cfg_if::cfg_if! { } } -mod api; - /// Map a Result<T, WinError> to io::Result<T>. trait IoResult<T> { fn io_result(self) -> crate::io::Result<T>; @@ -60,7 +61,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already // exists, we have to call it ourselves. - thread::Thread::set_name(&c"main"); + thread::Thread::set_name_wide(wide_str!("main")); } // SAFETY: must be called only once during runtime cleanup. diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index 1e6169ea8ec..9e15b15a351 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -154,10 +154,7 @@ impl Socket { match result { Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => { if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } let mut timeout = c::timeval { @@ -364,10 +361,7 @@ impl Socket { Some(dur) => { let timeout = sys::dur2timeout(dur); if timeout == 0 { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); + return Err(io::Error::ZERO_TIMEOUT); } timeout } diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index c0c63c3340f..70099e0a3b5 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -45,13 +45,11 @@ impl Thread { Err(io::Error::last_os_error()) }; - extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { - unsafe { - // Next, reserve some stack space for if we otherwise run out of stack. - stack_overflow::reserve_stack(); - // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnOnce()>)(); - } + unsafe extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { + // Next, reserve some stack space for if we otherwise run out of stack. + stack_overflow::reserve_stack(); + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); 0 } } @@ -60,12 +58,20 @@ impl Thread { if let Ok(utf8) = name.to_str() { if let Ok(utf16) = to_u16s(utf8) { unsafe { - c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); - }; + // SAFETY: the vec returned by `to_u16s` ends with a zero value + Self::set_name_wide(&utf16) + } }; }; } + /// # Safety + /// + /// `name` must end with a zero value + pub unsafe fn set_name_wide(name: &[u16]) { + c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()); + } + pub fn join(self) { let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; if rc == c::WAIT_FAILED { @@ -112,10 +118,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { sysinfo.dwNumberOfProcessors as usize }; match res { - 0 => Err(io::const_io_error!( - io::ErrorKind::NotFound, - "The number of hardware threads is not known for the target platform", - )), + 0 => Err(io::Error::UNKNOWN_THREAD_COUNT), cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }), } } diff --git a/library/std/src/sys/pal/windows/thread_local_key.rs b/library/std/src/sys/pal/windows/thread_local_key.rs index 1d9cb316a45..4c00860dae3 100644 --- a/library/std/src/sys/pal/windows/thread_local_key.rs +++ b/library/std/src/sys/pal/windows/thread_local_key.rs @@ -276,6 +276,7 @@ unsafe fn register_dtor(key: &'static StaticKey) { // the address of the symbol to ensure it sticks around. #[link_section = ".CRT$XLB"] +#[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section` pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = on_tls_callback; diff --git a/library/std/src/sys/pal/xous/net/tcpstream.rs b/library/std/src/sys/pal/xous/net/tcpstream.rs index aebef02acda..0ad88110711 100644 --- a/library/std/src/sys/pal/xous/net/tcpstream.rs +++ b/library/std/src/sys/pal/xous/net/tcpstream.rs @@ -140,10 +140,7 @@ impl TcpStream { pub fn set_read_timeout(&self, timeout: Option<Duration>) -> 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", - )); + return Err(io::Error::ZERO_TIMEOUT); } } self.read_timeout.store( @@ -156,10 +153,7 @@ impl TcpStream { pub fn set_write_timeout(&self, timeout: Option<Duration>) -> 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", - )); + return Err(io::Error::ZERO_TIMEOUT); } } self.write_timeout.store( diff --git a/library/std/src/sys/pal/xous/net/udp.rs b/library/std/src/sys/pal/xous/net/udp.rs index cafa5b3bde8..3d0522b25f3 100644 --- a/library/std/src/sys/pal/xous/net/udp.rs +++ b/library/std/src/sys/pal/xous/net/udp.rs @@ -331,10 +331,7 @@ impl UdpSocket { pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { if let Some(d) = timeout { if d.is_zero() { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - &"Zero duration is invalid" - )); + return Err(io::Error::ZERO_TIMEOUT); } } self.read_timeout @@ -345,10 +342,7 @@ impl UdpSocket { pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { if let Some(d) = timeout { if d.is_zero() { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - &"Zero duration is invalid" - )); + return Err(io::Error::ZERO_TIMEOUT); } } self.write_timeout diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/pal/zkvm/args.rs index 7753cf63840..583c16e3a47 100644 --- a/library/std/src/sys/pal/zkvm/args.rs +++ b/library/std/src/sys/pal/zkvm/args.rs @@ -1,6 +1,7 @@ use super::{abi, WORD_SIZE}; use crate::ffi::OsString; use crate::fmt; +use crate::sys::os_str; use crate::sys_common::FromInner; pub struct Args { @@ -33,7 +34,7 @@ impl Args { // "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() }) + OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() }) } } diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 228a976dbab..4f79f8c4961 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -12,8 +12,6 @@ const WORD_SIZE: usize = core::mem::size_of::<u32>(); 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; @@ -54,10 +52,7 @@ pub fn unsupported<T>() -> std_io::Result<T> { } pub fn unsupported_err() -> std_io::Error { - std_io::const_io_error!( - std_io::ErrorKind::Unsupported, - "operation not supported on this platform", - ) + std_io::Error::UNSUPPORTED_PLATFORM } pub fn is_interrupted(_code: i32) -> bool { diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index d8739ee3824..759beb2d306 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -5,6 +5,7 @@ use crate::fmt; use crate::io; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; +use crate::sys::os_str; use crate::sys_common::FromInner; pub fn errno() -> i32 { @@ -111,7 +112,7 @@ pub fn getenv(varname: &OsStr) -> Option<OsString> { // 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() })) + Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) } pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index d1918855797..337cc6c2ca0 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -202,7 +202,7 @@ impl Node { fn prepare(&mut self) { // Fall back to creating an unnamed `Thread` handle to allow locking in // TLS destructors. - self.thread.get_or_init(|| thread::try_current().unwrap_or_else(|| Thread::new(None))); + self.thread.get_or_init(|| thread::try_current().unwrap_or_else(Thread::new_unnamed)); self.completed = AtomicBool::new(false); } diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 5abf201aa20..cc21560fff5 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -25,7 +25,6 @@ pub mod fs; pub mod io; pub mod lazy_box; pub mod process; -pub mod thread; pub mod thread_local_dtor; pub mod thread_parking; pub mod wstr; diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 8c9885974b4..6a268633f72 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -417,6 +417,10 @@ impl TcpListener { // it allows up to about 37, but other times it doesn't even // accept 32. There may be a global limitation causing this. let backlog = 20; + } else if #[cfg(target_os = "haiku")] { + // Haiku does not support a queue length > 32 + // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81 + let backlog = 32; } else { // The default for all other platforms let backlog = 128; diff --git a/library/std/src/sys_common/thread.rs b/library/std/src/sys_common/thread.rs deleted file mode 100644 index 8f5624bbce9..00000000000 --- a/library/std/src/sys_common/thread.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::env; -use crate::sync::atomic::{self, Ordering}; -use crate::sys::thread as imp; - -pub fn min_stack() -> usize { - static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - match MIN.load(Ordering::Relaxed) { - 0 => {} - n => return n - 1, - } - let amt = env::var_os("RUST_MIN_STACK").and_then(|s| s.to_str().and_then(|s| s.parse().ok())); - let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE); - - // 0 is our sentinel value, so ensure that we'll never see 0 after - // initialization has run - MIN.store(amt + 1, Ordering::Relaxed); - amt -} diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 7dcc1141099..a9cd26389cd 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -1,4 +1,4 @@ -//! OS-based thread local storage +//! OS-based thread local storage for non-Windows systems //! //! This module provides an implementation of OS-based thread local storage, //! using the native OS-provided facilities (think `TlsAlloc` or @@ -11,6 +11,9 @@ //! the OS-TLS key. The other is a type which does implement `Drop` and hence //! has a safe interface. //! +//! Windows doesn't use this module at all; `sys::pal::windows::thread_local_key` +//! gets imported in its stead. +//! //! # Usage //! //! This module should likely not be used directly unless other primitives are diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index fbb882e640b..c1b4440e560 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -53,25 +53,25 @@ use crate::fmt; /// # Examples /// /// ``` -/// use std::cell::RefCell; +/// use std::cell::Cell; /// use std::thread; /// -/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1)); +/// thread_local!(static FOO: Cell<u32> = Cell::new(1)); /// -/// FOO.with_borrow(|v| assert_eq!(*v, 1)); -/// FOO.with_borrow_mut(|v| *v = 2); +/// assert_eq!(FOO.get(), 1); +/// FOO.set(2); /// /// // each thread starts out with the initial value of 1 /// let t = thread::spawn(move|| { -/// FOO.with_borrow(|v| assert_eq!(*v, 1)); -/// FOO.with_borrow_mut(|v| *v = 3); +/// assert_eq!(FOO.get(), 1); +/// FOO.set(3); /// }); /// /// // wait for the thread to complete and bail out on panic /// t.join().unwrap(); /// /// // we retain our original value of 2 despite the child thread -/// FOO.with_borrow(|v| assert_eq!(*v, 2)); +/// assert_eq!(FOO.get(), 2); /// ``` /// /// # Platform-specific behavior @@ -141,15 +141,16 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// Publicity and attributes for each static are allowed. Example: /// /// ``` -/// use std::cell::RefCell; +/// use std::cell::{Cell, RefCell}; +/// /// thread_local! { -/// pub static FOO: RefCell<u32> = RefCell::new(1); +/// pub static FOO: Cell<u32> = Cell::new(1); /// -/// static BAR: RefCell<f32> = RefCell::new(1.0); +/// static BAR: RefCell<Vec<f32>> = RefCell::new(vec![1.0, 2.0]); /// } /// -/// FOO.with_borrow(|v| assert_eq!(*v, 1)); -/// BAR.with_borrow(|v| assert_eq!(*v, 1.0)); +/// assert_eq!(FOO.get(), 1); +/// BAR.with_borrow(|v| assert_eq!(v[1], 2.0)); /// ``` /// /// Note that only shared references (`&T`) to the inner data may be obtained, so a @@ -164,12 +165,13 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// track any additional state. /// /// ``` -/// use std::cell::Cell; +/// use std::cell::RefCell; +/// /// thread_local! { -/// pub static FOO: Cell<u32> = const { Cell::new(1) }; +/// pub static FOO: RefCell<Vec<u32>> = const { RefCell::new(Vec::new()) }; /// } /// -/// assert_eq!(FOO.get(), 1); +/// FOO.with_borrow(|v| assert_eq!(v.len(), 0)); /// ``` /// /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more @@ -279,10 +281,9 @@ impl<T: 'static> LocalKey<T> { where F: FnOnce(&T) -> R, { - unsafe { - let thread_local = (self.inner)(None).ok_or(AccessError)?; - Ok(f(thread_local)) - } + // SAFETY: `inner` is safe to call within the lifetime of the thread + let thread_local = unsafe { (self.inner)(None).ok_or(AccessError)? }; + Ok(f(thread_local)) } /// Acquires a reference to the value in this TLS key, initializing it with @@ -301,14 +302,17 @@ impl<T: 'static> LocalKey<T> { where F: FnOnce(Option<T>, &T) -> R, { - unsafe { - let mut init = Some(init); - let reference = (self.inner)(Some(&mut init)).expect( + let mut init = Some(init); + + // SAFETY: `inner` is safe to call within the lifetime of the thread + let reference = unsafe { + (self.inner)(Some(&mut init)).expect( "cannot access a Thread Local Storage value \ during or after destruction", - ); - f(init, reference) - } + ) + }; + + f(init, reference) } } @@ -377,7 +381,7 @@ impl<T: 'static> LocalKey<Cell<T>> { where T: Copy, { - self.with(|cell| cell.get()) + self.with(Cell::get) } /// Takes the contained value, leaving `Default::default()` in its place. @@ -407,7 +411,7 @@ impl<T: 'static> LocalKey<Cell<T>> { where T: Default, { - self.with(|cell| cell.take()) + self.with(Cell::take) } /// Replaces the contained value, returning the old value. @@ -578,7 +582,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { where T: Default, { - self.with(|cell| cell.take()) + self.with(RefCell::take) } /// Replaces the contained value, returning the old value. diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f792a27dd69..604eb05040b 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -160,6 +160,7 @@ mod tests; use crate::any::Any; use crate::cell::{OnceCell, UnsafeCell}; +use crate::env; use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; @@ -171,9 +172,9 @@ use crate::panicking; use crate::pin::Pin; use crate::ptr::addr_of_mut; use crate::str; +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::Arc; use crate::sys::thread as imp; -use crate::sys_common::thread; use crate::sys_common::thread_parking::Parker; use crate::sys_common::{AsInner, IntoInner}; use crate::time::{Duration, Instant}; @@ -468,11 +469,29 @@ impl Builder { { let Builder { name, stack_size } = self; - let stack_size = stack_size.unwrap_or_else(thread::min_stack); + let stack_size = stack_size.unwrap_or_else(|| { + static MIN: AtomicUsize = AtomicUsize::new(0); - let my_thread = Thread::new(name.map(|name| { - CString::new(name).expect("thread name may not contain interior null bytes") - })); + match MIN.load(Ordering::Relaxed) { + 0 => {} + n => return n - 1, + } + + let amt = env::var_os("RUST_MIN_STACK") + .and_then(|s| s.to_str().and_then(|s| s.parse().ok())) + .unwrap_or(imp::DEFAULT_MIN_STACK_SIZE); + + // 0 is our sentinel value, so ensure that we'll never see 0 after + // initialization has run + MIN.store(amt + 1, Ordering::Relaxed); + amt + }); + + let my_thread = name.map_or_else(Thread::new_unnamed, |name| unsafe { + Thread::new( + CString::new(name).expect("thread name may not contain interior null bytes"), + ) + }); let their_thread = my_thread.clone(); let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet { @@ -694,7 +713,7 @@ pub(crate) fn set_current(thread: Thread) { /// In contrast to the public `current` function, this will not panic if called /// from inside a TLS destructor. pub(crate) fn try_current() -> Option<Thread> { - CURRENT.try_with(|current| current.get_or_init(|| Thread::new(None)).clone()).ok() + CURRENT.try_with(|current| current.get_or_init(|| Thread::new_unnamed()).clone()).ok() } /// Gets a handle to the thread that invokes it. @@ -1191,17 +1210,17 @@ impl ThreadId { cfg_if::cfg_if! { if #[cfg(target_has_atomic = "64")] { - use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + use crate::sync::atomic::AtomicU64; static COUNTER: AtomicU64 = AtomicU64::new(0); - let mut last = COUNTER.load(Relaxed); + let mut last = COUNTER.load(Ordering::Relaxed); loop { let Some(id) = last.checked_add(1) else { exhausted(); }; - match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) { + match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { Ok(_) => return ThreadId(NonZero::new(id).unwrap()), Err(id) => last = id, } @@ -1290,21 +1309,26 @@ pub struct Thread { } impl Thread { - // Used only internally to construct a thread object without spawning - pub(crate) fn new(name: Option<CString>) -> Thread { - if let Some(name) = name { - Self::new_inner(ThreadName::Other(name)) - } else { - Self::new_inner(ThreadName::Unnamed) - } + /// Used only internally to construct a thread object without spawning. + /// + /// # Safety + /// `name` must be valid UTF-8. + pub(crate) unsafe fn new(name: CString) -> Thread { + unsafe { Self::new_inner(ThreadName::Other(name)) } + } + + pub(crate) fn new_unnamed() -> Thread { + unsafe { Self::new_inner(ThreadName::Unnamed) } } // Used in runtime to construct main thread pub(crate) fn new_main() -> Thread { - Self::new_inner(ThreadName::Main) + unsafe { Self::new_inner(ThreadName::Main) } } - fn new_inner(name: ThreadName) -> Thread { + /// # Safety + /// If `name` is `ThreadName::Other(_)`, the contained string must be valid UTF-8. + unsafe fn new_inner(name: ThreadName) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index 7b11e7c17b1..e2e22e5194f 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -47,10 +47,16 @@ impl ScopeData { // chance it overflows to 0, which would result in unsoundness. if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 { // This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles. - self.decrement_num_running_threads(false); - panic!("too many running threads in thread scope"); + self.overflow(); } } + + #[cold] + fn overflow(&self) { + self.decrement_num_running_threads(false); + panic!("too many running threads in thread scope"); + } + pub(super) fn decrement_num_running_threads(&self, panic: bool) { if panic { self.a_thread_panicked.store(true, Ordering::Relaxed); diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs index fe789323f97..fd2a7f906f8 100644 --- a/library/std/tests/create_dir_all_bare.rs +++ b/library/std/tests/create_dir_all_bare.rs @@ -31,6 +31,7 @@ impl Drop for CurrentDir { } #[test] +#[cfg_attr(all(miri, windows), ignore)] // File system access on Windows not supported by Miri fn create_dir_all_bare() { let tmpdir = common::tmpdir(); CurrentDir::with(tmpdir.path(), || { diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs index 59f67f9901f..c56c111c37d 100644 --- a/library/std/tests/process_spawning.rs +++ b/library/std/tests/process_spawning.rs @@ -8,6 +8,7 @@ use std::str; mod common; #[test] +#[cfg_attr(miri, ignore)] // Process spawning not supported by Miri fn issue_15149() { // If we're the parent, copy our own binary to a new directory. let my_path = env::current_exe().unwrap(); diff --git a/library/std/tests/switch-stdout.rs b/library/std/tests/switch-stdout.rs index 27f3e8a9b96..0afe18088fa 100644 --- a/library/std/tests/switch-stdout.rs +++ b/library/std/tests/switch-stdout.rs @@ -51,6 +51,7 @@ fn switch_stdout_to(file: OwnedHandle) -> OwnedHandle { } #[test] +#[cfg_attr(miri, ignore)] // dup/SetStdHandle not supported by Miri fn switch_stdout() { let temp = common::tmpdir(); let path = temp.join("switch-stdout-output"); diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 4ce81f2846e..79a981d0b0d 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -5,7 +5,8 @@ use std::time::Duration; #[test] #[cfg_attr(target_os = "emscripten", ignore)] -fn sleep() { +#[cfg_attr(miri, ignore)] // Miri does not like the thread leak +fn sleep_very_long() { let finished = Arc::new(Mutex::new(false)); let t_finished = finished.clone(); thread::spawn(move || { diff --git a/library/stdarch b/library/stdarch -Subproject 967e7afd87cbea3232581a4a55031134ab88f59 +Subproject 7df81ba8c3e2d02c2ace0c5a6f4f32d800c09e5 diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 4c42e3bae56..0e2409f63ab 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -9,4 +9,6 @@ std = { path = "../std" } core = { path = "../core" } panic_unwind = { path = "../panic_unwind" } panic_abort = { path = "../panic_abort" } + +[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.150", default-features = false } diff --git a/library/test/src/console.rs b/library/test/src/console.rs index f3918ba333a..7e224d60d9d 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -315,10 +315,8 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> 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_unsupported = (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) - || cfg!(target_os = "zkvm") - || cfg!(miri); + let is_instant_unsupported = + (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) || cfg!(target_os = "zkvm"); let start_time = (!is_instant_unsupported).then(Instant::now); run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 728c73d8c50..f3c22061d25 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -140,7 +140,10 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt }); panic::set_hook(hook); } - match console::run_tests_console(&opts, tests) { + let res = console::run_tests_console(&opts, tests); + // Prevent Valgrind from reporting reachable blocks in users' unit tests. + drop(panic::take_hook()); + match res { Ok(true) => {} Ok(false) => process::exit(ERROR_EXIT_CODE), Err(e) => { diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index b7418d1189c..bbd1db8dfa5 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -15,10 +15,12 @@ doc = false [dependencies] core = { path = "../core" } -libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } compiler_builtins = "0.1.0" cfg-if = "1.0" +[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } + [target.'cfg(target_os = "xous")'.dependencies] unwinding = { version = "0.2.1", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 51d31a00afe..544d9fbf1ae 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -12,6 +12,10 @@ )] #![allow(internal_features)] +// Force libc to be included even if unused. This is required by many platforms. +#[cfg(not(all(windows, target_env = "msvc")))] +extern crate libc as _; + cfg_if::cfg_if! { if #[cfg(target_env = "msvc")] { // Windows MSVC no extra unwinder support needed diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 57ce3d0fa5c..e34e73a3516 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -1,6 +1,6 @@ #![allow(nonstandard_style)] -use libc::{c_int, c_void}; +use core::ffi::{c_int, c_void}; #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq)] diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs index 95e2eb000cc..083acaeb56a 100644 --- a/library/unwind/src/unwinding.rs +++ b/library/unwind/src/unwinding.rs @@ -1,6 +1,6 @@ #![allow(nonstandard_style)] -use libc::{c_int, c_void}; +use core::ffi::{c_int, c_void}; #[repr(C)] #[derive(Copy, Clone, PartialEq)] diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 818a7daadca..768aac912ce 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -152,9 +152,9 @@ v("default-linker", "rust.default-linker", "the default linker") # (others are conditionally saved). o("manage-submodules", "build.submodules", "let the build manage the git submodules") o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two (not recommended except for testing reproducible builds)") -o("bootstrap-cache-path", "build.bootstrap-cache-path", "use provided path for the bootstrap cache") o("extended", "build.extended", "build an extended rust tool set") +v("bootstrap-cache-path", None, "use provided path for the bootstrap cache") v("tools", None, "List of extended tools will be installed") v("codegen-backends", None, "List of codegen backends to build") v("build", "build.build", "GNUs ./configure syntax LLVM build triple") @@ -359,6 +359,8 @@ def apply_args(known_args, option_checking, config): set('target.{}.llvm-filecheck'.format(build_triple), value, config) elif option.name == 'tools': set('build.tools', value.split(','), config) + elif option.name == 'bootstrap-cache-path': + set('build.bootstrap-cache-path', value, config) elif option.name == 'codegen-backends': set('rust.codegen-backends', value.split(','), config) elif option.name == 'host': diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 0b67079917c..d6e60d52d63 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -52,6 +52,36 @@ check-aux: src/tools/cargo \ src/tools/cargotest \ $(BOOTSTRAP_ARGS) + # Run standard library tests in Miri. + # We use a 64bit little-endian and a 32bit big-endian target for max coverage. + $(Q)BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 \ + --target x86_64-unknown-linux-gnu,mips-unknown-linux-gnu \ + library/core \ + library/alloc \ + --no-doc + # Some doctests have intentional memory leaks. + # Also, they work only on the host. + $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ + $(BOOTSTRAP) miri --stage 2 \ + library/core \ + library/alloc \ + --doc + # In `std` we cannot test everything. + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 library/std \ + --no-doc -- \ + --skip fs:: --skip net:: --skip process:: --skip sys::pal:: + $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 library/std \ + --doc -- \ + --skip fs:: --skip net:: --skip process:: --skip sys::pal:: + # Also test some very target-specific modules on other targets. + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 library/std \ + --target aarch64-apple-darwin,i686-pc-windows-gnu \ + --no-doc -- \ + time:: sync:: thread:: env:: dist: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) distcheck: diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 55180a82885..37d91b14ca1 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -296,7 +296,7 @@ impl Step for Rustc { cargo_subcommand(builder.kind), ); - rustc_cargo(builder, &mut cargo, target, compiler.stage); + rustc_cargo(builder, &mut cargo, target, &compiler); // For ./x.py clippy, don't run with --all-targets because // linting tests and benchmarks can produce very noisy results diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index e03997181ee..9420e40d6c2 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -945,55 +945,10 @@ impl Step for Rustc { "build", ); - rustc_cargo(builder, &mut cargo, target, compiler.stage); + rustc_cargo(builder, &mut cargo, target, &compiler); - if builder.config.rust_profile_use.is_some() - && builder.config.rust_profile_generate.is_some() - { - panic!("Cannot use and generate PGO profiles at the same time"); - } - - // With LLD, we can use ICF (identical code folding) to reduce the executable size - // of librustc_driver/rustc and to improve i-cache utilization. - // - // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF) - // is already on by default in MSVC optimized builds, which is interpreted as --icf=all: - // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746 - // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827 - if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() { - cargo.rustflag("-Clink-args=-Wl,--icf=all"); - } - - let is_collecting = if let Some(path) = &builder.config.rust_profile_generate { - if compiler.stage == 1 { - cargo.rustflag(&format!("-Cprofile-generate={path}")); - // Apparently necessary to avoid overflowing the counters during - // a Cargo build profile - cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4"); - true - } else { - false - } - } else if let Some(path) = &builder.config.rust_profile_use { - if compiler.stage == 1 { - cargo.rustflag(&format!("-Cprofile-use={path}")); - if builder.is_verbose() { - cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function"); - } - true - } else { - false - } - } else { - false - }; - if is_collecting { - // Ensure paths to Rust sources are relative, not absolute. - cargo.rustflag(&format!( - "-Cllvm-args=-static-func-strip-dirname-prefix={}", - builder.config.src.components().count() - )); - } + // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be + // consistently applied by check/doc/test modes too. for krate in &*self.crates { cargo.arg("-p").arg(krate); @@ -1044,7 +999,12 @@ impl Step for Rustc { } } -pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, stage: u32) { +pub fn rustc_cargo( + builder: &Builder<'_>, + cargo: &mut Cargo, + target: TargetSelection, + compiler: &Compiler, +) { cargo .arg("--features") .arg(builder.rustc_features(builder.kind, target)) @@ -1055,7 +1015,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary // and may just be a time sink. - if stage != 0 { + if compiler.stage != 0 { match builder.config.rust_lto { RustcLto::Thin | RustcLto::Fat => { // Since using LTO for optimizing dylibs is currently experimental, @@ -1081,7 +1041,52 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec cargo.rustflag("-Clto=off"); } - rustc_cargo_env(builder, cargo, target, stage); + // With LLD, we can use ICF (identical code folding) to reduce the executable size + // of librustc_driver/rustc and to improve i-cache utilization. + // + // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF) + // is already on by default in MSVC optimized builds, which is interpreted as --icf=all: + // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746 + // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827 + if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() { + cargo.rustflag("-Clink-args=-Wl,--icf=all"); + } + + if builder.config.rust_profile_use.is_some() && builder.config.rust_profile_generate.is_some() { + panic!("Cannot use and generate PGO profiles at the same time"); + } + let is_collecting = if let Some(path) = &builder.config.rust_profile_generate { + if compiler.stage == 1 { + cargo.rustflag(&format!("-Cprofile-generate={path}")); + // Apparently necessary to avoid overflowing the counters during + // a Cargo build profile + cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4"); + true + } else { + false + } + } else if let Some(path) = &builder.config.rust_profile_use { + if compiler.stage == 1 { + cargo.rustflag(&format!("-Cprofile-use={path}")); + if builder.is_verbose() { + cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function"); + } + true + } else { + false + } + } else { + false + }; + if is_collecting { + // Ensure paths to Rust sources are relative, not absolute. + cargo.rustflag(&format!( + "-Cllvm-args=-static-func-strip-dirname-prefix={}", + builder.config.src.components().count() + )); + } + + rustc_cargo_env(builder, cargo, target, compiler.stage); } pub fn rustc_cargo_env( diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b51d3e15788..78176665929 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1548,6 +1548,7 @@ impl Step for Extended { compiler: builder.compiler(stage, target), backend: "cranelift".to_string(), }); + add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target}); let etc = builder.src.join("src/etc/installer"); @@ -2224,6 +2225,53 @@ impl Step for LlvmTools { } } +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] +pub struct LlvmBitcodeLinker { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for LlvmBitcodeLinker { + type Output = Option<GeneratedTarball>; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker"); + run.alias("llvm-bitcode-linker").default_condition(default) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(LlvmBitcodeLinker { + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { + let compiler = self.compiler; + let target = self.target; + + let llbc_linker = + builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] }); + + let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); + + // Prepare the image directory + let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple); + tarball.set_overlay(OverlayKind::LlvmBitcodeLinker); + tarball.is_preview(true); + + tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755); + + Some(tarball.generate()) + } +} + // Tarball intended for internal consumption to ease rustc/std development. // // Should not be considered stable by end users. diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 51b5cdc0565..a22cbeacf01 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -804,7 +804,7 @@ impl Step for Rustc { // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // cargo.rustdocflag("--generate-link-to-definition"); - compile::rustc_cargo(builder, &mut cargo, target, compiler.stage); + compile::rustc_cargo(builder, &mut cargo, target, &compiler); cargo.arg("-Zunstable-options"); cargo.arg("-Zskip-rustdoc-fingerprint"); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 41920fabaa9..767c0f69364 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -300,6 +300,15 @@ install!((self, builder, _config), ); } }; + LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, { + if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) { + install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping llvm-bitcode-linker stage{} ({})", self.compiler.stage, self.target), + ); + } + }; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index bacf5f0d33c..1980980b6d0 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -597,7 +597,7 @@ impl Step for Miri { builder.ensure(compile::Std::new(target_compiler, host)); let host_sysroot = builder.sysroot(target_compiler); - // # Run `cargo test`. + // Run `cargo test`. // This is with the Miri crate, so it uses the host compiler. let mut cargo = tool::prepare_tool_cargo( builder, @@ -652,15 +652,46 @@ impl Step for Miri { builder.run(&mut cargo); } } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CargoMiri { + target: TargetSelection, +} + +impl Step for CargoMiri { + type Output = (); + const ONLY_HOSTS: bool = false; - // # Run `cargo miri test`. + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/miri/cargo-miri") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CargoMiri { target: run.target }); + } + + /// Tests `cargo miri test`. + fn run(self, builder: &Builder<'_>) { + let host = builder.build.build; + let target = self.target; + let stage = builder.top_stage; + if stage == 0 { + eprintln!("cargo-miri cannot be tested at stage 0"); + std::process::exit(1); + } + + // This compiler runs on the host, we'll just use it for the target. + let compiler = builder.compiler(stage, host); + + // Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures // that we get the desired output), but that is sufficient to make sure that the libtest harness // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode. - // This is running the build `cargo-miri` for the given target, so we need the target compiler. let mut cargo = tool::prepare_tool_cargo( builder, - target_compiler, + compiler, Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test! target, "miri-test", @@ -1369,6 +1400,8 @@ impl Step for RunMakeSupport { default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" }); +default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" }); + default_test!(RunPassValgrind { path: "tests/run-pass-valgrind", mode: "run-pass-valgrind", @@ -2658,20 +2691,31 @@ impl Step for Crate { match mode { Mode::Std => { - compile::std_cargo(builder, target, compiler.stage, &mut cargo); - // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, - // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. - // Override it. - if builder.download_rustc() && compiler.stage > 0 { - let sysroot = builder - .out - .join(compiler.host.triple) - .join(format!("stage{}-test-sysroot", compiler.stage)); - cargo.env("RUSTC_SYSROOT", sysroot); + if builder.kind == Kind::Miri { + // We can't use `std_cargo` as that uses `optimized-compiler-builtins` which + // needs host tools for the given target. This is similar to what `compile::Std` + // does when `is_for_mir_opt_tests` is true. There's probably a chance for + // de-duplication here... `std_cargo` should support a mode that avoids needing + // host tools. + cargo + .arg("--manifest-path") + .arg(builder.src.join("library/sysroot/Cargo.toml")); + } else { + compile::std_cargo(builder, target, compiler.stage, &mut cargo); + // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, + // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. + // Override it. + if builder.download_rustc() && compiler.stage > 0 { + let sysroot = builder + .out + .join(compiler.host.triple) + .join(format!("stage{}-test-sysroot", compiler.stage)); + cargo.env("RUSTC_SYSROOT", sysroot); + } } } Mode::Rustc => { - compile::rustc_cargo(builder, &mut cargo, target, compiler.stage); + compile::rustc_cargo(builder, &mut cargo, target, &compiler); } _ => panic!("can only test libraries"), }; @@ -3258,6 +3302,11 @@ impl Step for CodegenCranelift { return; } + if builder.download_rustc() { + builder.info("CI rustc uses the default codegen backend. skipping"); + return; + } + if !target_supports_cranelift_backend(run.target) { builder.info("target not supported by rustc_codegen_cranelift. skipping"); return; @@ -3379,6 +3428,11 @@ impl Step for CodegenGCC { return; } + if builder.download_rustc() { + builder.info("CI rustc uses the default codegen backend. skipping"); + return; + } + let triple = run.target.triple; let target_supported = if triple.contains("linux") { triple.contains("x86_64") } else { false }; diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 1edf65d28b7..8d1ff2fcb24 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -746,9 +746,11 @@ impl Step for LlvmBitcodeLinker { .join(exe(bin_name, self.compiler.host)); if self.compiler.stage > 0 { - let bindir = builder.sysroot(self.compiler).join("bin"); - t!(fs::create_dir_all(&bindir)); - let bin_destination = bindir.join(exe(bin_name, self.compiler.host)); + let bindir_self_contained = builder + .sysroot(self.compiler) + .join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple)); + t!(fs::create_dir_all(&bindir_self_contained)); + let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host)); builder.copy_link(&tool_out, &bin_destination); bin_destination } else { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 9555be481e6..f31bc46d25f 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -645,27 +645,6 @@ pub enum Kind { } impl Kind { - pub fn parse(string: &str) -> Option<Kind> { - // these strings, including the one-letter aliases, must match the x.py help text - Some(match string { - "build" | "b" => Kind::Build, - "check" | "c" => Kind::Check, - "clippy" => Kind::Clippy, - "fix" => Kind::Fix, - "fmt" => Kind::Format, - "test" | "t" => Kind::Test, - "bench" => Kind::Bench, - "doc" | "d" => Kind::Doc, - "clean" => Kind::Clean, - "dist" => Kind::Dist, - "install" => Kind::Install, - "run" | "r" => Kind::Run, - "setup" => Kind::Setup, - "suggest" => Kind::Suggest, - _ => return None, - }) - } - pub fn as_str(&self) -> &'static str { match self { Kind::Build => "build", @@ -766,6 +745,7 @@ impl<'a> Builder<'a> { test::ExpandYamlAnchors, test::Tidy, test::Ui, + test::Crashes, test::RunPassValgrind, test::Coverage, test::CoverageMap, @@ -808,6 +788,7 @@ impl<'a> Builder<'a> { test::EditionGuide, test::Rustfmt, test::Miri, + test::CargoMiri, test::Clippy, test::RustDemangler, test::CompiletestTest, @@ -872,6 +853,7 @@ impl<'a> Builder<'a> { dist::Clippy, dist::Miri, dist::LlvmTools, + dist::LlvmBitcodeLinker, dist::RustDev, dist::Bootstrap, dist::Extended, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 96dec975250..c84eb8a684f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2483,9 +2483,20 @@ impl Config { llvm::is_ci_llvm_available(self, asserts) } }; + match download_ci_llvm { - None => self.channel == "dev" && if_unchanged(), - Some(StringOrBool::Bool(b)) => b, + None => { + (self.channel == "dev" || self.download_rustc_commit.is_some()) && if_unchanged() + } + Some(StringOrBool::Bool(b)) => { + if !b && self.download_rustc_commit.is_some() { + panic!( + "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`." + ); + } + + b + } // FIXME: "if-available" is deprecated. Remove this block later (around mid 2024) // to not break builds between the recent-to-old checkouts. Some(StringOrBool::String(s)) if s == "if-available" => { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index bcb8260b15a..1a8322c0dfd 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1911,15 +1911,6 @@ impl Compiler { pub fn is_snapshot(&self, build: &Build) -> bool { self.stage == 0 && self.host == build.build } - - /// Returns if this compiler should be treated as a final stage one in the - /// current build session. - /// This takes into account whether we're performing a full bootstrap or - /// not; don't directly compare the stage with `2`! - pub fn is_final_stage(&self, build: &Build) -> bool { - let final_stage = if build.config.full_bootstrap { 2 } else { 1 }; - self.stage >= final_stage - } } fn envify(s: &str) -> String { diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 95cd55c9a3d..16e0c2ac185 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -377,7 +377,7 @@ struct SuiteOutcome { measured: usize, filtered_out: usize, /// The time it took to execute this test suite, or `None` if time measurement was not possible - /// (e.g. due to running inside Miri). + /// (e.g. due to running on wasm). exec_time: Option<f64>, } diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 4f99079a57f..89fcac2a84b 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -20,6 +20,7 @@ pub(crate) enum OverlayKind { RLS, RustAnalyzer, RustcCodegenCranelift, + LlvmBitcodeLinker, } impl OverlayKind { @@ -64,6 +65,12 @@ impl OverlayKind { "compiler/rustc_codegen_cranelift/LICENSE-APACHE", "compiler/rustc_codegen_cranelift/LICENSE-MIT", ], + OverlayKind::LlvmBitcodeLinker => &[ + "COPYRIGHT", + "LICENSE-APACHE", + "LICENSE-MIT", + "src/tools/llvm-bitcode-linker/README.md", + ], } } @@ -87,6 +94,7 @@ impl OverlayKind { .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), OverlayKind::RustcCodegenCranelift => builder.rust_version(), + OverlayKind::LlvmBitcodeLinker => builder.rust_version(), } } } diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index 85b0f3b1081..d5027589e0b 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -26,4 +26,6 @@ ENV RUST_CONFIGURE_ARGS \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs -ENV SCRIPT python3 ../x.py --stage 2 test +# FIXME: Skipping cargo panic_abort_doc_tests due to https://github.com/rust-lang/rust/issues/123733 +ENV SCRIPT python3 ../x.py --stage 2 test && \ + python3 ../x.py --stage 2 test src/tools/cargo --test-args \"--skip panic_abort_doc_tests\" diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 09fbbac466c..5c459e5cd18 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -99,6 +99,7 @@ ENV TARGETS=$TARGETS,thumbv8m.base-none-eabi ENV TARGETS=$TARGETS,thumbv8m.main-none-eabi ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf ENV TARGETS=$TARGETS,riscv32i-unknown-none-elf +ENV TARGETS=$TARGETS,riscv32im-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf @@ -130,6 +131,8 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft CFLAGS_aarch64_unknown_none=-mstrict-align -march=armv8-a+fp+simd \ CC_riscv32i_unknown_none_elf=riscv32-unknown-elf-gcc \ CFLAGS_riscv32i_unknown_none_elf=-march=rv32i -mabi=ilp32 \ + CC_riscv32im_unknown_none_elf=riscv32-unknown-elf-gcc \ + CFLAGS_riscv32im_unknown_none_elf=-march=rv32im -mabi=ilp32 \ CC_riscv32imc_unknown_none_elf=riscv32-unknown-elf-gcc \ CFLAGS_riscv32imc_unknown_none_elf=-march=rv32imc -mabi=ilp32 \ CC_riscv32imac_unknown_none_elf=riscv32-unknown-elf-gcc \ diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock index a579ea965f2..b0c17d9a296 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "r-efi" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0" +checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" [[package]] name = "uefi_qemu_test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index e08c4e1e8b7..a74db2250fc 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -25,5 +25,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# Miri is just too slow with full assertions +ENV NO_DEBUG_ASSERTIONS=1 +ENV NO_OVERFLOW_CHECKS=1 + ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu ENV RUST_CHECK_TARGET check-aux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 6f720569898..a3e8f6176a3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -78,16 +78,6 @@ ENV PATH="$NODE_FOLDER:${PATH}" COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -# -# We also specify the version in case we need to update it to go around cache limitations. -# -# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case -# the local version of the package is different than the one used by the CI. -RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true - ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ @@ -100,6 +90,14 @@ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ RUN /scripts/build-gccjit.sh /scripts +# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries +# to create a new folder. For reference: +# https://github.com/puppeteer/puppeteer/issues/375 +# +# We also specify the version in case we need to update it to go around cache limitations. +# +# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case +# the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ - NODE_PATH=`npm root -g` python3 ../x.py test tests/rustdoc-gui --stage 2 \ - --test-args "'--no-sandbox --jobs 1'" + npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 14a8c245756..50c2e5e29f0 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.17.1 \ No newline at end of file +0.17.2 \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 38c5b173ae3..53b4583166d 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -32,9 +32,9 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt # that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. # This significantly increases the runtime of our test suite, or we'd do this in PR CI too. if [ -z "${PR_CI_JOB:-}" ]; then - MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri + MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri else - python3 "$X_PY" test --stage 2 src/tools/miri + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri fi # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. @@ -42,8 +42,8 @@ case $HOST_TARGET in x86_64-unknown-linux-gnu) # Only this branch runs in PR CI. # Fully test all main OSes, including a 32bit target. - python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin - python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target x86_64-apple-darwin + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc # Only run "pass" tests for the remaining targets, which is quite a bit faster. python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass python3 "$X_PY" test --stage 2 src/tools/miri --target i686-unknown-linux-gnu --test-args pass diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 80e23574404..de71b9f874f 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -249,7 +249,8 @@ x--expand-yaml-anchors--remove: <<: *step - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} @@ -340,9 +341,22 @@ concurrency: cancel-in-progress: true jobs: + # The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml. + calculate_matrix: + name: Calculate job matrix + runs-on: ubuntu-latest + outputs: + jobs: ${{ steps.jobs.outputs.jobs }} + steps: + - name: Checkout the source code + uses: actions/checkout@v4 + - name: Calculate the CI job matrix + run: python3 src/ci/scripts/calculate-job-matrix.py >> $GITHUB_OUTPUT + id: jobs pr: <<: *base-ci-job name: PR - ${{ matrix.name }} + needs: [ calculate_matrix ] env: <<: [*shared-ci-variables, *public-variables] PR_CI_JOB: 1 @@ -350,20 +364,8 @@ jobs: continue-on-error: ${{ matrix.name == 'mingw-check-tidy' }} strategy: matrix: - include: - - name: mingw-check - <<: *job-linux-4c - - - name: mingw-check-tidy - <<: *job-linux-4c - - - name: x86_64-gnu-llvm-17 - env: - ENABLE_GCC_CODEGEN: "1" - <<: *job-linux-16c - - - name: x86_64-gnu-tools - <<: *job-linux-16c + # Check the `calculate_matrix` job to see how is the matrix defined. + include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }} auto: <<: *base-ci-job diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml new file mode 100644 index 00000000000..7e89eef2670 --- /dev/null +++ b/src/ci/github-actions/jobs.yml @@ -0,0 +1,50 @@ +# This file contains definitions of CI job parameters that are loaded +# dynamically in CI from ci.yml. +# You *do not* need to re-run `src/tools/expand-yaml-anchors` when you +# modify this file. +shared_defs: + - &base-job + env: { } + + - &job-linux-4c + os: ubuntu-20.04-4core-16gb + <<: *base-job + + - &job-linux-8c + os: ubuntu-20.04-8core-32gb + <<: *base-job + + - &job-linux-16c + os: ubuntu-20.04-16core-64gb + <<: *base-job + + - &job-macos-xl + os: macos-13 # We use the standard runner for now + <<: *base-job + + - &job-macos-m1 + os: macos-14 + <<: *base-job + + - &job-windows-8c + os: windows-2019-8core-32gb + <<: *base-job + + - &job-windows-16c + os: windows-2019-16core-64gb + <<: *base-job + + - &job-aarch64-linux + os: [ self-hosted, ARM64, linux ] + +pr: + - name: mingw-check + <<: *job-linux-4c + - name: mingw-check-tidy + <<: *job-linux-4c + - name: x86_64-gnu-llvm-17 + env: + ENABLE_GCC_CODEGEN: "1" + <<: *job-linux-16c + - name: x86_64-gnu-tools + <<: *job-linux-16c diff --git a/src/ci/scripts/calculate-job-matrix.py b/src/ci/scripts/calculate-job-matrix.py new file mode 100755 index 00000000000..9b1e74c23c3 --- /dev/null +++ b/src/ci/scripts/calculate-job-matrix.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +""" +This script serves for generating a matrix of jobs that should +be executed on CI. + +It reads job definitions from `src/ci/github-actions/jobs.yml` +and filters them based on the event that happened on CI. + +Currently, it only supports PR builds. +""" + +import json +from pathlib import Path + +import yaml + +JOBS_YAML_PATH = Path(__file__).absolute().parent.parent / "github-actions" / "jobs.yml" + + +if __name__ == "__main__": + with open(JOBS_YAML_PATH) as f: + jobs = yaml.safe_load(f) + job_output = jobs["pr"] + print(f"jobs={json.dumps(job_output)}") diff --git a/src/doc/book b/src/doc/book -Subproject 19c40bfd2d57641d962f3119a1c343355f1b3c5 +Subproject 3131aa4642c627a24f523c82566b94a7d920f68 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 98b33e9a441457b0a491fe1be90e7de64eafc3e +Subproject eb3eb80e106d03250c1fb7c5666b1c8c5967286 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 2e95fc2fd31d669947e993aa07ef10dc9828bee +Subproject aa7d4b0b4653ddb47cb1de2036d090ec2ba9dab diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 6bc2415218d4dd0cb01433d8320f5ccf79c343a +Subproject 0d5f88475fe285affa6dbbc806e9e44d730797c diff --git a/src/doc/reference b/src/doc/reference -Subproject 984b36eca4b9293df04d5ba4eb5c4f77db0f51d +Subproject 55694913b1301cc809f9bf4a1ad1b3d6920efbd diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 7601e0c5ad29d5bd3b518700ea63fddfff5915a +Subproject 60d34b5fd33db1346f9aabfc0c9d0bda6c8e42b diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject ffa246b7fd95a96e1cd54883e613aed42c32547 +Subproject b77a34bd46399687b4ce6a17198e9f316c98879 diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md index 9daa0810126..32083b2f731 100644 --- a/src/doc/rustc/src/json.md +++ b/src/doc/rustc/src/json.md @@ -262,6 +262,36 @@ information, even if the diagnostics have been suppressed (such as with an } ``` +## Unused Dependency Notifications + +The options `--json=unused-externs` and `--json=unused-externs-silent` in +conjunction with the `unused-crate-dependencies` lint will emit JSON structures +reporting any crate dependencies (specified with `--extern`) which never had any +symbols referenced. These are intended to be consumed by the build system which +can then emit diagnostics telling the user to remove the unused dependencies +from `Cargo.toml` (or whatever build-system file defines dependencies). + +The JSON structure is: +```json +{ + "lint_level": "deny", /* Level of the warning */ + "unused_names": [ + "foo" /* Names of unused crates, as specified with --extern foo=libfoo.rlib */ + ], +} +``` + +The warn/deny/forbid lint level (as defined either on the command line or in the +source) dictates the `lint_level` in the JSON. With `unused-externs`, a +`deny` or `forbid` level diagnostic will also cause `rustc` to exit with a +failure exit code. + +`unused-externs-silent` will report the diagnostic the same way, but will not +cause `rustc` to exit with failure - it's up to the consumer to flag failure +appropriately. (This is needed by Cargo which shares the same dependencies +across multiple build targets, so it should only report an unused dependency if +its not used by any of the targets.) + [option-emit]: command-line-arguments.md#option-emit [option-error-format]: command-line-arguments.md#option-error-format [option-json]: command-line-arguments.md#option-json diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 13027eeaf4f..836929aba0b 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -37,7 +37,7 @@ present in the list of expected values. If `"value"` is not in it, then `rustc` the future.* To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside -`values()`: `values(none())`. It can be followed or precessed by any number of `"value"`. +`values()`: `values(none())`. It can be followed or preceded by any number of `"value"`. To enable checking of values, but to provide an *none*/empty set of expected values (ie. expect `#[cfg(name)]`), use these forms: @@ -77,7 +77,7 @@ Those well known names and values follows the same stability as what they refer Well known names and values checking is always enabled as long as at least one `--check-cfg` argument is present. -As of `2024-02-15T`, the list of known names is as follows: +As of `2024-04-06T`, the list of known names is as follows: <!--- See CheckCfg::fill_well_known in compiler/rustc_session/src/config.rs --> @@ -107,6 +107,7 @@ As of `2024-02-15T`, the list of known names is as follows: - `target_thread_local` - `target_vendor` - `test` + - `ub_checks` - `unix` - `windows` @@ -162,7 +163,7 @@ fn poke_platypus() {} fn tame_lion() {} #[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known - // condition name, it doens't expect any values + // condition name, it doesn't expect any values fn tame_windows() {} ``` diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-options.md b/src/doc/unstable-book/src/compiler-flags/codegen-options.md index 31dfcdb199a..cc51554706d 100644 --- a/src/doc/unstable-book/src/compiler-flags/codegen-options.md +++ b/src/doc/unstable-book/src/compiler-flags/codegen-options.md @@ -10,6 +10,10 @@ In addition to the stable set of linker flavors, the following unstable values a - `ptx`: use [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia NVPTX GPGPU support. - `bpf`: use [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support. +- `llbc`: for linking in llvm bitcode. Install the preview rustup components`llvm-bitcode-linker` + and `llvm-tools` to use as a self-contained linker by passing + `-Zunstable-options -Clink-self-contained=+linker` together with `-Clinker-flavor=llbc`. + Can currently only be used for Nvidia NVPTX targets (`nvptx64-nvidia-cuda`). Additionally, a set of more precise linker flavors also exists, for example allowing targets to declare that they use the LLD linker by default. The following values are currently unstable, and diff --git a/src/doc/unstable-book/src/compiler-flags/linker-features.md b/src/doc/unstable-book/src/compiler-flags/linker-features.md new file mode 100644 index 00000000000..643fcf7c6d7 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/linker-features.md @@ -0,0 +1,35 @@ +# `linker-features` + +-------------------- + +The `-Zlinker-features` compiler flag allows enabling or disabling specific features used during +linking, and is intended to be stabilized under the codegen options as `-Clinker-features`. + +These feature flags are a flexible extension mechanism that is complementary to linker flavors, +designed to avoid the combinatorial explosion of having to create a new set of flavors for each +linker feature we'd want to use. + +For example, this design allows: +- default feature sets for principal flavors, or for specific targets. +- flavor-specific features: for example, clang offers automatic cross-linking with `--target`, which + gcc-style compilers don't support. The *flavor* is still a C/C++ compiler, and we don't want to + multiply the number of flavors for this use-case. Instead, we can have a single `+target` feature. +- umbrella features: for example, if clang accumulates more features in the future than just the + `+target` above. That could be modeled as `+clang`. +- niche features for resolving specific issues: for example, on Apple targets the linker flag + implementing the `as-needed` native link modifier (#99424) is only possible on sufficiently recent + linker versions. +- still allows for discovery and automation, for example via feature detection. This can be useful + in exotic environments/build systems. + +The flag accepts a comma-separated list of features, individually enabled (`+features`) or disabled +(`-features`), though currently only one is exposed on the CLI: +- `lld`: to toggle using the lld linker, either the system-installed binary, or the self-contained + `rust-lld` linker. + +As described above, this list is intended to grow in the future. + +One of the most common uses of this flag will be to toggle self-contained linking with `rust-lld` on +and off: `-Clinker-features=+lld -Clink-self-contained=+linker` will use the toolchain's `rust-lld` +as the linker. Inversely, `-Clinker-features=-lld` would opt out of that, if the current target had +self-contained linking enabled by default. diff --git a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md index 4f3c780972d..9e765301206 100644 --- a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md +++ b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md @@ -8,4 +8,4 @@ arguments from argfiles specified with `@shell:<path>`. Because this feature controls the parsing of input arguments, the `-Zshell-argfiles` flag must be present before the argument specifying the -shell-style arguemnt file. +shell-style argument file. diff --git a/src/doc/unstable-book/src/compiler-flags/ub-checks.md b/src/doc/unstable-book/src/compiler-flags/ub-checks.md new file mode 100644 index 00000000000..528c868d7ad --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/ub-checks.md @@ -0,0 +1,17 @@ +# `ub-checks` + +The tracking issue for this feature is: [#123499](https://github.com/rust-lang/rust/issues/123499). + +-------------------- + +The `-Zub-checks` compiler flag enables additional runtime checks that detect some causes of Undefined Behavior at runtime. +By default, `-Zub-checks` flag inherits the value of `-Cdebug-assertions`. + +All checks are generated on a best-effort basis; even if we have a check implemented for some cause of Undefined Behavior, it may be possible for the check to not fire. +If a dependency is compiled with `-Zub-checks=no` but the final binary or library is compiled with `-Zub-checks=yes`, UB checks reached by the dependency are likely to be optimized out. + +When `-Zub-checks` detects UB, a non-unwinding panic is produced. +That means that we will not unwind the stack and will not call any `Drop` impls, but we will execute the configured panic hook. +We expect that unsafe code has been written which relies on code not unwinding which may have UB checks inserted. +Ergo, an unwinding panic could easily turn works-as-intended UB into a much bigger problem. +Calling the panic hook theoretically has the same implications, but we expect that the standard library panic hook will be stateless enough to be always called, and that if a user has configured a panic hook that the hook may be very helpful to debugging the detected UB. diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 59acbc73db4..43e11b6d57d 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - M68k - CSKY - s390x +- Arm64EC ## Register classes @@ -51,6 +52,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | `f[0-31]` | `f` | | s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | | s390x | `freg` | `f[0-15]` | `f` | +| Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | +| Arm64EC | `vreg` | `v[0-15]` | `w` | +| Arm64EC | `vreg_low16` | `v[0-15]` | `x` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -86,6 +90,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | +| Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | +| Arm64EC | `vreg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | ## Register aliases @@ -118,6 +124,12 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r29` | `rtb` | | CSKY | `r30` | `svbr` | | CSKY | `r31` | `tls` | +| Arm64EC | `x[0-30]` | `w[0-30]` | +| Arm64EC | `x29` | `fp` | +| Arm64EC | `x30` | `lr` | +| Arm64EC | `sp` | `wsp` | +| Arm64EC | `xzr` | `wzr` | +| Arm64EC | `v[0-15]` | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -128,8 +140,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | +| All | `r19` (Hexagon), `x19` (Arm64EC) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | @@ -145,6 +157,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r15` | This is the link register. | | CSKY | `r[26-30]` | Reserved by its ABI. | | CSKY | `r31` | This is the TLS register. | +| Arm64EC | `xzr` | This is a constant zero register which can't be modified. | +| Arm64EC | `x18` | This is an OS-reserved register. | +| Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. | ## Template modifiers @@ -165,6 +180,16 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | s390x | `freg` | None | `%f0` | None | | CSKY | `reg` | None | `r0` | None | | CSKY | `freg` | None | `f0` | None | +| Arm64EC | `reg` | None | `x0` | `x` | +| Arm64EC | `reg` | `w` | `w0` | `w` | +| Arm64EC | `reg` | `x` | `x0` | `x` | +| Arm64EC | `vreg` | None | `v0` | None | +| Arm64EC | `vreg` | `v` | `v0` | None | +| Arm64EC | `vreg` | `b` | `b0` | `b` | +| Arm64EC | `vreg` | `h` | `h0` | `h` | +| Arm64EC | `vreg` | `s` | `s0` | `s` | +| Arm64EC | `vreg` | `d` | `d0` | `d` | +| Arm64EC | `vreg` | `q` | `q0` | `q` | # Flags covered by `preserves_flags` @@ -177,3 +202,6 @@ These flags registers must be restored upon exiting the asm block if the `preser - The condition code register `ccr`. - s390x - The condition code register `cc`. +- Arm64EC + - Condition flags (`NZCV` register). + - Floating-point status (`FPSR` register). diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 217f6bb550b..daf63998461 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -168,7 +168,7 @@ fn clean_param_env<'tcx>( // FIXME(#111101): Incorporate the explicit predicates of the item here... let item_predicates: FxIndexSet<_> = - tcx.predicates_of(item_def_id).predicates.iter().map(|(pred, _)| pred).collect(); + tcx.param_env(item_def_id).caller_bounds().iter().collect(); let where_predicates = param_env .caller_bounds() .iter() diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 72d4cc7c465..8ed6ee014f3 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,141 +1,130 @@ -use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_hir as hir; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits; -use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::{self, ToPredicate}; +use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use super::*; +use thin_vec::ThinVec; -pub(crate) struct BlanketImplFinder<'a, 'tcx> { - pub(crate) cx: &'a mut core::DocContext<'tcx>, -} +use crate::clean; +use crate::clean::{ + clean_middle_assoc_item, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty_generics, +}; +use crate::core::DocContext; + +#[instrument(level = "debug", skip(cx))] +pub(crate) fn synthesize_blanket_impls( + cx: &mut DocContext<'_>, + item_def_id: DefId, +) -> Vec<clean::Item> { + let tcx = cx.tcx; + let ty = tcx.type_of(item_def_id); -impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { - pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> { - let cx = &mut self.cx; - let ty = cx.tcx.type_of(item_def_id); + let mut blanket_impls = Vec::new(); + for trait_def_id in tcx.all_traits() { + if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id) + || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some() + { + continue; + } + // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls + let trait_impls = tcx.trait_impls_of(trait_def_id); + 'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() { + trace!("considering impl `{impl_def_id:?}` for trait `{trait_def_id:?}`"); - trace!("get_blanket_impls({ty:?})"); - let mut impls = Vec::new(); - for trait_def_id in cx.tcx.all_traits() { - if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) - || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some() - { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { continue; } - // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls - let trait_impls = cx.tcx.trait_impls_of(trait_def_id); - 'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() { - trace!( - "get_blanket_impls: Considering impl for trait '{:?}' {:?}", - trait_def_id, - impl_def_id - ); - let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { - continue; - } - let infcx = cx.tcx.infer_ctxt().build(); - let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); - let impl_ty = ty.instantiate(infcx.tcx, args); - let param_env = ty::ParamEnv::empty(); + let infcx = tcx.infer_ctxt().build(); + let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); + let impl_ty = ty.instantiate(tcx, args); + let param_env = ty::ParamEnv::empty(); - let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); - let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args); + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = trait_ref.instantiate(tcx, impl_args); - // Require the type the impl is implemented on to match - // our type, and ignore the impl if there was a mismatch. - let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq( - DefineOpaqueTypes::Yes, - impl_trait_ref.self_ty(), - impl_ty, - ) else { - continue; - }; - let InferOk { value: (), obligations } = eq_result; - // FIXME(eddyb) ignoring `obligations` might cause false positives. - drop(obligations); + // Require the type the impl is implemented on to match + // our type, and ignore the impl if there was a mismatch. + let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq( + DefineOpaqueTypes::Yes, + impl_trait_ref.self_ty(), + impl_ty, + ) else { + continue; + }; + let InferOk { value: (), obligations } = eq_result; + // FIXME(eddyb) ignoring `obligations` might cause false positives. + drop(obligations); - trace!( - "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}", + let predicates = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_args) + .predicates + .into_iter() + .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx))); + for predicate in predicates { + let obligation = traits::Obligation::new( + tcx, + traits::ObligationCause::dummy(), param_env, - impl_trait_ref, - impl_ty + predicate, ); - let predicates = cx - .tcx - .predicates_of(impl_def_id) - .instantiate(cx.tcx, impl_args) - .predicates - .into_iter() - .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx))); - for predicate in predicates { - debug!("testing predicate {predicate:?}"); - let obligation = traits::Obligation::new( - infcx.tcx, - traits::ObligationCause::dummy(), - param_env, - predicate, - ); - match infcx.evaluate_obligation(&obligation) { - Ok(eval_result) if eval_result.may_apply() => {} - Err(traits::OverflowError::Canonical) => {} - _ => continue 'blanket_impls, - } + match infcx.evaluate_obligation(&obligation) { + Ok(eval_result) if eval_result.may_apply() => {} + Err(traits::OverflowError::Canonical) => {} + _ => continue 'blanket_impls, } - debug!( - "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}", - trait_ref, ty - ); + } + debug!("found applicable impl for trait ref {trait_ref:?}"); - cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); + cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); - impls.push(Item { - name: None, - attrs: Default::default(), - item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, - kind: Box::new(ImplItem(Box::new(Impl { - unsafety: hir::Unsafety::Normal, - generics: clean_ty_generics( - cx, - cx.tcx.generics_of(impl_def_id), - cx.tcx.explicit_predicates_of(impl_def_id), - ), - // FIXME(eddyb) compute both `trait_` and `for_` from - // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(clean_trait_ref_with_bindings( - cx, - ty::Binder::dummy(trait_ref.instantiate_identity()), - ThinVec::new(), - )), - for_: clean_middle_ty( - ty::Binder::dummy(ty.instantiate_identity()), - cx, - None, - None, - ), - items: cx - .tcx - .associated_items(impl_def_id) - .in_definition_order() - .filter(|item| !item.is_impl_trait_in_trait()) - .map(|item| clean_middle_assoc_item(item, cx)) - .collect::<Vec<_>>(), - polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(Box::new(clean_middle_ty( - ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()), - cx, - None, - None, - ))), - }))), - cfg: None, - inline_stmt_id: None, - }); - } + blanket_impls.push(clean::Item { + name: None, + attrs: Default::default(), + item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, + kind: Box::new(clean::ImplItem(Box::new(clean::Impl { + unsafety: hir::Unsafety::Normal, + generics: clean_ty_generics( + cx, + tcx.generics_of(impl_def_id), + tcx.explicit_predicates_of(impl_def_id), + ), + // FIXME(eddyb) compute both `trait_` and `for_` from + // the post-inference `trait_ref`, as it's more accurate. + trait_: Some(clean_trait_ref_with_bindings( + cx, + ty::Binder::dummy(trait_ref.instantiate_identity()), + ThinVec::new(), + )), + for_: clean_middle_ty( + ty::Binder::dummy(ty.instantiate_identity()), + cx, + None, + None, + ), + items: tcx + .associated_items(impl_def_id) + .in_definition_order() + .filter(|item| !item.is_impl_trait_in_trait()) + .map(|item| clean_middle_assoc_item(item, cx)) + .collect(), + polarity: ty::ImplPolarity::Positive, + kind: clean::ImplKind::Blanket(Box::new(clean_middle_ty( + ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()), + cx, + None, + None, + ))), + }))), + cfg: None, + inline_stmt_id: None, + }); } - - impls } + + blanket_impls } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6f86c6450d9..4d506edc47b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -63,8 +63,6 @@ pub(crate) fn try_inline( let import_def_id = attrs.and_then(|(_, def_id)| def_id); - let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); - let kind = match res { Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, ItemType::Trait); @@ -134,7 +132,11 @@ pub(crate) fn try_inline( cx.with_param_env(did, |cx| clean::ConstantItem(build_const(cx, did))) } Res::Def(DefKind::Macro(kind), did) => { - let mac = build_macro(cx, did, name, import_def_id, kind, attrs.is_doc_hidden()); + let is_doc_hidden = cx.tcx.is_doc_hidden(did) + || attrs_without_docs + .map(|(attrs, _)| attrs) + .is_some_and(|attrs| utils::attrs_have_doc_flag(attrs.iter(), sym::hidden)); + let mac = build_macro(cx, did, name, import_def_id, kind, is_doc_hidden); let type_kind = match kind { MacroKind::Bang => ItemType::Macro, @@ -148,8 +150,14 @@ pub(crate) fn try_inline( }; cx.inlined.insert(did.into()); - let mut item = - clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg); + let mut item = crate::clean::generate_item_with_correct_attrs( + cx, + kind, + did, + name, + import_def_id.and_then(|def_id| def_id.as_local()), + None, + ); // The visibility needs to reflect the one from the reexport and not from the "source" DefId. item.inline_stmt_id = import_def_id; ret.push(item); @@ -179,6 +187,7 @@ pub(crate) fn try_inline_glob( .iter() .filter(|child| !child.reexport_chain.is_empty()) .filter_map(|child| child.res.opt_def_id()) + .filter(|def_id| !cx.tcx.is_doc_hidden(def_id)) .collect(); let attrs = cx.tcx.hir().attrs(import.hir_id()); let mut items = build_module_items( diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a25a506d9c5..925d41e67f8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -29,7 +29,7 @@ use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, ExpnKind}; +use rustc_span::ExpnKind; use rustc_trait_selection::traits::wf::object_region_bounds; use std::borrow::Cow; @@ -37,14 +37,14 @@ use std::collections::BTreeMap; use std::mem; use thin_vec::ThinVec; -use crate::core::{self, DocContext}; +use crate::core::DocContext; use crate::formats::item_type::ItemType; use crate::visit_ast::Module as DocModule; use utils::*; pub(crate) use self::types::*; -pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res}; +pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls}; pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item { let mut items: Vec<Item> = vec![]; @@ -1782,6 +1782,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) } } TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), + TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()), TyKind::Array(ty, ref length) => { let length = match length { hir::ArrayLen::Infer(..) => "_".to_string(), @@ -2008,6 +2009,10 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))), + ty::Pat(ty, pat) => Type::Pat( + Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), + format!("{pat:?}").into_boxed_str(), + ), ty::Array(ty, mut n) => { n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); @@ -3002,22 +3007,22 @@ fn clean_use_statement_inner<'tcx>( // were specifically asked for it denied = true; } - if !denied { - if let Some(mut items) = inline::try_inline( + if !denied + && let Some(mut items) = inline::try_inline( cx, path.res, name, Some((attrs, Some(import_def_id))), &mut Default::default(), - ) { - items.push(Item::from_def_id_and_parts( - import_def_id, - None, - ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)), - cx, - )); - return items; - } + ) + { + items.push(Item::from_def_id_and_parts( + import_def_id, + None, + ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)), + cx, + )); + return items; } Import::new_simple(name, resolve_use_source(cx, path), true) }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6793ea9f485..b592bd76e4c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -23,6 +23,7 @@ use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::IndexVec; use rustc_metadata::rendered_const; +use rustc_middle::span_bug; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_resolve::rustdoc::{ @@ -266,8 +267,15 @@ impl ExternalCrate { let as_primitive = |res: Res<!>| { let Res::Def(DefKind::Mod, def_id) = res else { return None }; tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| { - // FIXME: should warn on unknown primitives? - Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?)) + let attr_value = attr.value_str().expect("syntax should already be validated"); + let Some(prim) = PrimitiveType::from_symbol(attr_value) else { + span_bug!( + attr.span, + "primitive `{attr_value}` is not a member of `PrimitiveType`" + ); + }; + + Some((def_id, prim)) }) }; @@ -1475,7 +1483,9 @@ pub(crate) enum Type { /// /// This is mostly Rustdoc's version of [`hir::Path`]. /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics. - Path { path: Path }, + Path { + path: Path, + }, /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static` DynTrait(Vec<PolyTrait>, Option<Lifetime>), /// A type parameter. @@ -1492,10 +1502,15 @@ pub(crate) enum Type { /// /// The `String` field is a stringified version of the array's length parameter. Array(Box<Type>, Box<str>), + Pat(Box<Type>, Box<str>), /// A raw pointer type: `*const i32`, `*mut i32` RawPointer(Mutability, Box<Type>), /// A reference type: `&i32`, `&'a mut Foo` - BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> }, + BorrowedRef { + lifetime: Option<Lifetime>, + mutability: Mutability, + type_: Box<Type>, + }, /// A qualified path to an associated item: `<Type as Trait>::Name` QPath(Box<QPathData>), @@ -1692,6 +1707,7 @@ impl Type { BareFunction(..) => PrimitiveType::Fn, Slice(..) => PrimitiveType::Slice, Array(..) => PrimitiveType::Array, + Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache), Generic(_) | Infer | ImplTrait(_) => return None, @@ -1745,6 +1761,7 @@ pub(crate) enum PrimitiveType { Str, Slice, Array, + Pat, Tuple, Unit, RawPointer, @@ -1797,8 +1814,10 @@ impl PrimitiveType { sym::bool => Some(PrimitiveType::Bool), sym::char => Some(PrimitiveType::Char), sym::str => Some(PrimitiveType::Str), + sym::f16 => Some(PrimitiveType::F16), sym::f32 => Some(PrimitiveType::F32), sym::f64 => Some(PrimitiveType::F64), + sym::f128 => Some(PrimitiveType::F128), sym::array => Some(PrimitiveType::Array), sym::slice => Some(PrimitiveType::Slice), sym::tuple => Some(PrimitiveType::Tuple), @@ -1831,8 +1850,10 @@ impl PrimitiveType { U32 => single(SimplifiedType::Uint(UintTy::U32)), U64 => single(SimplifiedType::Uint(UintTy::U64)), U128 => single(SimplifiedType::Uint(UintTy::U128)), + F16 => single(SimplifiedType::Float(FloatTy::F16)), F32 => single(SimplifiedType::Float(FloatTy::F32)), F64 => single(SimplifiedType::Float(FloatTy::F64)), + F128 => single(SimplifiedType::Float(FloatTy::F128)), Str => single(SimplifiedType::Str), Bool => single(SimplifiedType::Bool), Char => single(SimplifiedType::Char), @@ -1895,6 +1916,7 @@ impl PrimitiveType { Bool => sym::bool, Char => sym::char, Array => sym::array, + Pat => sym::pat, Slice => sym::slice, Tuple => sym::tuple, Unit => sym::unit, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index d5e0e83696f..aa923cc6117 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,5 +1,5 @@ use crate::clean::auto_trait::synthesize_auto_trait_impls; -use crate::clean::blanket_impl::BlanketImplFinder; +use crate::clean::blanket_impl::synthesize_blanket_impls; use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate, @@ -477,8 +477,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { } } -// FIXME(fmease): Update the `get_*` terminology to the `synthesize_` one. -pub(crate) fn get_auto_trait_and_blanket_impls( +pub(crate) fn synthesize_auto_trait_and_blanket_impls( cx: &mut DocContext<'_>, item_def_id: DefId, ) -> impl Iterator<Item = Item> { @@ -490,8 +489,8 @@ pub(crate) fn get_auto_trait_and_blanket_impls( let blanket_impls = cx .sess() .prof - .generic_activity("get_blanket_impls") - .run(|| BlanketImplFinder { cx }.get_blanket_impls(item_def_id)); + .generic_activity("synthesize_blanket_impls") + .run(|| synthesize_blanket_impls(cx, item_def_id)); auto_impls.into_iter().chain(blanket_impls) } @@ -581,7 +580,14 @@ pub(crate) fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Opti /// This function exists because it runs on `hir::Attributes` whereas the other is a /// `clean::Attributes` method. pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { - tcx.get_attrs(did, sym::doc) + attrs_have_doc_flag(tcx.get_attrs(did, sym::doc), flag) +} + +pub(crate) fn attrs_have_doc_flag<'a>( + mut attrs: impl Iterator<Item = &'a ast::Attribute>, + flag: Symbol, +) -> bool { + attrs .any(|attr| attr.meta_item_list().is_some_and(|l| rustc_attr::list_contains_name(&l, flag))) } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9802097ea29..11fc99eb511 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -203,10 +203,10 @@ impl Cache { impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> { if item.item_id.is_local() { - let is_stripped = matches!(*item.kind, clean::ItemKind::StrippedItem(..)); debug!( - "folding {} (stripped: {is_stripped:?}) \"{:?}\", id {:?}", + "folding {} (stripped: {:?}) \"{:?}\", id {:?}", item.type_(), + item.is_stripped(), item.name, item.item_id ); @@ -246,13 +246,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // trait. if let clean::TraitItem(ref t) = *item.kind { self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| (**t).clone()); - } - - // Collect all the implementors of traits. - if let clean::ImplItem(ref i) = *item.kind + } else if let clean::ImplItem(ref i) = *item.kind && let Some(trait_) = &i.trait_ && !i.kind.is_blanket() { + // Collect all the implementors of traits. self.cache .implementors .entry(trait_.def_id()) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 312765d3e6d..f82b89fdd5f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1071,6 +1071,10 @@ fn fmt_type<'cx>( write!(f, "]") } }, + clean::Type::Pat(ref t, ref pat) => { + fmt::Display::fmt(&t.print(cx), f)?; + write!(f, " is {pat}") + } clean::Array(ref t, ref n) => match **t { clean::Generic(name) if !f.alternate() => primitive_link( f, diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index fc6f51e8272..4cab2d64257 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -231,7 +231,7 @@ impl<'tcx> Context<'tcx> { rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), }; let mut page_buffer = Buffer::html(); - print_item(self, it, &mut page_buffer, &page); + print_item(self, it, &mut page_buffer); layout::render( &clone_shared.layout, &page, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index fbb521a6188..168db5c0948 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -31,11 +31,10 @@ use crate::html::format::{ display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause, visibility_print_with_space, Buffer, Ending, PrintWithSpace, }; -use crate::html::layout::Page; +use crate::html::highlight; use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::render::{document_full, document_item_info}; use crate::html::url_parts_builder::UrlPartsBuilder; -use crate::html::{highlight, static_files}; use askama::Template; use itertools::Itertools; @@ -157,8 +156,6 @@ struct PathComponent { #[derive(Template)] #[template(path = "print_item.html")] struct ItemVars<'a> { - static_root_path: &'a str, - clipboard_svg: &'static static_files::StaticFile, typ: &'a str, name: &'a str, item_type: &'a str, @@ -178,12 +175,7 @@ fn print_where_clause_and_check<'a, 'tcx: 'a>( len_before != buffer.len() } -pub(super) fn print_item( - cx: &mut Context<'_>, - item: &clean::Item, - buf: &mut Buffer, - page: &Page<'_>, -) { +pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buffer) { debug_assert!(!item.is_stripped()); let typ = match *item.kind { clean::ModuleItem(_) => { @@ -252,8 +244,6 @@ pub(super) fn print_item( }; let item_vars = ItemVars { - static_root_path: &page.get_static_root_path(), - clipboard_svg: &static_files::STATIC_FILES.clipboard_svg, typ, name: item.name.as_ref().unwrap().as_str(), item_type: &item.type_().to_string(), @@ -1237,22 +1227,18 @@ fn item_opaque_ty( } fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { - fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { - wrap_item(w, |w| { - write!( - w, - "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", - attrs = render_attributes_in_pre(it, "", cx), - vis = visibility_print_with_space(it, cx), - name = it.name.unwrap(), - generics = t.generics.print(cx), - where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), - type_ = t.type_.print(cx), - ); - }); - } - - write_content(w, cx, it, t); + wrap_item(w, |w| { + write!( + w, + "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", + attrs = render_attributes_in_pre(it, "", cx), + vis = visibility_print_with_space(it, cx), + name = it.name.unwrap(), + generics = t.generics.print(cx), + where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), + type_ = t.type_.print(cx), + ); + }); write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 51f90e45500..7083999de68 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -668,7 +668,7 @@ fn get_index_type_id( } } // Not supported yet - clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None, + clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None, } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0bb073b1cea..e9c687b42fa 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1603,6 +1603,16 @@ a.tooltip:hover::after { border-color: var(--settings-button-border-focus); } +#settings-menu > a { + line-height: 0; + font-size: 0; +} +#settings-menu > a:before { + content: url('wheel-63255fc4502dca9a.svg'); + width: 22px; + height: 22px; +} + #sidebar-button > a:before { content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \ fill="none" stroke="black">\ @@ -1622,11 +1632,17 @@ a.tooltip:hover::after { padding-left: 2px; border: 0; width: 33px; + line-height: 0; + font-size: 0; } -#copy-path > img { + +#copy-path:before { filter: var(--copy-path-img-filter); + content: url('clipboard-24048e6d87f63d07.svg'); + width: 19px; + height: 18px; } -#copy-path:hover > img { +#copy-path:hover:before { filter: var(--copy-path-img-hover-filter); } diff --git a/src/librustdoc/html/static/images/clipboard.svg b/src/librustdoc/html/static/images/clipboard.svg index 8adbd996304..e437c83fb6b 100644 --- a/src/librustdoc/html/static/images/clipboard.svg +++ b/src/librustdoc/html/static/images/clipboard.svg @@ -1 +1 @@ -<svg width="24" height="25" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard"><path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/><path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/></svg> +<svg width="19" height="18" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard"><path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/><path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/></svg> diff --git a/src/librustdoc/html/static/images/favicon-16x16.png b/src/librustdoc/html/static/images/favicon-16x16.png deleted file mode 100644 index ea4b45cae16..00000000000 --- a/src/librustdoc/html/static/images/favicon-16x16.png +++ /dev/null Binary files differdiff --git a/src/librustdoc/html/static/images/wheel.svg b/src/librustdoc/html/static/images/wheel.svg index 83c07f63d10..ba30f13dd58 100644 --- a/src/librustdoc/html/static/images/wheel.svg +++ b/src/librustdoc/html/static/images/wheel.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="27.434" height="29.5" enable-background="new 0 0 27.434 29.5" viewBox="0 0 27.434 29.5"><path d="M27.316 18.39a2.696 2.696 0 0 0-.98-1.46 1.62 1.62 0 0 1-.016-.762l.035-.176v-1.191c0-1.246-.003-1.278-.046-1.473a1.717 1.717 0 0 1 .007-.805c.477-.343.829-.859.997-1.472.257-.957.074-2.094-.508-3.117l-.594-1.032c-.746-1.304-1.965-2.117-3.18-2.117-.379 0-.75.078-1.086.235a1.958 1.958 0 0 1-.855-.391l-.102-.082-.117-.063-1.855-1.07-.094-.055-.106-.043c-.378-.156-.66-.41-.77-.554C17.919 1.172 16.349 0 14.297 0h-1.155c-2.043 0-3.61 1.152-3.75 2.723-.114.14-.391.382-.758.527l-.102.04-.094.05-1.94 1.066-.134.074-.117.094a2.019 2.019 0 0 1-.832.403 2.518 2.518 0 0 0-1.008-.211c-1.199 0-2.414.82-3.168 2.14l-.59 1.032c-.41.718-.64 1.523-.64 2.257-.004.953.36 1.758 1.012 2.258.035.152.058.445-.016.785-.04.168-.063.282-.063 1.563 0 1.148 0 1.148.016 1.261l.008.075.015.074c.075.344.047.64.012.8-.644.5-1.004 1.302-.992 2.259.008.726.238 1.52.648 2.242l.59 1.027c.758 1.332 1.965 2.16 3.149 2.16.324 0 .644-.062.937-.187.168.039.492.156.813.418l.11.086.124.07 2.047 1.156.102.059.105.043c.363.144.648.379.766.52.164 1.519 1.718 2.632 3.746 2.632h1.156c2.035 0 3.598-1.133 3.746-2.672.117-.144.402-.394.773-.55l.114-.047.101-.063 1.961-1.156.106-.063.097-.078c.309-.246.653-.37.832-.398.313.136.66.21 1.016.21 1.2 0 2.41-.82 3.164-2.14l.594-1.031c.59-1.028.777-2.164.52-3.117Zm-2.043 2.247-.59 1.031c-.437.766-1.105 1.25-1.636 1.25a.7.7 0 0 1-.371-.094 1.146 1.146 0 0 0-.567-.129c-.593 0-1.382.297-2.007.797l-1.961 1.156c-1.016.426-1.848 1.293-1.848 1.93 0 .64-.898 1.16-1.996 1.16H13.14c-1.102 0-2-.515-2-1.14 0-.63-.832-1.477-1.852-1.887l-2.047-1.16c-.637-.512-1.426-.813-2.008-.813-.199 0-.379.035-.515.114a.648.648 0 0 1-.332.085c-.52 0-1.18-.5-1.621-1.273l-.59-1.031c-.543-.953-.555-1.98-.024-2.285.532-.305.782-1.434.551-2.504V14.8c0-1.09.02-1.18.02-1.18.238-1.074-.008-2.203-.551-2.516-.54-.304-.54-1.34.008-2.293l.59-1.03c.437-.766 1.101-1.255 1.636-1.255a.73.73 0 0 1 .364.094c.152.086.343.125.566.125.594 0 1.379-.297 2.004-.793l1.945-1.066c1.02-.407 1.856-1.278 1.856-1.934 0-.656.898-1.191 2-1.191h1.156c1.098 0 1.996.543 1.996 1.21 0 .669.832 1.555 1.848 1.973L20 6.012c.617.492 1.402.777 2.012.777.242 0 .453-.047.62-.14a.79.79 0 0 1 .403-.102c.55 0 1.223.476 1.652 1.23l.59 1.032c.543.953.52 2.004-.062 2.336-.574.332-.86 1.48-.625 2.554 0 0 .008.04.008 1.102v1.011c-.215 1.051.07 2.176.636 2.5.567.325.586 1.368.04 2.325Zm0 0"/><path d="M13.61 7.61a7.084 7.084 0 0 0-7.083 7.085 7.085 7.085 0 1 0 14.168 0A7.088 7.088 0 0 0 13.61 7.61Zm0 12.41a5.33 5.33 0 0 1-5.325-5.325 5.33 5.33 0 0 1 5.324-5.32 5.327 5.327 0 0 1 5.325 5.32 5.328 5.328 0 0 1-5.325 5.325Zm0 0"/><path d="M13.684 9.906a4.722 4.722 0 0 0-4.72 4.719 4.722 4.722 0 0 0 4.72 4.719 4.724 4.724 0 0 0 4.714-4.719 4.724 4.724 0 0 0-4.714-4.719Zm0 7.676a2.954 2.954 0 1 1 0-5.91 2.953 2.953 0 0 1 2.953 2.953 2.957 2.957 0 0 1-2.953 2.957Zm0 0"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" enable-background="new 0 0 22 22" viewBox="0 0 27.434 29.5"><path d="M27.316 18.39a2.696 2.696 0 0 0-.98-1.46 1.62 1.62 0 0 1-.016-.762l.035-.176v-1.191c0-1.246-.003-1.278-.046-1.473a1.717 1.717 0 0 1 .007-.805c.477-.343.829-.859.997-1.472.257-.957.074-2.094-.508-3.117l-.594-1.032c-.746-1.304-1.965-2.117-3.18-2.117-.379 0-.75.078-1.086.235a1.958 1.958 0 0 1-.855-.391l-.102-.082-.117-.063-1.855-1.07-.094-.055-.106-.043c-.378-.156-.66-.41-.77-.554C17.919 1.172 16.349 0 14.297 0h-1.155c-2.043 0-3.61 1.152-3.75 2.723-.114.14-.391.382-.758.527l-.102.04-.094.05-1.94 1.066-.134.074-.117.094a2.019 2.019 0 0 1-.832.403 2.518 2.518 0 0 0-1.008-.211c-1.199 0-2.414.82-3.168 2.14l-.59 1.032c-.41.718-.64 1.523-.64 2.257-.004.953.36 1.758 1.012 2.258.035.152.058.445-.016.785-.04.168-.063.282-.063 1.563 0 1.148 0 1.148.016 1.261l.008.075.015.074c.075.344.047.64.012.8-.644.5-1.004 1.302-.992 2.259.008.726.238 1.52.648 2.242l.59 1.027c.758 1.332 1.965 2.16 3.149 2.16.324 0 .644-.062.937-.187.168.039.492.156.813.418l.11.086.124.07 2.047 1.156.102.059.105.043c.363.144.648.379.766.52.164 1.519 1.718 2.632 3.746 2.632h1.156c2.035 0 3.598-1.133 3.746-2.672.117-.144.402-.394.773-.55l.114-.047.101-.063 1.961-1.156.106-.063.097-.078c.309-.246.653-.37.832-.398.313.136.66.21 1.016.21 1.2 0 2.41-.82 3.164-2.14l.594-1.031c.59-1.028.777-2.164.52-3.117Zm-2.043 2.247-.59 1.031c-.437.766-1.105 1.25-1.636 1.25a.7.7 0 0 1-.371-.094 1.146 1.146 0 0 0-.567-.129c-.593 0-1.382.297-2.007.797l-1.961 1.156c-1.016.426-1.848 1.293-1.848 1.93 0 .64-.898 1.16-1.996 1.16H13.14c-1.102 0-2-.515-2-1.14 0-.63-.832-1.477-1.852-1.887l-2.047-1.16c-.637-.512-1.426-.813-2.008-.813-.199 0-.379.035-.515.114a.648.648 0 0 1-.332.085c-.52 0-1.18-.5-1.621-1.273l-.59-1.031c-.543-.953-.555-1.98-.024-2.285.532-.305.782-1.434.551-2.504V14.8c0-1.09.02-1.18.02-1.18.238-1.074-.008-2.203-.551-2.516-.54-.304-.54-1.34.008-2.293l.59-1.03c.437-.766 1.101-1.255 1.636-1.255a.73.73 0 0 1 .364.094c.152.086.343.125.566.125.594 0 1.379-.297 2.004-.793l1.945-1.066c1.02-.407 1.856-1.278 1.856-1.934 0-.656.898-1.191 2-1.191h1.156c1.098 0 1.996.543 1.996 1.21 0 .669.832 1.555 1.848 1.973L20 6.012c.617.492 1.402.777 2.012.777.242 0 .453-.047.62-.14a.79.79 0 0 1 .403-.102c.55 0 1.223.476 1.652 1.23l.59 1.032c.543.953.52 2.004-.062 2.336-.574.332-.86 1.48-.625 2.554 0 0 .008.04.008 1.102v1.011c-.215 1.051.07 2.176.636 2.5.567.325.586 1.368.04 2.325Zm0 0"/><path d="M13.61 7.61a7.084 7.084 0 0 0-7.083 7.085 7.085 7.085 0 1 0 14.168 0A7.088 7.088 0 0 0 13.61 7.61Zm0 12.41a5.33 5.33 0 0 1-5.325-5.325 5.33 5.33 0 0 1 5.324-5.32 5.327 5.327 0 0 1 5.325 5.32 5.328 5.328 0 0 1-5.325 5.325Zm0 0"/><path d="M13.684 9.906a4.722 4.722 0 0 0-4.72 4.719 4.722 4.722 0 0 0 4.72 4.719 4.724 4.724 0 0 0 4.714-4.719 4.724 4.724 0 0 0-4.714-4.719Zm0 7.676a2.954 2.954 0 1 1 0-5.91 2.953 2.953 0 0 1 2.953 2.953 2.957 2.957 0 0 1-2.953 2.957Zm0 0"/></svg> \ No newline at end of file diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index ca9a78f51b3..d8874c2fda0 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -106,7 +106,6 @@ static_files! { license_mit => "static/LICENSE-MIT.txt", rust_logo_svg => "static/images/rust-logo.svg", rust_favicon_svg => "static/images/favicon.svg", - rust_favicon_png_16 => "static/images/favicon-16x16.png", rust_favicon_png_32 => "static/images/favicon-32x32.png", fira_sans_regular => "static/fonts/FiraSans-Regular.woff2", fira_sans_medium => "static/fonts/FiraSans-Medium.woff2", diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 0f3debae66c..1dc9041658e 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -6,13 +6,9 @@ <meta name="generator" content="rustdoc"> {# #} <meta name="description" content="{{page.description}}"> {# #} <title>{{page.title}}</title> {# #} - <script> if (window.location.protocol !== "file:") document.write(` {# Hack to skip preloading fonts locally - see #98769 #} - <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {# #} - <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {# #} - <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_medium}}"> {# #} - <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_regular}}"> {# #} - <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_semibold}}"> {# #} - `)</script> {# #} + <script>if(window.location.protocol!=="file:") {# Hack to skip preloading fonts locally - see #98769 #} + document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_regular}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #} + </script> {# #} <link rel="stylesheet" {#+ #} href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #} <link rel="stylesheet" {#+ #} @@ -62,8 +58,6 @@ <link rel="icon" href="{{layout.favicon}}"> {# #} {% else %} <link rel="alternate icon" type="image/png" {#+ #} - href="{{static_root_path|safe}}{{files.rust_favicon_png_16}}"> {# #} - <link rel="alternate icon" type="image/png" {#+ #} href="{{static_root_path|safe}}{{files.rust_favicon_png_32}}"> {# #} <link rel="icon" type="image/svg+xml" {#+ #} href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {# #} @@ -114,13 +108,13 @@ <div class="version">{{+ display_krate_version_extra}}</div> {# #} {% endif %} {% else %} - <div class="src-sidebar-title"> + <div class="src-sidebar-title"> {# #} <h2>Files</h2> {# #} </div> {# #} {% endif %} {{ sidebar|safe }} </nav> {# #} - <div class="sidebar-resizer"></div> + <div class="sidebar-resizer"></div> {# #} <main> {# #} {% if page.css_class != "src" %}<div class="width-limiter">{% endif %} <nav class="sub"> {# #} @@ -142,8 +136,7 @@ </div> {# #} <div id="settings-menu" tabindex="-1"> {# #} <a href="{{page.root_path|safe}}settings.html" title="settings"> {# #} - <img width="22" height="22" alt="Change settings" {#+ #} - src="{{static_root_path|safe}}{{files.wheel_svg}}"> {# #} + Settings {# #} </a> {# #} </div> {# #} </form> {# #} diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index 1d215c26968..76e770453b6 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -7,9 +7,7 @@ {% endfor %} <a class="{{item_type}}" href="#">{{name}}</a> {# #} <button id="copy-path" title="Copy item path to clipboard"> {# #} - <img src="{{static_root_path|safe}}{{clipboard_svg}}" {#+ #} - width="19" height="18" {#+ #} - alt="Copy item path"> {# #} + Copy item path {# #} </button> {# #} </h1> {# #} <span class="out-of-band"> diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index d982134181c..3251b4c14c9 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -5,7 +5,7 @@ {% endif %} <div class="sidebar-elems"> {% if is_crate %} - <ul class="block"> + <ul class="block"> {# #} <li><a id="all-types" href="all.html">All Items</a></li> {# #} </ul> {% endif %} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index cb50a27326f..35b99ab46f0 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -573,6 +573,10 @@ impl FromWithTcx<clean::Type> for Type { Tuple(t) => Type::Tuple(t.into_tcx(tcx)), Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() }, + clean::Type::Pat(t, p) => Type::Pat { + type_: Box::new((*t).into_tcx(tcx)), + __pat_unstable_do_not_use: p.to_string(), + }, ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a5c26429013..1ba4e6cbdf0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -491,6 +491,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::Str => Res::Primitive(Str), ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), ty::Tuple(_) => Res::Primitive(Tuple), + ty::Pat(..) => Res::Primitive(Pat), ty::Array(..) => Res::Primitive(Array), ty::Slice(_) => Res::Primitive(Slice), ty::RawPtr(_, _) => Res::Primitive(RawPointer), @@ -536,8 +537,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { I64 => tcx.types.i64, I128 => tcx.types.i128, Isize => tcx.types.isize, + F16 => tcx.types.f16, F32 => tcx.types.f32, F64 => tcx.types.f64, + F128 => tcx.types.f128, U8 => tcx.types.u8, U16 => tcx.types.u16, U32 => tcx.types.u32, @@ -2196,8 +2199,10 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> { "u32" => U32, "u64" => U64, "u128" => U128, + "f16" => F16, "f32" => F32, "f64" => F64, + "f128" => F128, "char" => Char, "bool" | "true" | "false" => Bool, "str" | "&str" => Str, diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index fbbb6152cfe..c92cf9d3e80 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -122,7 +122,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> _ => true, } }) { - let impls = get_auto_trait_and_blanket_impls(cx, def_id); + let impls = synthesize_auto_trait_and_blanket_impls(cx, def_id); new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id))); } } @@ -230,8 +230,10 @@ impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? if !self.cx.tcx.is_doc_hidden(i.item_id.expect_def_id()) { - self.impls - .extend(get_auto_trait_and_blanket_impls(self.cx, i.item_id.expect_def_id())); + self.impls.extend(synthesize_auto_trait_and_blanket_impls( + self.cx, + i.item_id.expect_def_id(), + )); } } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 569c17ee36e..09886024595 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -6,7 +6,7 @@ use rustc_errors::SuggestionStyle; use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; use rustc_hir::HirId; use rustc_lint_defs::Applicability; -use rustc_resolve::rustdoc::source_span_for_markdown_range; +use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, source_span_for_markdown_range}; use rustc_span::def_id::DefId; use rustc_span::Symbol; @@ -29,16 +29,13 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { return; }; - let doc = item.doc_value(); - if doc.is_empty() { - return; - } - - if let Some(item_id) = item.def_id() { - check_redundant_explicit_link_for_did(cx, item, item_id, hir_id, &doc); - } - if let Some(item_id) = item.inline_stmt_id { - check_redundant_explicit_link_for_did(cx, item, item_id, hir_id, &doc); + let hunks = prepare_to_doc_link_resolution(&item.attrs.doc_strings); + for (item_id, doc) in hunks { + if let Some(item_id) = item_id.or(item.def_id()) + && !doc.is_empty() + { + check_redundant_explicit_link_for_did(cx, item, item_id, hir_id, &doc); + } } } diff --git a/src/llvm-project b/src/llvm-project -Subproject 0af6c732ec6ca189cd7725e4a7d4290793046e8 +Subproject af8f9eb61a2ad4ee1f2d3f46d157b93a47c6a4b diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 164f88faa31..89d6f8d67f1 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 28; +pub const FORMAT_VERSION: u32 = 29; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -562,6 +562,13 @@ pub enum Type { type_: Box<Type>, len: String, }, + /// `u32 is 1..` + Pat { + #[serde(rename = "type")] + type_: Box<Type>, + #[doc(hidden)] + __pat_unstable_do_not_use: String, + }, /// `impl TraitA + TraitB + ...` ImplTrait(Vec<GenericBound>), /// `_` diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 28e7b2bc0a812f90126be30f48a00a4ada990ea +Subproject 48eca1b164695022295ce466b64b44e4e0228b0 diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 560b2acc1c7..f83fb1b9019 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -821,6 +821,7 @@ impl TyCoercionStability { | TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) + | TyKind::Pat(..) | TyKind::Never | TyKind::Tup(_) | TyKind::Path(_) => Self::Deref, @@ -869,6 +870,7 @@ impl TyCoercionStability { | ty::Int(_) | ty::Uint(_) | ty::Array(..) + | ty::Pat(..) | ty::Float(_) | ty::RawPtr(..) | ty::FnPtr(_) diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 0599afca09f..790bed580fd 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -71,7 +71,7 @@ impl LateLintPass<'_> for LargeIncludeFile { span_lint_and_note( cx, LARGE_INCLUDE_FILE, - expr.span, + expr.span.source_callsite(), "attempted to include a large file", None, format!( diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index a60a40a2a47..2bb63ec2b04 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -294,8 +294,7 @@ fn elision_suggestions( let span = cx .sess() .source_map() - .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace()) - .unwrap_or(usage.ident.span); + .span_extend_while_whitespace(usage.ident.span); (span, String::new()) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 23fc323446e..d3347466be9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -12,7 +12,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; -use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -437,9 +436,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) - && let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id) - && fn_ctxt.can_coerce(ty, output_ty) + && rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { return false; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index f5ce8dd29b1..3cf054e7207 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { /// /// ### Known problems /// The lint does not work properly with desugaring and - /// macro, it has been allowed in the mean time. + /// macro, it has been allowed in the meantime. /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index b3c729dacdd..3aa979cb11b 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -300,7 +300,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on `include_str!(..)`", "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen( + snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability).replacen( "include_str", "include_bytes", 1, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 6f5ac625e35..a6a6e9a3bac 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,4 +1,4 @@ -use super::utils::check_cast; +use rustc_hir_typeck::cast::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; - let mut sugg = match check_cast(cx, e, from_ty, to_ty) { + let mut sugg = match check_cast(cx.tcx, cx.param_env, e, from_ty, to_ty) { Some(FnPtrAddrCast | PtrAddrCast) if const_context => return false, Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 15f1890aa39..e8ccd35b4da 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,10 +1,5 @@ -use rustc_hir as hir; -use rustc_hir::Expr; -use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt}; use rustc_lint::LateContext; -use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; -use rustc_span::DUMMY_SP; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment @@ -20,35 +15,3 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx false } } - -/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of -/// the cast. In certain cases, including some invalid casts from array references -/// to pointers, this may cause additional errors to be emitted and/or ICE error -/// messages. This function will panic if that occurs. -pub(super) fn check_cast<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, -) -> Option<CastKind> { - let hir_id = e.hir_id; - let local_def_id = hir_id.owner.def_id; - - let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id); - let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id); - - if let Ok(check) = cast::CastCheck::new( - &fn_ctxt, - e, - from_ty, - to_ty, - // We won't show any error to the user, so we don't care what the span is here. - DUMMY_SP, - DUMMY_SP, - hir::Constness::NotConst, - ) { - check.do_check(&fn_ctxt).ok() - } else { - None - } -} diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f8bbe997774..6c3d9329932 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1068,6 +1068,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(ty); self.hash_array_length(len); }, + TyKind::Pat(ty, pat) => { + self.hash_ty(ty); + self.hash_pat(pat); + }, TyKind::Ptr(ref mut_ty) => { self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index b84f4e87e07..763ce59ba1d 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -4,7 +4,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: the compiler unexpectedly panicked. this is a bug. -note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the mean time +note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the meantime | = note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists = note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr index b45cb11939f..34224065f07 100644 --- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr +++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr @@ -7,7 +7,6 @@ LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); = note: the configuration allows a maximum size of 600 bytes = note: `-D clippy::large-include-file` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]` - = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) error: attempted to include a large file --> tests/ui-toml/large_include_file/large_include_file.rs:14:35 @@ -16,7 +15,6 @@ LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes - = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/empty_docs.stderr b/src/tools/clippy/tests/ui/empty_docs.stderr index 28ebea22c5d..5fd7272d7c1 100644 --- a/src/tools/clippy/tests/ui/empty_docs.stderr +++ b/src/tools/clippy/tests/ui/empty_docs.stderr @@ -25,19 +25,20 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:30:5 + --> tests/ui/empty_docs.rs:30:13 | LL | #[doc = ""] - | ^^^^^^^^^^^ + | ^^ | = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:33:5 + --> tests/ui/empty_docs.rs:33:13 | -LL | / #[doc = ""] +LL | #[doc = ""] + | _____________^ LL | | #[doc = ""] - | |_______________^ + | |______________^ | = help: consider removing or filling it diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 4539c9b3285..38c29b91928 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -20,7 +20,7 @@ tracing-subscriber = { version = "0.3.3", default-features = false, features = [ regex = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -rustfix = "0.6.0" +rustfix = "0.8.1" once_cell = "1.16.0" walkdir = "2" glob = "0.3.0" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 78246136f2a..aa69791b3b4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -69,6 +69,7 @@ string_enum! { Assembly => "assembly", CoverageMap => "coverage-map", CoverageRun => "coverage-run", + Crashes => "crashes", } } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e414bc384f1..f78e0363f55 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -266,7 +266,7 @@ impl TestProps { aux_crates: vec![], revisions: vec![], rustc_env: vec![("RUSTC_ICE".to_string(), "0".to_string())], - unset_rustc_env: vec![], + unset_rustc_env: vec![("RUSTC_LOG_COLOR".to_string())], exec_env: vec![], unset_exec_env: vec![], build_aux_docs: false, @@ -581,6 +581,16 @@ impl TestProps { self.incremental = true; } + if config.mode == Mode::Crashes { + // we don't want to pollute anything with backtrace-files + // also turn off backtraces in order to save some execution + // time on the tests; we only need to know IF it crashes + self.rustc_env = vec![ + ("RUST_BACKTRACE".to_string(), "0".to_string()), + ("RUSTC_ICE".to_string(), "0".to_string()), + ]; + } + for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { if let Ok(val) = env::var(key) { if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() { @@ -596,7 +606,8 @@ impl TestProps { fn update_fail_mode(&mut self, ln: &str, config: &Config) { let check_ui = |mode: &str| { - if config.mode != Mode::Ui { + // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows + if config.mode != Mode::Ui && config.mode != Mode::Crashes { panic!("`{}-fail` header is only supported in UI tests", mode); } }; @@ -625,6 +636,7 @@ impl TestProps { fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) { let check_no_run = |s| match (config.mode, s) { (Mode::Ui, _) => (), + (Mode::Crashes, _) => (), (Mode::Codegen, "build-pass") => (), (Mode::Incremental, _) => { if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) { @@ -757,6 +769,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-mode-codegen-units", "ignore-mode-coverage-map", "ignore-mode-coverage-run", + "ignore-mode-crashes", "ignore-mode-debuginfo", "ignore-mode-incremental", "ignore-mode-js-doc-test", @@ -790,15 +803,18 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-thumb", "ignore-thumbv8m.base-none-eabi", "ignore-thumbv8m.main-none-eabi", + "ignore-tvos", "ignore-unix", "ignore-unknown", "ignore-uwp", + "ignore-visionos", "ignore-vxworks", "ignore-wasi", "ignore-wasm", "ignore-wasm32", "ignore-wasm32-bare", "ignore-wasm64", + "ignore-watchos", "ignore-windows", "ignore-windows-gnu", "ignore-x32", @@ -819,6 +835,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-dynamic-linking", "needs-git-hash", "needs-llvm-components", + "needs-matching-clang", "needs-profiler-support", "needs-relocation-model-pic", "needs-run-enabled", @@ -855,6 +872,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-cdb", "only-gnu", "only-i686-pc-windows-msvc", + "only-ios", "only-linux", "only-loongarch64", "only-loongarch64-unknown-linux-gnu", @@ -870,10 +888,13 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-sparc64", "only-stable", "only-thumb", + "only-tvos", "only-unix", + "only-visionos", "only-wasm32", "only-wasm32-bare", "only-wasm32-wasip1", + "only-watchos", "only-windows", "only-x86", "only-x86_64", @@ -934,16 +955,25 @@ struct HeaderLine<'ln> { pub(crate) struct CheckDirectiveResult<'ln> { is_known_directive: bool, directive_name: &'ln str, + trailing_directive: Option<&'ln str>, } -// Returns `(is_known_directive, directive_name)`. pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> { - let directive_name = - directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln); + let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, "")); + + let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post); + let trailing_directive = { + // 1. is the directive name followed by a space? (to exclude `:`) + matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" ")) + // 2. is what is after that directive also a directive (ex: "only-x86 only-arm") + && KNOWN_DIRECTIVE_NAMES.contains(&trailing) + } + .then_some(trailing); CheckDirectiveResult { is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name), directive_name: directive_ln, + trailing_directive, } } @@ -1013,7 +1043,8 @@ fn iter_header( if testfile.extension().map(|e| e == "rs").unwrap_or(false) { let directive_ln = non_revisioned_directive_line.trim(); - let CheckDirectiveResult { is_known_directive, .. } = check_directive(directive_ln); + let CheckDirectiveResult { is_known_directive, trailing_directive, .. } = + check_directive(directive_ln); if !is_known_directive { *poisoned = true; @@ -1027,6 +1058,21 @@ fn iter_header( return; } + + if let Some(trailing_directive) = &trailing_directive { + *poisoned = true; + + eprintln!( + "error: detected trailing compiletest test directive `{}` in {}:{}\n \ + help: put the trailing directive in it's own line: `//@ {}`", + trailing_directive, + testfile.display(), + line_number, + trailing_directive, + ); + + return; + } } it(HeaderLine { @@ -1050,7 +1096,8 @@ fn iter_header( let rest = rest.trim_start(); - let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest); + let CheckDirectiveResult { is_known_directive, directive_name, .. } = + check_directive(rest); if is_known_directive { *poisoned = true; diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 83f0755b5c8..8a37a4d6d31 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -667,3 +667,24 @@ fn test_non_rs_unknown_directive_not_checked() { ); assert!(!poisoned); } + +#[test] +fn test_trailing_directive() { + let mut poisoned = false; + run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm"); + assert!(poisoned); +} + +#[test] +fn test_trailing_directive_with_comment() { + let mut poisoned = false; + run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm with comment"); + assert!(poisoned); +} + +#[test] +fn test_not_trailing_directive() { + let mut poisoned = false; + run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental"); + assert!(!poisoned); +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 1624e2a6084..c8a8b79921e 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -65,7 +65,8 @@ pub fn parse_config(args: Vec<String>) -> Config { "mode", "which sort of compile tests to run", "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + | rustdoc-json | codegen-units | incremental | run-make | ui \ + | js-doc-test | mir-opt | assembly | crashes", ) .reqopt( "", @@ -82,7 +83,12 @@ pub fn parse_config(args: Vec<String>) -> Config { .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") .optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header") - .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") + .optmulti( + "", + "skip", + "skip tests matching SUBSTRING. Can be passed multiple times", + "SUBSTRING", + ) .optflag("", "exact", "filters match exactly") .optopt( "", @@ -145,7 +151,11 @@ pub fn parse_config(args: Vec<String>) -> Config { .optflag("", "profiler-support", "is the profiler runtime enabled for this target") .optflag("h", "help", "show this message") .reqopt("", "channel", "current Rust channel", "CHANNEL") - .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries") + .optflag( + "", + "git-hash", + "run tests which rely on commit version being compiled into the binaries", + ) .optopt("", "edition", "default Rust edition", "EDITION") .reqopt("", "git-repository", "name of the git repository", "ORG/REPO") .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH"); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 689fdc5dfeb..38d22fef113 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -4,7 +4,7 @@ use crate::common::{ expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, }; use crate::common::{incremental_dir, output_base_dir, output_base_name, output_testname_unique}; -use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; +use crate::common::{Assembly, Crashes, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; @@ -244,7 +244,7 @@ impl<'test> TestCx<'test> { /// Code executed for each revision in turn (or, if there are no /// revisions, exactly once, with revision == None). fn run_revision(&self) { - if self.props.should_ice && self.config.mode != Incremental { + if self.props.should_ice && self.config.mode != Incremental && self.config.mode != Crashes { self.fatal("cannot use should-ice in a test that is not cfail"); } match self.config.mode { @@ -263,6 +263,7 @@ impl<'test> TestCx<'test> { JsDocTest => self.run_js_doc_test(), CoverageMap => self.run_coverage_map_test(), CoverageRun => self.run_coverage_run_test(), + Crashes => self.run_crash_test(), } } @@ -295,6 +296,7 @@ impl<'test> TestCx<'test> { match self.config.mode { JsDocTest => true, Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build), + Crashes => false, Incremental => { let revision = self.revision.expect("incremental tests require a list of revisions"); @@ -359,6 +361,27 @@ impl<'test> TestCx<'test> { self.check_forbid_output(&output_to_check, &proc_res); } + fn run_crash_test(&self) { + let pm = self.pass_mode(); + let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); + + if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() { + eprintln!("{}", proc_res.status); + eprintln!("{}", proc_res.stdout); + eprintln!("{}", proc_res.stderr); + eprintln!("{}", proc_res.cmdline); + } + + // if a test does not crash, consider it an error + if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { + self.fatal(&format!( + "test no longer crashes/triggers ICE! Please give it a mearningful name, \ + add a doc-comment to the start of the test explaining why it exists and \ + move it to tests/ui or wherever you see fit." + )); + } + } + fn run_rfail_test(&self) { let pm = self.pass_mode(); let should_run = self.run_if_enabled(); @@ -752,6 +775,19 @@ impl<'test> TestCx<'test> { Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)+ Branch \()[0-9]+:").unwrap()); let coverage = BRANCH_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` + static MCDC_DECISION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| { + Regex::new(r"(?m:^)(?<prefix>(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?<middle>[0-9]+\) to \()[0-9]+:").unwrap() + }); + let coverage = + MCDC_DECISION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:${middle}LL:"); + + // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` + static MCDC_CONDITION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| { + Regex::new(r"(?m:^)(?<prefix>(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:").unwrap() + }); + let coverage = MCDC_CONDITION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + coverage.into_owned() } @@ -2354,6 +2390,11 @@ impl<'test> TestCx<'test> { "ignore-directory-in-diagnostics-source-blocks={}", home::cargo_home().expect("failed to find cargo home").to_str().unwrap() )); + // Similarly, vendored sources shouldn't be shown when running from a dist tarball. + rustc.arg("-Z").arg(format!( + "ignore-directory-in-diagnostics-source-blocks={}", + self.config.find_rust_src_root().unwrap().join("vendor").display(), + )); // Optionally prevent default --sysroot if specified in test compile-flags. if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) @@ -2499,7 +2540,7 @@ impl<'test> TestCx<'test> { rustc.arg("-Cdebug-assertions=no"); } RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake - | CodegenUnits | JsDocTest => { + | CodegenUnits | JsDocTest | Crashes => { // do not use JSON output } } @@ -3767,6 +3808,14 @@ impl<'test> TestCx<'test> { debug!(?support_lib_deps); debug!(?support_lib_deps_deps); + let orig_dylib_env_paths = + Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); + + let mut host_dylib_env_paths = Vec::new(); + host_dylib_env_paths.push(cwd.join(&self.config.compile_lib_path)); + host_dylib_env_paths.extend(orig_dylib_env_paths.iter().cloned()); + let host_dylib_env_paths = env::join_paths(host_dylib_env_paths).unwrap(); + let mut cmd = Command::new(&self.config.rustc_path); cmd.arg("-o") .arg(&recipe_bin) @@ -3783,6 +3832,7 @@ impl<'test> TestCx<'test> { .env("RUSTC", cwd.join(&self.config.rustc_path)) .env("TMPDIR", &tmpdir) .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) + .env(dylib_env_var(), &host_dylib_env_paths) .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) .env("LLVM_COMPONENTS", &self.config.llvm_components) @@ -3810,19 +3860,15 @@ impl<'test> TestCx<'test> { // Finally, we need to run the recipe binary to build and run the actual tests. debug!(?recipe_bin); - let mut dylib_env_paths = String::new(); - dylib_env_paths.push_str(&env::var(dylib_env_var()).unwrap()); - dylib_env_paths.push(':'); - dylib_env_paths.push_str(&support_lib_path.parent().unwrap().to_string_lossy()); - dylib_env_paths.push(':'); - dylib_env_paths.push_str( - &stage_std_path.join("rustlib").join(&self.config.host).join("lib").to_string_lossy(), - ); + let mut dylib_env_paths = orig_dylib_env_paths.clone(); + dylib_env_paths.push(support_lib_path.parent().unwrap().to_path_buf()); + dylib_env_paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); + let dylib_env_paths = env::join_paths(dylib_env_paths).unwrap(); - let mut target_rpath_env_path = String::new(); - target_rpath_env_path.push_str(&tmpdir.to_string_lossy()); - target_rpath_env_path.push(':'); - target_rpath_env_path.push_str(&dylib_env_paths); + let mut target_rpath_env_path = Vec::new(); + target_rpath_env_path.push(&tmpdir); + target_rpath_env_path.extend(&orig_dylib_env_paths); + let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap(); let mut cmd = Command::new(&recipe_bin); cmd.current_dir(&self.testpaths.file) @@ -4252,7 +4298,7 @@ impl<'test> TestCx<'test> { if self.props.run_rustfix && self.config.compare_mode.is_none() { // And finally, compile the fixed code and make sure it both // succeeds and has no diagnostics. - let rustc = self.make_compile_args( + let mut rustc = self.make_compile_args( &self.expected_output_path(UI_FIXED), TargetLocation::ThisFile(self.make_exe_name()), emit_metadata, @@ -4260,6 +4306,26 @@ impl<'test> TestCx<'test> { LinkToAux::Yes, Vec::new(), ); + + // If a test is revisioned, it's fixed source file can be named "a.foo.fixed", which, + // well, "a.foo" isn't a valid crate name. So we explicitly mangle the test name + // (including the revision) here to avoid the test writer having to manually specify a + // `#![crate_name = "..."]` as a workaround. This is okay since we're only checking if + // the fixed code is compilable. + if self.revision.is_some() { + let crate_name = + self.testpaths.file.file_stem().expect("test must have a file stem"); + // crate name must be alphanumeric or `_`. + let crate_name = + crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); + // replace `a.foo` -> `a__foo` for crate name purposes. + // replace `revision-name-with-dashes` -> `revision_name_with_underscore` + let crate_name = crate_name.replace(".", "__"); + let crate_name = crate_name.replace("-", "_"); + rustc.arg("--crate-name"); + rustc.arg(crate_name); + } + let res = self.compose_and_run_compiler(rustc, None); if !res.status.success() { self.fatal_proc_rec("failed to compile fixed code", &res); diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs index ee42243e83d..817b56109a5 100644 --- a/src/tools/compiletest/src/runtest/tests.rs +++ b/src/tools/compiletest/src/runtest/tests.rs @@ -50,72 +50,68 @@ fn normalize_platform_differences() { } /// Test for anonymizing line numbers in coverage reports, especially for -/// branch regions. +/// MC/DC regions. /// -/// FIXME(#119681): This test can be removed when we have examples of branch +/// FIXME(#123409): This test can be removed when we have examples of MC/DC /// coverage in the actual coverage test suite. #[test] fn anonymize_coverage_line_numbers() { let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage); let input = r#" - 6| 3|fn print_size<T>() { - 7| 3| if std::mem::size_of::<T>() > 4 { + 7| 2|fn mcdc_check_neither(a: bool, b: bool) { + 8| 2| if a && b { + ^0 ------------------ - | Branch (7:8): [True: 0, False: 1] - | Branch (7:8): [True: 0, False: 1] - | Branch (7:8): [True: 1, False: 0] + |---> MC/DC Decision Region (8:8) to (8:14) + | + | Number of Conditions: 2 + | Condition C1 --> (8:8) + | Condition C2 --> (8:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | + | C1-Pair: not covered + | C2-Pair: not covered + | MC/DC Coverage for Decision: 0.00% + | ------------------ - 8| 1| println!("size > 4"); + 9| 0| say("a and b"); + 10| 2| } else { + 11| 2| say("not both"); + 12| 2| } + 13| 2|} "#; let expected = r#" - LL| 3|fn print_size<T>() { - LL| 3| if std::mem::size_of::<T>() > 4 { + LL| 2|fn mcdc_check_neither(a: bool, b: bool) { + LL| 2| if a && b { + ^0 ------------------ - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:8): [True: 1, False: 0] - ------------------ - LL| 1| println!("size > 4"); -"#; - - assert_eq!(anon(input), expected); - - ////////// - - let input = r#" - 12| 3|} - ------------------ - | branch_generics::print_size::<()>: - | 6| 1|fn print_size<T>() { - | 7| 1| if std::mem::size_of::<T>() > 4 { - | ------------------ - | | Branch (7:8): [True: 0, False: 1] - | ------------------ - | 8| 0| println!("size > 4"); - | 9| 1| } else { - | 10| 1| println!("size <= 4"); - | 11| 1| } - | 12| 1|} - ------------------ -"#; - - let expected = r#" - LL| 3|} - ------------------ - | branch_generics::print_size::<()>: - | LL| 1|fn print_size<T>() { - | LL| 1| if std::mem::size_of::<T>() > 4 { - | ------------------ - | | Branch (LL:8): [True: 0, False: 1] - | ------------------ - | LL| 0| println!("size > 4"); - | LL| 1| } else { - | LL| 1| println!("size <= 4"); - | LL| 1| } - | LL| 1|} + |---> MC/DC Decision Region (LL:8) to (LL:14) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | + | C1-Pair: not covered + | C2-Pair: not covered + | MC/DC Coverage for Decision: 0.00% + | ------------------ + LL| 0| say("a and b"); + LL| 2| } else { + LL| 2| say("not both"); + LL| 2| } + LL| 2|} "#; assert_eq!(anon(input), expected); diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 49e3a6ed583..b308c8de14f 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -70,7 +70,8 @@ pub(crate) fn dump_covfun_mappings( } // If the mapping is a branch region, print both of its arms // in resolved form (even if they aren't expressions). - MappingKind::Branch { r#true, r#false } => { + MappingKind::Branch { r#true, r#false } + | MappingKind::MCDCBranch { r#true, r#false, .. } => { println!(" true = {}", expression_resolver.format_term(r#true)); println!(" false = {}", expression_resolver.format_term(r#false)); } @@ -164,6 +165,26 @@ impl<'a> Parser<'a> { let r#false = self.read_simple_term()?; Ok(MappingKind::Branch { r#true, r#false }) } + 5 => { + let bitmap_idx = self.read_uleb128_u32()?; + let conditions_num = self.read_uleb128_u32()?; + Ok(MappingKind::MCDCDecision { bitmap_idx, conditions_num }) + } + 6 => { + let r#true = self.read_simple_term()?; + let r#false = self.read_simple_term()?; + let condition_id = self.read_uleb128_u32()?; + let true_next_id = self.read_uleb128_u32()?; + let false_next_id = self.read_uleb128_u32()?; + Ok(MappingKind::MCDCBranch { + r#true, + r#false, + condition_id, + true_next_id, + false_next_id, + }) + } + _ => Err(anyhow!("unknown mapping kind: {raw_mapping_kind:#x}")), } } @@ -224,7 +245,28 @@ enum MappingKind { // Using raw identifiers here makes the dump output a little bit nicer // (via the derived Debug), at the expense of making this tool's source // code a little bit uglier. - Branch { r#true: CovTerm, r#false: CovTerm }, + Branch { + r#true: CovTerm, + r#false: CovTerm, + }, + MCDCBranch { + r#true: CovTerm, + r#false: CovTerm, + // These attributes are printed in Debug but not used directly. + #[allow(dead_code)] + condition_id: u32, + #[allow(dead_code)] + true_next_id: u32, + #[allow(dead_code)] + false_next_id: u32, + }, + MCDCDecision { + // These attributes are printed in Debug but not used directly. + #[allow(dead_code)] + bitmap_idx: u32, + #[allow(dead_code)] + conditions_num: u32, + }, } struct MappingRegion { diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs index 3fc72ecbbc4..60651734b9e 100644 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ b/src/tools/expand-yaml-anchors/src/main.rs @@ -2,11 +2,11 @@ use std::error::Error; use std::path::{Path, PathBuf}; use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; -/// List of directories containing files to expand. The first tuple element is the source -/// directory, while the second tuple element is the destination directory. +/// List of files to expand. The first tuple element is the source +/// file, while the second tuple element is the destination file. #[rustfmt::skip] static TO_EXPAND: &[(&str, &str)] = &[ - ("src/ci/github-actions", ".github/workflows"), + ("src/ci/github-actions/ci.yml", ".github/workflows/ci.yml"), ]; /// Name of a special key that will be removed from all the maps in expanded configuration files. @@ -62,27 +62,20 @@ impl App { fn run(&self) -> Result<(), Box<dyn Error>> { for (source, dest) in TO_EXPAND { let source = self.base.join(source); - let dest = self.base.join(dest); - for entry in std::fs::read_dir(&source)? { - let path = entry?.path(); - if !path.is_file() || path.extension().and_then(|e| e.to_str()) != Some("yml") { - continue; - } - - let dest_path = dest.join(path.file_name().unwrap()); - self.expand(&path, &dest_path).with_context(|| match self.mode { - Mode::Generate => format!( - "failed to expand {} into {}", - self.path(&path), - self.path(&dest_path) - ), - Mode::Check => format!( - "{} is not up to date; please run \ + let dest_path = self.base.join(dest); + + self.expand(&source, &dest_path).with_context(|| match self.mode { + Mode::Generate => format!( + "failed to expand {} into {}", + self.path(&source), + self.path(&dest_path) + ), + Mode::Check => format!( + "{} is not up to date; please run \ `x.py run src/tools/expand-yaml-anchors`.", - self.path(&dest_path) - ), - })?; - } + self.path(&dest_path) + ), + })?; } Ok(()) } diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 592e97310a4..9e08f7e5f9b 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -262,6 +262,7 @@ impl<'a> Validator<'a> { Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait), Type::Generic(_) => {} Type::Primitive(_) => {} + Type::Pat { type_, __pat_unstable_do_not_use: _ } => self.check_type(type_), Type::FunctionPointer(fp) => self.check_function_pointer(&**fp), Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)), Type::Slice(inner) => self.check_type(&**inner), diff --git a/src/tools/llvm-bitcode-linker/src/linker.rs b/src/tools/llvm-bitcode-linker/src/linker.rs index aa6b6443e4d..40572f22342 100644 --- a/src/tools/llvm-bitcode-linker/src/linker.rs +++ b/src/tools/llvm-bitcode-linker/src/linker.rs @@ -62,7 +62,7 @@ impl Session { .arg("-o") .arg(&self.link_path) .output() - .unwrap(); + .context("An error occured when calling llvm-link. Make sure the llvm-tools component is installed.")?; if !llvm_link_output.status.success() { tracing::error!( @@ -108,7 +108,9 @@ impl Session { opt_cmd.arg("--strip-debug"); } - let opt_output = opt_cmd.output().unwrap(); + let opt_output = opt_cmd.output().context( + "An error occured when calling opt. Make sure the llvm-tools component is installed.", + )?; if !opt_output.status.success() { tracing::error!( @@ -133,8 +135,11 @@ impl Session { lcc_command.arg("--mcpu").arg(mcpu); } - let lcc_output = - lcc_command.arg(&self.opt_path).arg("-o").arg(&self.out_path).output().unwrap(); + let lcc_output = lcc_command + .arg(&self.opt_path) + .arg("-o").arg(&self.out_path) + .output() + .context("An error occured when calling llc. Make sure the llvm-tools component is installed.")?; if !lcc_output.status.success() { tracing::error!( diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 67a5bf3d141..3f7a965e9df 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -32,8 +32,9 @@ use rustc_driver::Compilation; use rustc_hir::{self as hir, Node}; use rustc_interface::interface::Config; use rustc_middle::{ - middle::exported_symbols::{ - ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, + middle::{ + codegen_fn_attrs::CodegenFnAttrFlags, + exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel}, }, query::LocalCrate, ty::TyCtxt, @@ -136,6 +137,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { config.override_queries = Some(|_, local_providers| { // `exported_symbols` and `reachable_non_generics` provided by rustc always returns // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false. + // In addition we need to add #[used] symbols to exported_symbols for `lookup_link_section`. local_providers.exported_symbols = |tcx, LocalCrate| { let reachable_set = tcx.with_stable_hashing_context(|hcx| { tcx.reachable_set(()).to_sorted(&hcx, true) @@ -160,19 +162,28 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { }) if !tcx.generics_of(local_def_id).requires_monomorphization(tcx) ); - (is_reachable_non_generic - && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator()) - .then_some(( - ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - // Some dummy `SymbolExportInfo` here. We only use - // `exported_symbols` in shims/foreign_items.rs and the export info - // is ignored. - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Text, - used: false, - }, - )) + if !is_reachable_non_generic { + return None; + } + let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id); + if codegen_fn_attrs.contains_extern_indicator() + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + { + Some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + // Some dummy `SymbolExportInfo` here. We only use + // `exported_symbols` in shims/foreign_items.rs and the export info + // is ignored. + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Text, + used: false, + }, + )) + } else { + None + } }), ) } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index d0d73bb1b34..d1136272f01 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -158,7 +158,7 @@ pub struct Thread<'mir, 'tcx> { } pub type StackEmptyCallback<'mir, 'tcx> = - Box<dyn FnMut(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx, Poll<()>>>; + Box<dyn FnMut(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx, Poll<()>> + 'tcx>; impl<'mir, 'tcx> Thread<'mir, 'tcx> { /// Get the name of the current thread if it was set. diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index f7edbdb9c5e..df0ede1e1b6 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -192,18 +192,18 @@ impl Default for MiriConfig { /// The state of the main thread. Implementation detail of `on_main_stack_empty`. #[derive(Default, Debug)] -enum MainThreadState { +enum MainThreadState<'tcx> { #[default] Running, - TlsDtors(tls::TlsDtorsState), + TlsDtors(tls::TlsDtorsState<'tcx>), Yield { remaining: u32, }, Done, } -impl MainThreadState { - fn on_main_stack_empty<'tcx>( +impl<'tcx> MainThreadState<'tcx> { + fn on_main_stack_empty( &mut self, this: &mut MiriInterpCx<'_, 'tcx>, ) -> InterpResult<'tcx, Poll<()>> { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 998de80a7eb..e2c6769ccb5 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -9,16 +9,21 @@ use rand::RngCore; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; -use rustc_hir::def::{DefKind, Namespace}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::{ + def::{DefKind, Namespace}, + def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}, +}; use rustc_index::IndexVec; +use rustc_middle::middle::dependency_format::Linkage; +use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::mir; use rustc_middle::ty::{ self, layout::{LayoutOf, TyAndLayout}, FloatTy, IntTy, Ty, TyCtxt, UintTy, }; -use rustc_span::{def_id::CrateNum, sym, Span, Symbol}; +use rustc_session::config::CrateType; +use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -153,6 +158,38 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) None } +/// Call `f` for each exported symbol. +pub fn iter_exported_symbols<'tcx>( + tcx: TyCtxt<'tcx>, + mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>, +) -> InterpResult<'tcx> { + // `dependency_formats` includes all the transitive informations needed to link a crate, + // which is what we need here since we need to dig out `exported_symbols` from all transitive + // dependencies. + let dependency_formats = tcx.dependency_formats(()); + let dependency_format = dependency_formats + .iter() + .find(|(crate_type, _)| *crate_type == CrateType::Executable) + .expect("interpreting a non-executable crate"); + for cnum in iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( + |(num, &linkage)| { + // We add 1 to the number because that's what rustc also does everywhere it + // calls `CrateNum::new`... + #[allow(clippy::arithmetic_side_effects)] + (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) + }, + )) { + // We can ignore `_export_info` here: we are a Rust crate, and everything is exported + // from a Rust crate. + for &(symbol, _export_info) in tcx.exported_symbols(cnum) { + if let ExportedSymbol::NonGeneric(def_id) = symbol { + f(cnum, def_id)?; + } + } + } + Ok(()) +} + /// Convert a softfloat type to its corresponding hostfloat type. pub trait ToHost { type HostFloat; @@ -1189,6 +1226,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } Ok(()) } + + /// Lookup an array of immediates stored as a linker section of name `name`. + fn lookup_link_section( + &mut self, + name: &str, + ) -> InterpResult<'tcx, Vec<ImmTy<'tcx, Provenance>>> { + let this = self.eval_context_mut(); + let tcx = this.tcx.tcx; + + let mut array = vec![]; + + iter_exported_symbols(tcx, |_cnum, def_id| { + let attrs = tcx.codegen_fn_attrs(def_id); + let Some(link_section) = attrs.link_section else { + return Ok(()); + }; + if link_section.as_str() == name { + let instance = ty::Instance::mono(tcx, def_id); + let const_val = this.eval_global(instance).unwrap_or_else(|err| { + panic!( + "failed to evaluate static in required link_section: {def_id:?}\n{err:?}" + ) + }); + let val = this.read_immediate(&const_val)?; + array.push(val); + } + Ok(()) + })?; + + Ok(array) + } } impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index a25d377f3a7..6b0797f6da1 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -2,17 +2,10 @@ use std::{collections::hash_map::Entry, io::Write, iter, path::Path}; use rustc_apfloat::Float; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_hir::{ - def::DefKind, - def_id::{CrateNum, LOCAL_CRATE}, -}; -use rustc_middle::middle::{ - codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage, - exported_symbols::ExportedSymbol, -}; +use rustc_hir::{def::DefKind, def_id::CrateNum}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; -use rustc_session::config::CrateType; use rustc_span::Symbol; use rustc_target::{ abi::{Align, Size}, @@ -174,74 +167,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Entry::Vacant(e) => { // Find it if it was not cached. let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; - // `dependency_formats` includes all the transitive informations needed to link a crate, - // which is what we need here since we need to dig out `exported_symbols` from all transitive - // dependencies. - let dependency_formats = tcx.dependency_formats(()); - let dependency_format = dependency_formats - .iter() - .find(|(crate_type, _)| *crate_type == CrateType::Executable) - .expect("interpreting a non-executable crate"); - for cnum in iter::once(LOCAL_CRATE).chain( - dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { - // We add 1 to the number because that's what rustc also does everywhere it - // calls `CrateNum::new`... - #[allow(clippy::arithmetic_side_effects)] - (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) - }), - ) { - // We can ignore `_export_info` here: we are a Rust crate, and everything is exported - // from a Rust crate. - for &(symbol, _export_info) in tcx.exported_symbols(cnum) { - if let ExportedSymbol::NonGeneric(def_id) = symbol { - let attrs = tcx.codegen_fn_attrs(def_id); - let symbol_name = if let Some(export_name) = attrs.export_name { - export_name - } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - tcx.item_name(def_id) + helpers::iter_exported_symbols(tcx, |cnum, def_id| { + let attrs = tcx.codegen_fn_attrs(def_id); + let symbol_name = if let Some(export_name) = attrs.export_name { + export_name + } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + tcx.item_name(def_id) + } else { + // Skip over items without an explicitly defined symbol name. + return Ok(()); + }; + if symbol_name == link_name { + if let Some((original_instance, original_cnum)) = instance_and_crate { + // Make sure we are consistent wrt what is 'first' and 'second'. + let original_span = tcx.def_span(original_instance.def_id()).data(); + let span = tcx.def_span(def_id).data(); + if original_span < span { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: original_span, + first_crate: tcx.crate_name(original_cnum), + second: span, + second_crate: tcx.crate_name(cnum), + }); } else { - // Skip over items without an explicitly defined symbol name. - continue; - }; - if symbol_name == link_name { - if let Some((original_instance, original_cnum)) = instance_and_crate - { - // Make sure we are consistent wrt what is 'first' and 'second'. - let original_span = - tcx.def_span(original_instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); - if original_span < span { - throw_machine_stop!( - TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: original_span, - first_crate: tcx.crate_name(original_cnum), - second: span, - second_crate: tcx.crate_name(cnum), - } - ); - } else { - throw_machine_stop!( - TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: span, - first_crate: tcx.crate_name(cnum), - second: original_span, - second_crate: tcx.crate_name(original_cnum), - } - ); - } - } - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - throw_ub_format!( - "attempt to call an exported symbol that is not defined as a function" - ); - } - instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: span, + first_crate: tcx.crate_name(cnum), + second: original_span, + second_crate: tcx.crate_name(original_cnum), + }); } } + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { + throw_ub_format!( + "attempt to call an exported symbol that is not defined as a function" + ); + } + instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } - } + Ok(()) + })?; e.insert(instance_and_crate.map(|ic| ic.0)) } diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 7f929d9a91e..d25bae1cdc0 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -219,61 +219,76 @@ impl VisitProvenance for TlsData<'_> { } #[derive(Debug, Default)] -pub struct TlsDtorsState(TlsDtorsStatePriv); +pub struct TlsDtorsState<'tcx>(TlsDtorsStatePriv<'tcx>); #[derive(Debug, Default)] -enum TlsDtorsStatePriv { +enum TlsDtorsStatePriv<'tcx> { #[default] Init, PthreadDtors(RunningDtorState), + /// For Windows Dtors, we store the list of functions that we still have to call. + /// These are functions from the magic `.CRT$XLB` linker section. + WindowsDtors(Vec<ImmTy<'tcx, Provenance>>), Done, } -impl TlsDtorsState { - pub fn on_stack_empty<'tcx>( +impl<'tcx> TlsDtorsState<'tcx> { + pub fn on_stack_empty( &mut self, this: &mut MiriInterpCx<'_, 'tcx>, ) -> InterpResult<'tcx, Poll<()>> { use TlsDtorsStatePriv::*; - match &mut self.0 { - Init => { - match this.tcx.sess.target.os.as_ref() { - "linux" | "freebsd" | "android" => { - // Run the pthread dtors. - self.0 = PthreadDtors(Default::default()); + let new_state = 'new_state: { + match &mut self.0 { + Init => { + match this.tcx.sess.target.os.as_ref() { + "linux" | "freebsd" | "android" => { + // Run the pthread dtors. + break 'new_state PthreadDtors(Default::default()); + } + "macos" => { + // The macOS thread wide destructor runs "before any TLS slots get + // freed", so do that first. + this.schedule_macos_tls_dtor()?; + // When the stack is empty again, go on with the pthread dtors. + break 'new_state PthreadDtors(Default::default()); + } + "windows" => { + // Determine which destructors to run. + let dtors = this.lookup_windows_tls_dtors()?; + // And move to the final state. + break 'new_state WindowsDtors(dtors); + } + _ => { + // No TLS dtor support. + // FIXME: should we do something on wasi? + break 'new_state Done; + } } - "macos" => { - // The macOS thread wide destructor runs "before any TLS slots get - // freed", so do that first. - this.schedule_macos_tls_dtor()?; - // When the stack is empty again, go on with the pthread dtors. - self.0 = PthreadDtors(Default::default()); - } - "windows" => { - // Run the special magic hook. - this.schedule_windows_tls_dtors()?; - // And move to the final state. - self.0 = Done; + } + PthreadDtors(state) => { + match this.schedule_next_pthread_tls_dtor(state)? { + Poll::Pending => return Ok(Poll::Pending), // just keep going + Poll::Ready(()) => break 'new_state Done, } - _ => { - // No TLS dtor support. - // FIXME: should we do something on wasi? - self.0 = Done; + } + WindowsDtors(dtors) => { + if let Some(dtor) = dtors.pop() { + this.schedule_windows_tls_dtor(dtor)?; + return Ok(Poll::Pending); // we stay in this state (but `dtors` got shorter) + } else { + // No more destructors to run. + break 'new_state Done; } } - } - PthreadDtors(state) => { - match this.schedule_next_pthread_tls_dtor(state)? { - Poll::Pending => {} // just keep going - Poll::Ready(()) => self.0 = Done, + Done => { + this.machine.tls.delete_all_thread_tls(this.get_active_thread()); + return Ok(Poll::Ready(())); } } - Done => { - this.machine.tls.delete_all_thread_tls(this.get_active_thread()); - return Ok(Poll::Ready(())); - } - } + }; + self.0 = new_state; Ok(Poll::Pending) } } @@ -282,22 +297,19 @@ impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriInterpCx<'m trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Schedule TLS destructors for Windows. /// On windows, TLS destructors are managed by std. - fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { + fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec<ImmTy<'tcx, Provenance>>> { let this = self.eval_context_mut(); // Windows has a special magic linker section that is run on certain events. - // Instead of searching for that section and supporting arbitrary hooks in there - // (that would be basically https://github.com/rust-lang/miri/issues/450), - // we specifically look up the static in libstd that we know is placed - // in that section. - if !this.have_module(&["std"]) { - // Looks like we are running in a `no_std` crate. - // That also means no TLS dtors callback to call. - return Ok(()); - } - let thread_callback = - this.eval_windows("thread_local_key", "p_thread_callback").to_pointer(this)?; - let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?; + // We don't support most of that, but just enough to make thread-local dtors in `std` work. + Ok(this.lookup_link_section(".CRT$XLB")?) + } + + fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let dtor = dtor.to_scalar().to_pointer(this)?; + let thread_callback = this.get_ptr_fn(dtor)?.as_instance()?; // FIXME: Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits // but std treats both the same. @@ -305,7 +317,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. // FIXME: `h` should be a handle to the current module and what `pv` should be is unknown - // but both are ignored by std + // but both are ignored by std. this.call_function( thread_callback, Abi::System { unwind: false }, diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 8a8f98a5eda..46b0a543802 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -96,6 +96,7 @@ llvm-config = "{llvm_config}" "tests/pretty", "tests/run-pass-valgrind", "tests/ui", + "tests/crashes", ]; for test_path in env.skipped_tests() { args.extend(["--skip", test_path]); diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs index 2c9ad4f1700..a2d51902652 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/cc.rs @@ -1,6 +1,6 @@ use std::env; use std::path::Path; -use std::process::{Command, Output}; +use std::process::Command; use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname}; @@ -19,6 +19,8 @@ pub struct Cc { cmd: Command, } +crate::impl_common_helpers!(Cc); + impl Cc { /// Construct a new platform-specific C compiler invocation. /// @@ -43,22 +45,6 @@ impl Cc { self } - /// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various - /// possible C compilers on the various platforms to check which arguments are legal for - /// which compiler. - pub fn arg(&mut self, flag: &str) -> &mut Self { - self.cmd.arg(flag); - self - } - - /// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the - /// various possible C compilers on the various platforms to check which arguments are legal - /// for which compiler. - pub fn args(&mut self, args: &[&str]) -> &mut Self { - self.cmd.args(args); - self - } - /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable /// is under `$TMPDIR`. pub fn out_exe(&mut self, name: &str) -> &mut Self { @@ -85,25 +71,6 @@ impl Cc { self } - - /// Run the constructed C invocation command and assert that it is successfully run. - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } - - /// Inspect what the underlying [`Command`] is up to the current construction. - pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { - f(&self.cmd); - self - } } /// `EXTRACFLAGS` diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e70acf58571..47b46a0a699 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -1,3 +1,8 @@ +//! `run-make-support` is a support library for run-make tests. It provides command wrappers and +//! convenience utility functions to help test writers reduce duplication. The support library +//! notably is built via cargo: this means that if your test wants some non-trivial utility, such +//! as `object` or `wasmparser`, they can be re-exported and be made available through this library. + pub mod cc; pub mod run; pub mod rustc; @@ -82,7 +87,7 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String { cygpath.arg(path.as_ref()); let output = cygpath.output().unwrap(); if !output.status.success() { - handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number); + handle_failed_output(&cygpath, output, caller_line_number); } let s = String::from_utf8(output.stdout).unwrap(); // cygpath -w can attach a newline @@ -98,20 +103,158 @@ pub fn uname() -> String { let mut uname = Command::new("uname"); let output = uname.output().unwrap(); if !output.status.success() { - handle_failed_output(&format!("{:#?}", uname), output, caller_line_number); + handle_failed_output(&uname, output, caller_line_number); } String::from_utf8(output.stdout).unwrap() } -fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! { +fn handle_failed_output(cmd: &Command, output: Output, caller_line_number: u32) -> ! { if output.status.success() { - eprintln!("command incorrectly succeeded at line {caller_line_number}"); + eprintln!("command unexpectedly succeeded at line {caller_line_number}"); } else { eprintln!("command failed at line {caller_line_number}"); } - eprintln!("{cmd}"); + eprintln!("{cmd:?}"); eprintln!("output status: `{}`", output.status); eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap()); eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); std::process::exit(1) } + +/// Set the runtime library path as needed for running the host rustc/rustdoc/etc. +pub fn set_host_rpath(cmd: &mut Command) { + let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); + cmd.env(&ld_lib_path_envvar, { + let mut paths = vec![]; + paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); + paths.push(PathBuf::from(env::var("HOST_RPATH_DIR").unwrap())); + for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { + paths.push(p.to_path_buf()); + } + env::join_paths(paths.iter()).unwrap() + }); +} + +/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct +/// containing a `cmd: Command` field. The provided helpers are: +/// +/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended +/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add +/// new specific helper methods over relying on these generic argument providers. +/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to +/// methods of the same name on [`Command`]. +/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the +/// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are +/// higher-level convenience methods which waits for the command to finish running and assert +/// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when +/// possible. +/// +/// Example usage: +/// +/// ```ignore (illustrative) +/// struct CommandWrapper { cmd: Command } +/// +/// crate::impl_common_helpers!(CommandWrapper); +/// +/// impl CommandWrapper { +/// // ... additional specific helper methods +/// } +/// ``` +/// +/// [`Command`]: ::std::process::Command +/// [`Output`]: ::std::process::Output +macro_rules! impl_common_helpers { + ($wrapper: ident) => { + impl $wrapper { + /// Specify an environment variable. + pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + V: AsRef<::std::ffi::OsStr>, + { + self.cmd.env(key, value); + self + } + + /// Remove an environmental variable. + pub fn env_remove<K>(&mut self, key: K) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + { + self.cmd.env_remove(key); + self + } + + /// Clear all environmental variables. + pub fn env_var(&mut self) -> &mut Self { + self.cmd.env_clear(); + self + } + + /// Generic command argument provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn arg<S>(&mut self, arg: S) -> &mut Self + where + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.arg(arg); + self + } + + /// Generic command arguments provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn args<S>(&mut self, args: &[S]) -> &mut Self + where + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.args(args); + self + } + + /// Inspect what the underlying [`Command`][::std::process::Command] is up to the + /// current construction. + pub fn inspect<I>(&mut self, inspector: I) -> &mut Self + where + I: FnOnce(&::std::process::Command), + { + inspector(&self.cmd); + self + } + + /// Get the [`Output`][::std::process::Output] of the finished process. + pub fn output(&mut self) -> ::std::process::Output { + self.cmd.output().expect("failed to get output of finished process") + } + + /// Run the constructed command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> ::std::process::Output { + let caller_location = ::std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&self.cmd, output, caller_line_number); + } + output + } + + /// Run the constructed command and assert that it does not successfully run. + #[track_caller] + pub fn run_fail(&mut self) -> ::std::process::Output { + let caller_location = ::std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if output.status.success() { + handle_failed_output(&self.cmd, output, caller_line_number); + } + output + } + } + }; +} + +pub(crate) use impl_common_helpers; diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index e33ea9d6e40..9aad91f1b46 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -45,7 +45,7 @@ pub fn run(name: &str) -> Output { let (cmd, output) = run_common(name); if !output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + handle_failed_output(&cmd, output, caller_line_number); } output } @@ -58,7 +58,7 @@ pub fn run_fail(name: &str) -> Output { let (cmd, output) = run_common(name); if output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + handle_failed_output(&cmd, output, caller_line_number); } output } diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 50ff0d26bbb..ebda151b908 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -1,9 +1,9 @@ use std::env; -use std::ffi::OsStr; +use std::ffi::OsString; use std::path::Path; use std::process::{Command, Output}; -use crate::{handle_failed_output, tmp_dir}; +use crate::{handle_failed_output, set_host_rpath, tmp_dir}; /// Construct a new `rustc` invocation. pub fn rustc() -> Rustc { @@ -21,9 +21,12 @@ pub struct Rustc { cmd: Command, } +crate::impl_common_helpers!(Rustc); + fn setup_common() -> Command { let rustc = env::var("RUSTC").unwrap(); let mut cmd = Command::new(rustc); + set_host_rpath(&mut cmd); cmd.arg("--out-dir").arg(tmp_dir()).arg("-L").arg(tmp_dir()); cmd } @@ -86,94 +89,75 @@ impl Rustc { self } - /// Specify target triple. - pub fn target(&mut self, target: &str) -> &mut Self { - assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); - self.cmd.arg(format!("--target={target}")); + /// This flag defers LTO optimizations to the linker. + pub fn linker_plugin_lto(&mut self, option: &str) -> &mut Self { + self.cmd.arg(format!("-Clinker-plugin-lto={option}")); self } - /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. - /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>` - /// is passed (note the space). - pub fn arg(&mut self, arg: &str) -> &mut Self { - assert!( - !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), - "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" - ); - self.cmd.arg(arg); + /// Specify what happens when the code panics. + pub fn panic(&mut self, option: &str) -> &mut Self { + self.cmd.arg(format!("-Cpanic={option}")); self } - /// Specify the crate type. - pub fn crate_type(&mut self, crate_type: &str) -> &mut Self { - self.cmd.arg("--crate-type"); - self.cmd.arg(crate_type); + /// Specify number of codegen units + pub fn codegen_units(&mut self, units: usize) -> &mut Self { + self.cmd.arg(format!("-Ccodegen-units={units}")); self } - /// Specify the edition year. - pub fn edition(&mut self, edition: &str) -> &mut Self { - self.cmd.arg("--edition"); - self.cmd.arg(edition); + /// Specify directory path used for incremental cache + pub fn incremental<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + let mut arg = OsString::new(); + arg.push("-Cincremental="); + arg.push(path.as_ref()); + self.cmd.arg(&arg); self } - /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. - /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>` - /// is passed (note the space). - pub fn args(&mut self, args: &[&str]) -> &mut Self { - for arg in args { - assert!( - !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), - "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" - ); - } - - self.cmd.args(args); + /// Specify error format to use + pub fn error_format(&mut self, format: &str) -> &mut Self { + self.cmd.arg(format!("--error-format={format}")); self } - pub fn env(&mut self, name: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Self { - self.cmd.env(name, value); + /// Specify json messages printed by the compiler + pub fn json(&mut self, items: &str) -> &mut Self { + self.cmd.arg(format!("--json={items}")); self } - // Command inspection, output and running helper methods - - /// Get the [`Output`][std::process::Output] of the finished `rustc` process. - pub fn output(&mut self) -> Output { - self.cmd.output().unwrap() + /// Specify target triple. + pub fn target(&mut self, target: &str) -> &mut Self { + assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); + self.cmd.arg(format!("--target={target}")); + self } - /// Run the constructed `rustc` command and assert that it is successfully run. - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); + /// Specify the crate type. + pub fn crate_type(&mut self, crate_type: &str) -> &mut Self { + self.cmd.arg("--crate-type"); + self.cmd.arg(crate_type); + self + } - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output + /// Specify the edition year. + pub fn edition(&mut self, edition: &str) -> &mut Self { + self.cmd.arg("--edition"); + self.cmd.arg(edition); + self } #[track_caller] - pub fn run_fail(&mut self) -> Output { + pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); let output = self.cmd.output().unwrap(); - if output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + if output.status.code().unwrap() != code { + handle_failed_output(&self.cmd, output, caller_line_number); } output } - - /// Inspect what the underlying [`Command`] is up to the current construction. - pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { - f(&self.cmd); - self - } } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 9607ff02f96..1054ac83c10 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -2,7 +2,7 @@ use std::env; use std::path::Path; use std::process::{Command, Output}; -use crate::handle_failed_output; +use crate::{handle_failed_output, set_host_rpath}; /// Construct a plain `rustdoc` invocation with no flags set. pub fn bare_rustdoc() -> Rustdoc { @@ -19,9 +19,13 @@ pub struct Rustdoc { cmd: Command, } +crate::impl_common_helpers!(Rustdoc); + fn setup_common() -> Command { let rustdoc = env::var("RUSTDOC").unwrap(); - Command::new(rustdoc) + let mut cmd = Command::new(rustdoc); + set_host_rpath(&mut cmd); + cmd } impl Rustdoc { @@ -58,22 +62,14 @@ impl Rustdoc { self } - /// Fallback argument provider. Consider adding meaningfully named methods instead of using - /// this method. - pub fn arg(&mut self, arg: &str) -> &mut Self { - self.cmd.arg(arg); - self - } - - /// Run the build `rustdoc` command and assert that the run is successful. #[track_caller] - pub fn run(&mut self) -> Output { + pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + if output.status.code().unwrap() != code { + handle_failed_output(&self.cmd, output, caller_line_number); } output } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7f220a456a8..10a87f6e698 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -867,6 +867,11 @@ impl Rewrite for ast::Ty { self.span, shape, ), + ast::TyKind::Pat(ref ty, ref pat) => { + let ty = ty.rewrite(context, shape)?; + let pat = pat.rewrite(context, shape)?; + Some(format!("{ty} is {pat}")) + } } } } diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 8c6b1eb22ec..58302b8e63b 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -6,7 +6,6 @@ autobins = false [dependencies] cargo_metadata = "0.15" -cargo-platform = "0.1.2" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } lazy_static = "1" diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index c3ed1ff6891..3914feb3499 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -59,7 +59,6 @@ run-make/emit/Makefile run-make/env-dep-info/Makefile run-make/error-found-staticlib-instead-crate/Makefile run-make/error-writing-dependencies/Makefile -run-make/exit-code/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile @@ -321,7 +320,6 @@ run-make/use-suggestions-rust-2018/Makefile run-make/used-cdylib-macos/Makefile run-make/used/Makefile run-make/valid-print-requests/Makefile -run-make/version/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index aec2856dbbc..f380513f4ef 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -1,6 +1,6 @@ //! Checks the licenses of third-party dependencies. -use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId}; +use cargo_metadata::{Metadata, Package, PackageId}; use std::collections::HashSet; use std::path::Path; @@ -191,6 +191,7 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); /// rustc. Please check with the compiler team before adding an entry. const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start + "addr2line", "adler", "ahash", "aho-corasick", @@ -468,6 +469,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "mach", "memchr", "object", + "once_cell", "proc-macro2", "quote", "regalloc2", @@ -668,27 +670,7 @@ fn check_permitted_dependencies( let mut deps = HashSet::new(); for to_check in restricted_dependency_crates { let to_check = pkg_from_name(metadata, to_check); - use cargo_platform::Cfg; - use std::str::FromStr; - // We don't expect the compiler to ever run on wasm32, so strip - // out those dependencies to avoid polluting the permitted list. - deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| { - dep_kinds.iter().any(|dep_kind| { - dep_kind - .target - .as_ref() - .map(|target| { - !target.matches( - "wasm32-unknown-unknown", - &[ - Cfg::from_str("target_arch=\"wasm32\"").unwrap(), - Cfg::from_str("target_os=\"unknown\"").unwrap(), - ], - ) - }) - .unwrap_or(true) - }) - }); + deps_of(metadata, &to_check.id, &mut deps); } // Check that the PERMITTED_DEPENDENCIES does not have unused entries. @@ -740,18 +722,13 @@ fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> let mut result = HashSet::new(); for name in RUNTIME_CRATES { let id = &pkg_from_name(metadata, name).id; - deps_of_filtered(metadata, id, &mut result, &|_| true); + deps_of(metadata, id, &mut result); } result } /// Recursively find all dependencies. -fn deps_of_filtered<'a>( - metadata: &'a Metadata, - pkg_id: &'a PackageId, - result: &mut HashSet<&'a PackageId>, - filter: &dyn Fn(&[DepKindInfo]) -> bool, -) { +fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>) { if !result.insert(pkg_id) { return; } @@ -764,9 +741,6 @@ fn deps_of_filtered<'a>( .find(|n| &n.id == pkg_id) .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve")); for dep in &node.deps { - if !filter(&dep.dep_kinds) { - continue; - } - deps_of_filtered(metadata, &dep.pkg, result, filter); + deps_of(metadata, &dep.pkg, result); } } diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 6fc65e56901..39f7e70b693 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -71,10 +71,12 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String let path = root_path.join(Path::new(ERROR_CODES_PATH)); let file = fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}")); + let path = path.display(); let mut error_codes = Vec::new(); - for line in file.lines() { + for (line_index, line) in file.lines().enumerate() { + let line_index = line_index + 1; let line = line.trim(); if line.starts_with('E') { @@ -82,39 +84,54 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String // Extract the error code from the line. Emit a fatal error if it is not in the correct // format. - let err_code = if let Some(err_code) = split_line { - err_code.0.to_owned() - } else { + let Some(split_line) = split_line else { errors.push(format!( - "Expected a line with the format `Eabcd: abcd, \ + "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \ but got \"{}\" without a `:` delimiter", line, )); continue; }; + let err_code = split_line.0.to_owned(); + // If this is a duplicate of another error code, emit a fatal error. if error_codes.contains(&err_code) { - errors.push(format!("Found duplicate error code: `{}`", err_code)); + errors.push(format!( + "{path}:{line_index}: Found duplicate error code: `{}`", + err_code + )); continue; } let mut chars = err_code.chars(); - chars.next(); + assert_eq!(chars.next(), Some('E')); let error_num_as_str = chars.as_str(); // Ensure that the line references the correct markdown file. - let expected_filename = format!(" {},", error_num_as_str); - if expected_filename != split_line.unwrap().1 { + let rest = split_line.1.split_once(','); + let Some(rest) = rest else { + errors.push(format!( + "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \ + but got \"{}\" without a `,` delimiter", + line, + )); + continue; + }; + if error_num_as_str != rest.0.trim() { errors.push(format!( - "`{}:` should be followed by `{}` but instead found `{}` in \ + "{path}:{line_index}: `{}:` should be followed by `{},` but instead found `{}` in \ `compiler/rustc_error_codes/src/lib.rs`", err_code, - expected_filename, - split_line.unwrap().1, + error_num_as_str, + split_line.1, )); continue; } + if !rest.1.trim().is_empty() && !rest.1.trim().starts_with("//") { + errors.push(format!("{path}:{line_index}: should only have one error per line")); + continue; + } error_codes.push(err_code); } @@ -146,14 +163,14 @@ fn check_error_codes_docs( return; } - // Make sure that the file is referenced in `error_codes.rs` + // Make sure that the file is referenced in `rustc_error_codes/src/lib.rs` let filename = path.file_name().unwrap().to_str().unwrap().split_once('.'); let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format. if error_codes.iter().all(|e| e != err_code) { errors.push(format!( "Found valid file `{}` in error code docs directory without corresponding \ - entry in `error_code.rs`", + entry in `rustc_error_codes/src/lib.rs`", path.display() )); return; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 874c15ce41d..211dc347b0f 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1,4377 +1,4370 @@ - -/* ============================================================ ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️ ============================================================ -*/ -[ -"ui/abi/issue-28676.rs", -"ui/abi/issues/issue-22565-rust-call.rs", -"ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs", -"ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs", -"ui/argument-suggestions/issue-100154.rs", -"ui/argument-suggestions/issue-100478.rs", -"ui/argument-suggestions/issue-101097.rs", -"ui/argument-suggestions/issue-109425.rs", -"ui/argument-suggestions/issue-109831.rs", -"ui/argument-suggestions/issue-112507.rs", -"ui/argument-suggestions/issue-96638.rs", -"ui/argument-suggestions/issue-97197.rs", -"ui/argument-suggestions/issue-97484.rs", -"ui/argument-suggestions/issue-98894.rs", -"ui/argument-suggestions/issue-98897.rs", -"ui/argument-suggestions/issue-99482.rs", -"ui/array-slice-vec/issue-15730.rs", -"ui/array-slice-vec/issue-18425.rs", -"ui/array-slice-vec/issue-69103-extra-binding-subslice.rs", -"ui/asm/issue-113788.rs", -"ui/asm/issue-72570.rs", -"ui/asm/issue-85247.rs", -"ui/asm/issue-87802.rs", -"ui/asm/issue-89305.rs", -"ui/asm/issue-92378.rs", -"ui/asm/issue-97490.rs", -"ui/asm/issue-99071.rs", -"ui/asm/issue-99122-2.rs", -"ui/asm/issue-99122.rs", -"ui/asm/x86_64/issue-82869.rs", -"ui/asm/x86_64/issue-89875.rs", -"ui/asm/x86_64/issue-96797.rs", -"ui/associated-consts/issue-102335-const.rs", -"ui/associated-consts/issue-105330.rs", -"ui/associated-consts/issue-110933.rs", -"ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs", -"ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.rs", -"ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs", -"ui/associated-consts/issue-47814.rs", -"ui/associated-consts/issue-58022.rs", -"ui/associated-consts/issue-63496.rs", -"ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs", -"ui/associated-consts/issue-88599-ref-self.rs", -"ui/associated-consts/issue-93775.rs", -"ui/associated-consts/issue-93835.rs", -"ui/associated-inherent-types/issue-104260.rs", -"ui/associated-inherent-types/issue-109071.rs", -"ui/associated-inherent-types/issue-109299-1.rs", -"ui/associated-inherent-types/issue-109299.rs", -"ui/associated-inherent-types/issue-109768.rs", -"ui/associated-inherent-types/issue-109789.rs", -"ui/associated-inherent-types/issue-109790.rs", -"ui/associated-inherent-types/issue-111404-0.rs", -"ui/associated-inherent-types/issue-111404-1.rs", -"ui/associated-inherent-types/issue-111879-0.rs", -"ui/associated-inherent-types/issue-111879-1.rs", -"ui/associated-item/issue-105449.rs", -"ui/associated-item/issue-48027.rs", -"ui/associated-item/issue-87638.rs", -"ui/associated-type-bounds/issue-102335-ty.rs", -"ui/associated-type-bounds/issue-104916.rs", -"ui/associated-type-bounds/issue-61752.rs", -"ui/associated-type-bounds/issue-70292.rs", -"ui/associated-type-bounds/issue-71443-1.rs", -"ui/associated-type-bounds/issue-71443-2.rs", -"ui/associated-type-bounds/issue-73818.rs", -"ui/associated-type-bounds/issue-79949.rs", -"ui/associated-type-bounds/issue-81193.rs", -"ui/associated-type-bounds/issue-83017.rs", -"ui/associated-type-bounds/issue-99828.rs", -"ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs", -"ui/associated-types/issue-18655.rs", -"ui/associated-types/issue-19081.rs", -"ui/associated-types/issue-19883.rs", -"ui/associated-types/issue-20005.rs", -"ui/associated-types/issue-20825-2.rs", -"ui/associated-types/issue-20825.rs", -"ui/associated-types/issue-21363.rs", -"ui/associated-types/issue-21726.rs", -"ui/associated-types/issue-22037.rs", -"ui/associated-types/issue-22066.rs", -"ui/associated-types/issue-22560.rs", -"ui/associated-types/issue-22828.rs", -"ui/associated-types/issue-23208.rs", -"ui/associated-types/issue-23595-1.rs", -"ui/associated-types/issue-23595-2.rs", -"ui/associated-types/issue-24159.rs", -"ui/associated-types/issue-24204.rs", -"ui/associated-types/issue-24338.rs", -"ui/associated-types/issue-25339.rs", -"ui/associated-types/issue-25700-1.rs", -"ui/associated-types/issue-25700-2.rs", -"ui/associated-types/issue-25700.rs", -"ui/associated-types/issue-26262.rs", -"ui/associated-types/issue-26681.rs", -"ui/associated-types/issue-27675-unchecked-bounds.rs", -"ui/associated-types/issue-27901.rs", -"ui/associated-types/issue-28871.rs", -"ui/associated-types/issue-31597.rs", -"ui/associated-types/issue-32323.rs", -"ui/associated-types/issue-32350.rs", -"ui/associated-types/issue-36499.rs", -"ui/associated-types/issue-37808.rs", -"ui/associated-types/issue-37883.rs", -"ui/associated-types/issue-38821.rs", -"ui/associated-types/issue-38917.rs", -"ui/associated-types/issue-39532.rs", -"ui/associated-types/issue-40093.rs", -"ui/associated-types/issue-41868.rs", -"ui/associated-types/issue-43475.rs", -"ui/associated-types/issue-43784-associated-type.rs", -"ui/associated-types/issue-43924.rs", -"ui/associated-types/issue-44153.rs", -"ui/associated-types/issue-47139-1.rs", -"ui/associated-types/issue-47139-2.rs", -"ui/associated-types/issue-47385.rs", -"ui/associated-types/issue-47814.rs", -"ui/associated-types/issue-48010.rs", -"ui/associated-types/issue-48551.rs", -"ui/associated-types/issue-50301.rs", -"ui/associated-types/issue-54108.rs", -"ui/associated-types/issue-54182-1.rs", -"ui/associated-types/issue-54182-2.rs", -"ui/associated-types/issue-54467.rs", -"ui/associated-types/issue-55846.rs", -"ui/associated-types/issue-59324.rs", -"ui/associated-types/issue-62200.rs", -"ui/associated-types/issue-63591.rs", -"ui/associated-types/issue-63593.rs", -"ui/associated-types/issue-64848.rs", -"ui/associated-types/issue-64855-2.rs", -"ui/associated-types/issue-64855.rs", -"ui/associated-types/issue-65774-1.rs", -"ui/associated-types/issue-65774-2.rs", -"ui/associated-types/issue-65934.rs", -"ui/associated-types/issue-67684.rs", -"ui/associated-types/issue-69398.rs", -"ui/associated-types/issue-71113.rs", -"ui/associated-types/issue-72806.rs", -"ui/associated-types/issue-76179.rs", -"ui/associated-types/issue-82079.rs", -"ui/associated-types/issue-85103-layout-debug.rs", -"ui/associated-types/issue-87261.rs", -"ui/associated-types/issue-88856.rs", -"ui/associated-types/issue-91069.rs", -"ui/associated-types/issue-91231.rs", -"ui/associated-types/issue-91234.rs", -"ui/async-await/auxiliary/issue-107036.rs", -"ui/async-await/auxiliary/issue-72470-lib.rs", -"ui/async-await/in-trait/issue-102138.rs", -"ui/async-await/in-trait/issue-102219.rs", -"ui/async-await/in-trait/issue-102310.rs", -"ui/async-await/in-trait/issue-104678.rs", -"ui/async-await/issue-101715.rs", -"ui/async-await/issue-105501.rs", -"ui/async-await/issue-107036.rs", -"ui/async-await/issue-108572.rs", -"ui/async-await/issue-54239-private-type-triggers-lint.rs", -"ui/async-await/issue-60709.rs", -"ui/async-await/issue-61076.rs", -"ui/async-await/issue-61452.rs", -"ui/async-await/issue-61793.rs", -"ui/async-await/issue-62658.rs", -"ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs", -"ui/async-await/issue-63832-await-short-temporary-lifetime.rs", -"ui/async-await/issue-64130-1-sync.rs", -"ui/async-await/issue-64130-2-send.rs", -"ui/async-await/issue-64130-3-other.rs", -"ui/async-await/issue-64130-4-async-move.rs", -"ui/async-await/issue-64130-non-send-future-diags.rs", -"ui/async-await/issue-64391.rs", -"ui/async-await/issue-65634-raw-ident-suggestion.rs", -"ui/async-await/issue-66312.rs", -"ui/async-await/issue-66387-if-without-else.rs", -"ui/async-await/issue-67252-unnamed-future.rs", -"ui/async-await/issue-67651.rs", -"ui/async-await/issue-67765-async-diagnostic.rs", -"ui/async-await/issue-68112.rs", -"ui/async-await/issue-68523-start.rs", -"ui/async-await/issue-68523.rs", -"ui/async-await/issue-69446-fnmut-capture.rs", -"ui/async-await/issue-70594.rs", -"ui/async-await/issue-70818.rs", -"ui/async-await/issue-70935-complex-spans.rs", -"ui/async-await/issue-71137.rs", -"ui/async-await/issue-72442.rs", -"ui/async-await/issue-72470-llvm-dominate.rs", -"ui/async-await/issue-72590-type-error-sized.rs", -"ui/async-await/issue-73050.rs", -"ui/async-await/issue-73137.rs", -"ui/async-await/issue-73541-1.rs", -"ui/async-await/issue-73541-2.rs", -"ui/async-await/issue-73541-3.rs", -"ui/async-await/issue-73541.rs", -"ui/async-await/issue-73741-type-err.rs", -"ui/async-await/issue-74047.rs", -"ui/async-await/issue-74072-lifetime-name-annotations.rs", -"ui/async-await/issue-74497-lifetime-in-opaque.rs", -"ui/async-await/issue-75785-confusing-named-region.rs", -"ui/async-await/issue-76547.rs", -"ui/async-await/issue-77993-2.rs", -"ui/async-await/issue-78115.rs", -"ui/async-await/issue-84841.rs", -"ui/async-await/issue-86507.rs", -"ui/async-await/issue-93197.rs", -"ui/async-await/issue-93648.rs", -"ui/async-await/issue-98634.rs", -"ui/async-await/issues/auxiliary/issue-60674.rs", -"ui/async-await/issues/auxiliary/issue_67893.rs", -"ui/async-await/issues/issue-102206.rs", -"ui/async-await/issues/issue-107280.rs", -"ui/async-await/issues/issue-112225-1.rs", -"ui/async-await/issues/issue-112225-2.rs", -"ui/async-await/issues/issue-51719.rs", -"ui/async-await/issues/issue-51751.rs", -"ui/async-await/issues/issue-53249.rs", -"ui/async-await/issues/issue-54752-async-block.rs", -"ui/async-await/issues/issue-54974.rs", -"ui/async-await/issues/issue-55324.rs", -"ui/async-await/issues/issue-55809.rs", -"ui/async-await/issues/issue-58885.rs", -"ui/async-await/issues/issue-59001.rs", -"ui/async-await/issues/issue-59972.rs", -"ui/async-await/issues/issue-60518.rs", -"ui/async-await/issues/issue-60655-latebound-regions.rs", -"ui/async-await/issues/issue-60674.rs", -"ui/async-await/issues/issue-61187.rs", -"ui/async-await/issues/issue-61986.rs", -"ui/async-await/issues/issue-62009-1.rs", -"ui/async-await/issues/issue-62009-2.rs", -"ui/async-await/issues/issue-62097.rs", -"ui/async-await/issues/issue-62517-1.rs", -"ui/async-await/issues/issue-62517-2.rs", -"ui/async-await/issues/issue-63388-1.rs", -"ui/async-await/issues/issue-63388-2.rs", -"ui/async-await/issues/issue-63388-3.rs", -"ui/async-await/issues/issue-63388-4.rs", -"ui/async-await/issues/issue-64391-2.rs", -"ui/async-await/issues/issue-64433.rs", -"ui/async-await/issues/issue-64477-2.rs", -"ui/async-await/issues/issue-64477.rs", -"ui/async-await/issues/issue-64964.rs", -"ui/async-await/issues/issue-65159.rs", -"ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs", -"ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs", -"ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs", -"ui/async-await/issues/issue-65436-raw-ptr-not-send.rs", -"ui/async-await/issues/issue-66695-static-refs.rs", -"ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs", -"ui/async-await/issues/issue-67611-static-mut-refs.rs", -"ui/async-await/issues/issue-67893.rs", -"ui/async-await/issues/issue-69307-nested.rs", -"ui/async-await/issues/issue-69307.rs", -"ui/async-await/issues/issue-72312.rs", -"ui/async-await/issues/issue-78600.rs", -"ui/async-await/issues/issue-78654.rs", -"ui/async-await/issues/issue-78938-async-block.rs", -"ui/async-await/issues/issue-95307.rs", -"ui/async-await/return-type-notation/issue-110963-early.rs", -"ui/async-await/return-type-notation/issue-110963-late.rs", -"ui/async-await/track-caller/issue-105134.rs", -"ui/attributes/issue-100631.rs", -"ui/attributes/issue-105594-invalid-attr-validation.rs", -"ui/attributes/issue-115264-expr-field.rs", -"ui/attributes/issue-115264-pat-field.rs", -"ui/attributes/issue-40962.rs", -"ui/attributes/issue-90873.rs", -"ui/auto-traits/issue-117789.rs", -"ui/auto-traits/issue-23080-2.rs", -"ui/auto-traits/issue-23080.rs", -"ui/auto-traits/issue-83857-ub.rs", -"ui/auto-traits/issue-84075.rs", -"ui/auxiliary/issue-13560-1.rs", -"ui/auxiliary/issue-13560-2.rs", -"ui/auxiliary/issue-13560-3.rs", -"ui/auxiliary/issue-16822.rs", -"ui/auxiliary/issue-18502.rs", -"ui/auxiliary/issue-24106.rs", -"ui/auxiliary/issue-76387.rs", -"ui/bench/issue-32062.rs", -"ui/binding/issue-53114-borrow-checks.rs", -"ui/binding/issue-53114-safety-checks.rs", -"ui/binop/issue-25916.rs", -"ui/binop/issue-28837.rs", -"ui/binop/issue-3820.rs", -"ui/binop/issue-62375.rs", -"ui/binop/issue-77910-1.rs", -"ui/binop/issue-77910-2.rs", -"ui/binop/issue-93927.rs", -"ui/block-result/issue-11714.rs", -"ui/block-result/issue-13428.rs", -"ui/block-result/issue-13624.rs", -"ui/block-result/issue-20862.rs", -"ui/block-result/issue-22645.rs", -"ui/block-result/issue-3563.rs", -"ui/block-result/issue-5500.rs", -"ui/borrowck/issue-101119.rs", -"ui/borrowck/issue-102209.rs", -"ui/borrowck/issue-103095.rs", -"ui/borrowck/issue-103250.rs", -"ui/borrowck/issue-103624.rs", -"ui/borrowck/issue-104639-lifetime-order.rs", -"ui/borrowck/issue-10876.rs", -"ui/borrowck/issue-109271-pass-self-into-closure.rs", -"ui/borrowck/issue-111554.rs", -"ui/borrowck/issue-114374-invalid-help-fmt-args.rs", -"ui/borrowck/issue-11493.rs", -"ui/borrowck/issue-115259-suggest-iter-mut.rs", -"ui/borrowck/issue-119915-bad-clone-suggestion.rs", -"ui/borrowck/issue-17263.rs", -"ui/borrowck/issue-17545.rs", -"ui/borrowck/issue-17718-static-move.rs", -"ui/borrowck/issue-20801.rs", -"ui/borrowck/issue-23338-params-outlive-temps-of-body.rs", -"ui/borrowck/issue-24267-flow-exit.rs", -"ui/borrowck/issue-25793.rs", -"ui/borrowck/issue-28934.rs", -"ui/borrowck/issue-29166.rs", -"ui/borrowck/issue-31287-drop-in-guard.rs", -"ui/borrowck/issue-33819.rs", -"ui/borrowck/issue-36082.rs", -"ui/borrowck/issue-41962.rs", -"ui/borrowck/issue-42344.rs", -"ui/borrowck/issue-45199.rs", -"ui/borrowck/issue-45983.rs", -"ui/borrowck/issue-46095.rs", -"ui/borrowck/issue-46471.rs", -"ui/borrowck/issue-47215-ice-from-drop-elab.rs", -"ui/borrowck/issue-47646.rs", -"ui/borrowck/issue-51117.rs", -"ui/borrowck/issue-51301.rs", -"ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs", -"ui/borrowck/issue-51415.rs", -"ui/borrowck/issue-52713-bug.rs", -"ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs", -"ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs", -"ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs", -"ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs", -"ui/borrowck/issue-54499-field-mutation-of-moved-out.rs", -"ui/borrowck/issue-54499-field-mutation-of-never-init.rs", -"ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs", -"ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs", -"ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs", -"ui/borrowck/issue-58776-borrowck-scans-children.rs", -"ui/borrowck/issue-62007-assign-box.rs", -"ui/borrowck/issue-62007-assign-field.rs", -"ui/borrowck/issue-62107-match-arm-scopes.rs", -"ui/borrowck/issue-62387-suggest-iter-mut-2.rs", -"ui/borrowck/issue-62387-suggest-iter-mut.rs", -"ui/borrowck/issue-64453.rs", -"ui/borrowck/issue-69789-iterator-mut-suggestion.rs", -"ui/borrowck/issue-70919-drop-in-loop.rs", -"ui/borrowck/issue-71546.rs", -"ui/borrowck/issue-7573.rs", -"ui/borrowck/issue-80772.rs", -"ui/borrowck/issue-81365-1.rs", -"ui/borrowck/issue-81365-10.rs", -"ui/borrowck/issue-81365-11.rs", -"ui/borrowck/issue-81365-2.rs", -"ui/borrowck/issue-81365-3.rs", -"ui/borrowck/issue-81365-4.rs", -"ui/borrowck/issue-81365-5.rs", -"ui/borrowck/issue-81365-6.rs", -"ui/borrowck/issue-81365-7.rs", -"ui/borrowck/issue-81365-8.rs", -"ui/borrowck/issue-81365-9.rs", -"ui/borrowck/issue-81899.rs", -"ui/borrowck/issue-82032.rs", -"ui/borrowck/issue-82126-mismatched-subst-and-hir.rs", -"ui/borrowck/issue-82462.rs", -"ui/borrowck/issue-83309-ice-immut-in-for-loop.rs", -"ui/borrowck/issue-83760.rs", -"ui/borrowck/issue-83924.rs", -"ui/borrowck/issue-85581.rs", -"ui/borrowck/issue-85765-closure.rs", -"ui/borrowck/issue-85765.rs", -"ui/borrowck/issue-87456-point-to-closure.rs", -"ui/borrowck/issue-88434-minimal-example.rs", -"ui/borrowck/issue-88434-removal-index-should-be-less.rs", -"ui/borrowck/issue-91206.rs", -"ui/borrowck/issue-92015.rs", -"ui/borrowck/issue-92157.rs", -"ui/borrowck/issue-93078.rs", -"ui/borrowck/issue-93093.rs", -"ui/borrowck/issue-95079-missing-move-in-nested-closure.rs", -"ui/box/issue-82446.rs", -"ui/box/issue-95036.rs", -"ui/c-variadic/issue-32201.rs", -"ui/c-variadic/issue-86053-1.rs", -"ui/c-variadic/issue-86053-2.rs", -"ui/cast/issue-106883-is-empty.rs", -"ui/cast/issue-10991.rs", -"ui/cast/issue-17444.rs", -"ui/cast/issue-84213.rs", -"ui/cast/issue-85586.rs", -"ui/cast/issue-88621.rs", -"ui/cast/issue-89497.rs", -"ui/closure-expected-type/issue-24421.rs", -"ui/closure_context/issue-26046-fn-mut.rs", -"ui/closure_context/issue-26046-fn-once.rs", -"ui/closure_context/issue-42065.rs", -"ui/closures/2229_closure_analysis/issue-118144.rs", -"ui/closures/2229_closure_analysis/issue-87378.rs", -"ui/closures/2229_closure_analysis/issue-87987.rs", -"ui/closures/2229_closure_analysis/issue-88118-2.rs", -"ui/closures/2229_closure_analysis/issue-88476.rs", -"ui/closures/2229_closure_analysis/issue-89606.rs", -"ui/closures/2229_closure_analysis/issue-90465.rs", -"ui/closures/2229_closure_analysis/issue-92724-needsdrop-query-cycle.rs", -"ui/closures/2229_closure_analysis/issue_88118.rs", -"ui/closures/2229_closure_analysis/match/issue-87097.rs", -"ui/closures/2229_closure_analysis/match/issue-87426.rs", -"ui/closures/2229_closure_analysis/match/issue-87988.rs", -"ui/closures/2229_closure_analysis/match/issue-88331.rs", -"ui/closures/2229_closure_analysis/migrations/issue-78720.rs", -"ui/closures/2229_closure_analysis/migrations/issue-86753.rs", -"ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-87378.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-88372.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-88431.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-88476.rs", -"ui/closures/issue-101696.rs", -"ui/closures/issue-102089-multiple-opaque-cast.rs", -"ui/closures/issue-10398.rs", -"ui/closures/issue-10682.rs", -"ui/closures/issue-109188.rs", -"ui/closures/issue-111932.rs", -"ui/closures/issue-113087.rs", -"ui/closures/issue-11873.rs", -"ui/closures/issue-1460.rs", -"ui/closures/issue-23012-supertrait-signature-inference.rs", -"ui/closures/issue-25439.rs", -"ui/closures/issue-41366.rs", -"ui/closures/issue-42463.rs", -"ui/closures/issue-46742.rs", -"ui/closures/issue-48109.rs", -"ui/closures/issue-52437.rs", -"ui/closures/issue-67123.rs", -"ui/closures/issue-6801.rs", -"ui/closures/issue-68025.rs", -"ui/closures/issue-72408-nested-closures-exponential.rs", -"ui/closures/issue-78720.rs", -"ui/closures/issue-80313-mutable-borrow-in-closure.rs", -"ui/closures/issue-80313-mutable-borrow-in-move-closure.rs", -"ui/closures/issue-80313-mutation-in-closure.rs", -"ui/closures/issue-80313-mutation-in-move-closure.rs", -"ui/closures/issue-81700-mut-borrow.rs", -"ui/closures/issue-82438-mut-without-upvar.rs", -"ui/closures/issue-84044-drop-non-mut.rs", -"ui/closures/issue-84128.rs", -"ui/closures/issue-868.rs", -"ui/closures/issue-87461.rs", -"ui/closures/issue-87814-1.rs", -"ui/closures/issue-87814-2.rs", -"ui/closures/issue-90871.rs", -"ui/closures/issue-97607.rs", -"ui/closures/issue-99565.rs", -"ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs", -"ui/codegen/auxiliary/issue-97708-aux.rs", -"ui/codegen/issue-101585-128bit-repeat.rs", -"ui/codegen/issue-16602-1.rs", -"ui/codegen/issue-16602-2.rs", -"ui/codegen/issue-16602-3.rs", -"ui/codegen/issue-27859.rs", -"ui/codegen/issue-28950.rs", -"ui/codegen/issue-55976.rs", -"ui/codegen/issue-63787.rs", -"ui/codegen/issue-64401.rs", -"ui/codegen/issue-79865-llvm-miscompile.rs", -"ui/codegen/issue-82833-slice-miscompile.rs", -"ui/codegen/issue-82859-slice-miscompile.rs", -"ui/codegen/issue-88043-bb-does-not-have-terminator.rs", -"ui/codegen/issue-97708.rs", -"ui/codegen/issue-99551.rs", -"ui/codemap_tests/issue-11715.rs", -"ui/codemap_tests/issue-28308.rs", -"ui/coercion/auxiliary/issue-39823.rs", -"ui/coercion/issue-101066.rs", -"ui/coercion/issue-14589.rs", -"ui/coercion/issue-26905-rpass.rs", -"ui/coercion/issue-26905.rs", -"ui/coercion/issue-36007.rs", -"ui/coercion/issue-37655.rs", -"ui/coercion/issue-3794.rs", -"ui/coercion/issue-39823.rs", -"ui/coercion/issue-53475.rs", -"ui/coercion/issue-73886.rs", -"ui/coercion/issue-88097.rs", -"ui/coherence/issue-85026.rs", -"ui/coherence/issue-99663-2.rs", -"ui/coherence/issue-99663.rs", -"ui/command/issue-10626.rs", -"ui/compare-method/issue-90444.rs", -"ui/conditional-compilation/issue-34028.rs", -"ui/confuse-field-and-method/issue-18343.rs", -"ui/confuse-field-and-method/issue-2392.rs", -"ui/confuse-field-and-method/issue-32128.rs", -"ui/confuse-field-and-method/issue-33784.rs", -"ui/const-generics/generic_arg_infer/issue-91614.rs", -"ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs", -"ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs", -"ui/const-generics/generic_const_exprs/issue-100217.rs", -"ui/const-generics/generic_const_exprs/issue-100360.rs", -"ui/const-generics/generic_const_exprs/issue-102074.rs", -"ui/const-generics/generic_const_exprs/issue-102768.rs", -"ui/const-generics/generic_const_exprs/issue-105257.rs", -"ui/const-generics/generic_const_exprs/issue-105608.rs", -"ui/const-generics/generic_const_exprs/issue-109141.rs", -"ui/const-generics/generic_const_exprs/issue-62504.rs", -"ui/const-generics/generic_const_exprs/issue-69654.rs", -"ui/const-generics/generic_const_exprs/issue-72787.rs", -"ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.rs", -"ui/const-generics/generic_const_exprs/issue-73298.rs", -"ui/const-generics/generic_const_exprs/issue-73899.rs", -"ui/const-generics/generic_const_exprs/issue-74634.rs", -"ui/const-generics/generic_const_exprs/issue-74713.rs", -"ui/const-generics/generic_const_exprs/issue-76595.rs", -"ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs", -"ui/const-generics/generic_const_exprs/issue-80561-incorrect-param-env.rs", -"ui/const-generics/generic_const_exprs/issue-80742.rs", -"ui/const-generics/generic_const_exprs/issue-82268.rs", -"ui/const-generics/generic_const_exprs/issue-83765.rs", -"ui/const-generics/generic_const_exprs/issue-83972.rs", -"ui/const-generics/generic_const_exprs/issue-84408.rs", -"ui/const-generics/generic_const_exprs/issue-84669.rs", -"ui/const-generics/generic_const_exprs/issue-85848.rs", -"ui/const-generics/generic_const_exprs/issue-86710.rs", -"ui/const-generics/generic_const_exprs/issue-89851.rs", -"ui/const-generics/generic_const_exprs/issue-90847.rs", -"ui/const-generics/generic_const_exprs/issue-94287.rs", -"ui/const-generics/generic_const_exprs/issue-94293.rs", -"ui/const-generics/generic_const_exprs/issue-96699.rs", -"ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs", -"ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs", -"ui/const-generics/generic_const_exprs/issue-99647.rs", -"ui/const-generics/generic_const_exprs/issue-99705.rs", -"ui/const-generics/infer/issue-77092.rs", -"ui/const-generics/issue-102124.rs", -"ui/const-generics/issue-105689.rs", -"ui/const-generics/issue-106419-struct-with-multiple-const-params.rs", -"ui/const-generics/issue-112505-overflow.rs", -"ui/const-generics/issue-46511.rs", -"ui/const-generics/issue-66451.rs", -"ui/const-generics/issue-70408.rs", -"ui/const-generics/issue-80471.rs", -"ui/const-generics/issue-93647.rs", -"ui/const-generics/issue-97007.rs", -"ui/const-generics/issues/issue-100313.rs", -"ui/const-generics/issues/issue-105037.rs", -"ui/const-generics/issues/issue-105821.rs", -"ui/const-generics/issues/issue-56445-1.rs", -"ui/const-generics/issues/issue-56445-2.rs", -"ui/const-generics/issues/issue-56445-3.rs", -"ui/const-generics/issues/issue-60818-struct-constructors.rs", -"ui/const-generics/issues/issue-61336-1.rs", -"ui/const-generics/issues/issue-61336-2.rs", -"ui/const-generics/issues/issue-61336.rs", -"ui/const-generics/issues/issue-61422.rs", -"ui/const-generics/issues/issue-61432.rs", -"ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs", -"ui/const-generics/issues/issue-62878.rs", -"ui/const-generics/issues/issue-63322-forbid-dyn.rs", -"ui/const-generics/issues/issue-64519.rs", -"ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs", -"ui/const-generics/issues/issue-66906.rs", -"ui/const-generics/issues/issue-67185-1.rs", -"ui/const-generics/issues/issue-67185-2.rs", -"ui/const-generics/issues/issue-67375.rs", -"ui/const-generics/issues/issue-67739.rs", -"ui/const-generics/issues/issue-67945-1.rs", -"ui/const-generics/issues/issue-67945-2.rs", -"ui/const-generics/issues/issue-67945-3.rs", -"ui/const-generics/issues/issue-67945-4.rs", -"ui/const-generics/issues/issue-68104-print-stack-overflow.rs", -"ui/const-generics/issues/issue-68366.rs", -"ui/const-generics/issues/issue-68596.rs", -"ui/const-generics/issues/issue-68615-adt.rs", -"ui/const-generics/issues/issue-68615-array.rs", -"ui/const-generics/issues/issue-69654-run-pass.rs", -"ui/const-generics/issues/issue-70125-1.rs", -"ui/const-generics/issues/issue-70125-2.rs", -"ui/const-generics/issues/issue-70167.rs", -"ui/const-generics/issues/issue-70180-1-stalled_on.rs", -"ui/const-generics/issues/issue-70180-2-stalled_on.rs", -"ui/const-generics/issues/issue-70225.rs", -"ui/const-generics/issues/issue-70273-assoc-fn.rs", -"ui/const-generics/issues/issue-71169.rs", -"ui/const-generics/issues/issue-71202.rs", -"ui/const-generics/issues/issue-71381.rs", -"ui/const-generics/issues/issue-71382.rs", -"ui/const-generics/issues/issue-71547.rs", -"ui/const-generics/issues/issue-71611.rs", -"ui/const-generics/issues/issue-71986.rs", -"ui/const-generics/issues/issue-72352.rs", -"ui/const-generics/issues/issue-72845.rs", -"ui/const-generics/issues/issue-73120.rs", -"ui/const-generics/issues/issue-73260.rs", -"ui/const-generics/issues/issue-73491.rs", -"ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs", -"ui/const-generics/issues/issue-74101.rs", -"ui/const-generics/issues/issue-74255.rs", -"ui/const-generics/issues/issue-74906.rs", -"ui/const-generics/issues/issue-74950.rs", -"ui/const-generics/issues/issue-75047.rs", -"ui/const-generics/issues/issue-75299.rs", -"ui/const-generics/issues/issue-76701-ty-param-in-const.rs", -"ui/const-generics/issues/issue-79674.rs", -"ui/const-generics/issues/issue-80062.rs", -"ui/const-generics/issues/issue-80375.rs", -"ui/const-generics/issues/issue-82956.rs", -"ui/const-generics/issues/issue-83249.rs", -"ui/const-generics/issues/issue-83288.rs", -"ui/const-generics/issues/issue-83466.rs", -"ui/const-generics/issues/issue-83765.rs", -"ui/const-generics/issues/issue-84659.rs", -"ui/const-generics/issues/issue-85031-2.rs", -"ui/const-generics/issues/issue-86033.rs", -"ui/const-generics/issues/issue-86530.rs", -"ui/const-generics/issues/issue-86535-2.rs", -"ui/const-generics/issues/issue-86535.rs", -"ui/const-generics/issues/issue-86820.rs", -"ui/const-generics/issues/issue-87076.rs", -"ui/const-generics/issues/issue-87470.rs", -"ui/const-generics/issues/issue-87493.rs", -"ui/const-generics/issues/issue-87964.rs", -"ui/const-generics/issues/issue-88119.rs", -"ui/const-generics/issues/issue-88468.rs", -"ui/const-generics/issues/issue-88997.rs", -"ui/const-generics/issues/issue-89146.rs", -"ui/const-generics/issues/issue-89304.rs", -"ui/const-generics/issues/issue-89320.rs", -"ui/const-generics/issues/issue-89334.rs", -"ui/const-generics/issues/issue-90318.rs", -"ui/const-generics/issues/issue-90364.rs", -"ui/const-generics/issues/issue-90455.rs", -"ui/const-generics/issues/issue-92186.rs", -"ui/const-generics/issues/issue-96654.rs", -"ui/const-generics/issues/issue-97278.rs", -"ui/const-generics/issues/issue-97634.rs", -"ui/const-generics/issues/issue-98629.rs", -"ui/const-generics/issues/issue-99641.rs", -"ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs", -"ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs", -"ui/const-generics/parser-error-recovery/issue-89013-type.rs", -"ui/const-generics/parser-error-recovery/issue-89013.rs", -"ui/const-generics/type-dependent/issue-61936.rs", -"ui/const-generics/type-dependent/issue-63695.rs", -"ui/const-generics/type-dependent/issue-67144-1.rs", -"ui/const-generics/type-dependent/issue-67144-2.rs", -"ui/const-generics/type-dependent/issue-69816.rs", -"ui/const-generics/type-dependent/issue-70217.rs", -"ui/const-generics/type-dependent/issue-70507.rs", -"ui/const-generics/type-dependent/issue-70586.rs", -"ui/const-generics/type-dependent/issue-71348.rs", -"ui/const-generics/type-dependent/issue-71382.rs", -"ui/const-generics/type-dependent/issue-71805.rs", -"ui/const-generics/type-dependent/issue-73730.rs", -"ui/const_prop/issue-102553.rs", -"ui/const_prop/issue-86351.rs", -"ui/consts/auxiliary/issue-17718-aux.rs", -"ui/consts/auxiliary/issue-63226.rs", -"ui/consts/const-eval/issue-100878.rs", -"ui/consts/const-eval/issue-104390.rs", -"ui/consts/const-eval/issue-114994-fail.rs", -"ui/consts/const-eval/issue-114994.rs", -"ui/consts/const-eval/issue-43197.rs", -"ui/consts/const-eval/issue-44578.rs", -"ui/consts/const-eval/issue-47971.rs", -"ui/consts/const-eval/issue-49296.rs", -"ui/consts/const-eval/issue-50706.rs", -"ui/consts/const-eval/issue-50814-2.rs", -"ui/consts/const-eval/issue-50814.rs", -"ui/consts/const-eval/issue-51300.rs", -"ui/consts/const-eval/issue-52475.rs", -"ui/consts/const-eval/issue-53157.rs", -"ui/consts/const-eval/issue-53401.rs", -"ui/consts/const-eval/issue-55541.rs", -"ui/consts/const-eval/issue-64908.rs", -"ui/consts/const-eval/issue-64970.rs", -"ui/consts/const-eval/issue-65394.rs", -"ui/consts/const-eval/issue-70723.rs", -"ui/consts/const-eval/issue-70804-fn-subtyping.rs", -"ui/consts/const-eval/issue-84957-const-str-as-bytes.rs", -"ui/consts/const-eval/issue-85155.rs", -"ui/consts/const-eval/issue-85907.rs", -"ui/consts/const-eval/issue-91827-extern-types-field-offset.rs", -"ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs", -"ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs", -"ui/consts/const-mut-refs/issue-76510.rs", -"ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.rs", -"ui/consts/const_in_pattern/issue-44333.rs", -"ui/consts/const_in_pattern/issue-53708.rs", -"ui/consts/const_in_pattern/issue-62614.rs", -"ui/consts/const_in_pattern/issue-65466.rs", -"ui/consts/const_in_pattern/issue-73431.rs", -"ui/consts/control-flow/issue-46843.rs", -"ui/consts/control-flow/issue-50577.rs", -"ui/consts/extra-const-ub/issue-100771.rs", -"ui/consts/extra-const-ub/issue-101034.rs", -"ui/consts/issue-102117.rs", -"ui/consts/issue-103790.rs", -"ui/consts/issue-104155.rs", -"ui/consts/issue-104396.rs", -"ui/consts/issue-104609.rs", -"ui/consts/issue-104768.rs", -"ui/consts/issue-105536-const-val-roundtrip-ptr-eq.rs", -"ui/consts/issue-116186.rs", -"ui/consts/issue-13837.rs", -"ui/consts/issue-13902.rs", -"ui/consts/issue-16538.rs", -"ui/consts/issue-17074.rs", -"ui/consts/issue-17458.rs", -"ui/consts/issue-17718-borrow-interior.rs", -"ui/consts/issue-17718-const-bad-values.rs", -"ui/consts/issue-17718-const-borrow.rs", -"ui/consts/issue-17718-constants-not-static.rs", -"ui/consts/issue-17718-references.rs", -"ui/consts/issue-17718.rs", -"ui/consts/issue-17756.rs", -"ui/consts/issue-18294.rs", -"ui/consts/issue-19244.rs", -"ui/consts/issue-21562.rs", -"ui/consts/issue-21721.rs", -"ui/consts/issue-23833.rs", -"ui/consts/issue-23968-const-not-overflow.rs", -"ui/consts/issue-25826.rs", -"ui/consts/issue-27890.rs", -"ui/consts/issue-28113.rs", -"ui/consts/issue-28822.rs", -"ui/consts/issue-29798.rs", -"ui/consts/issue-29914-2.rs", -"ui/consts/issue-29914-3.rs", -"ui/consts/issue-29914.rs", -"ui/consts/issue-29927-1.rs", -"ui/consts/issue-29927.rs", -"ui/consts/issue-32829-2.rs", -"ui/consts/issue-32829.rs", -"ui/consts/issue-33537.rs", -"ui/consts/issue-33903.rs", -"ui/consts/issue-3521.rs", -"ui/consts/issue-36163.rs", -"ui/consts/issue-37222.rs", -"ui/consts/issue-37550-1.rs", -"ui/consts/issue-37550.rs", -"ui/consts/issue-37991.rs", -"ui/consts/issue-39161-bogus-error.rs", -"ui/consts/issue-39974.rs", -"ui/consts/issue-43105.rs", -"ui/consts/issue-44255.rs", -"ui/consts/issue-44415.rs", -"ui/consts/issue-46553.rs", -"ui/consts/issue-47789.rs", -"ui/consts/issue-50439.rs", -"ui/consts/issue-52023-array-size-pointer-cast.rs", -"ui/consts/issue-52060.rs", -"ui/consts/issue-54224.rs", -"ui/consts/issue-54348.rs", -"ui/consts/issue-54387.rs", -"ui/consts/issue-54582.rs", -"ui/consts/issue-54954.rs", -"ui/consts/issue-56164.rs", -"ui/consts/issue-58435-ice-with-assoc-const.rs", -"ui/consts/issue-62045.rs", -"ui/consts/issue-63226.rs", -"ui/consts/issue-63952.rs", -"ui/consts/issue-64059.rs", -"ui/consts/issue-64506.rs", -"ui/consts/issue-64662.rs", -"ui/consts/issue-65348.rs", -"ui/consts/issue-66342.rs", -"ui/consts/issue-66345.rs", -"ui/consts/issue-66397.rs", -"ui/consts/issue-66693-panic-in-array-len.rs", -"ui/consts/issue-66693.rs", -"ui/consts/issue-66787.rs", -"ui/consts/issue-67529.rs", -"ui/consts/issue-67640.rs", -"ui/consts/issue-67641.rs", -"ui/consts/issue-67696-const-prop-ice.rs", -"ui/consts/issue-67862.rs", -"ui/consts/issue-68264-overflow.rs", -"ui/consts/issue-68542-closure-in-array-len.rs", -"ui/consts/issue-68684.rs", -"ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs", -"ui/consts/issue-69310-array-size-lit-wrong-ty.rs", -"ui/consts/issue-69312.rs", -"ui/consts/issue-69488.rs", -"ui/consts/issue-69532.rs", -"ui/consts/issue-6991.rs", -"ui/consts/issue-70773-mir-typeck-lt-norm.rs", -"ui/consts/issue-70942-trait-vs-impl-mismatch.rs", -"ui/consts/issue-73976-monomorphic.rs", -"ui/consts/issue-73976-polymorphic.rs", -"ui/consts/issue-76064.rs", -"ui/consts/issue-77062-large-zst-array.rs", -"ui/consts/issue-78655.rs", -"ui/consts/issue-79137-monomorphic.rs", -"ui/consts/issue-79137-toogeneric.rs", -"ui/consts/issue-79152-const-array-index.rs", -"ui/consts/issue-79690.rs", -"ui/consts/issue-87046.rs", -"ui/consts/issue-88071.rs", -"ui/consts/issue-88649.rs", -"ui/consts/issue-89088.rs", -"ui/consts/issue-90762.rs", -"ui/consts/issue-90870.rs", -"ui/consts/issue-90878-2.rs", -"ui/consts/issue-90878-3.rs", -"ui/consts/issue-90878.rs", -"ui/consts/issue-91434.rs", -"ui/consts/issue-91560.rs", -"ui/consts/issue-94371.rs", -"ui/consts/issue-94675.rs", -"ui/consts/issue-96169.rs", -"ui/coroutine/issue-102645.rs", -"ui/coroutine/issue-105084.rs", -"ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs", -"ui/coroutine/issue-113279.rs", -"ui/coroutine/issue-44197.rs", -"ui/coroutine/issue-45729-unsafe-in-coroutine.rs", -"ui/coroutine/issue-48048.rs", -"ui/coroutine/issue-52304.rs", -"ui/coroutine/issue-52398.rs", -"ui/coroutine/issue-53548-1.rs", -"ui/coroutine/issue-53548.rs", -"ui/coroutine/issue-57017.rs", -"ui/coroutine/issue-57084.rs", -"ui/coroutine/issue-57478.rs", -"ui/coroutine/issue-58888.rs", -"ui/coroutine/issue-61442-stmt-expr-with-drop.rs", -"ui/coroutine/issue-62506-two_awaits.rs", -"ui/coroutine/issue-64620-yield-array-element.rs", -"ui/coroutine/issue-68112.rs", -"ui/coroutine/issue-69017.rs", -"ui/coroutine/issue-69039.rs", -"ui/coroutine/issue-87142.rs", -"ui/coroutine/issue-88653.rs", -"ui/coroutine/issue-91477.rs", -"ui/coroutine/issue-93161.rs", -"ui/cross-crate/issue-64872/issue-64872.rs", -"ui/cycle-trait/issue-12511.rs", -"ui/debuginfo/issue-105386-debuginfo-ub.rs", -"ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs", -"ui/deprecation/issue-84637-deprecated-associated-function.rs", -"ui/derived-errors/issue-30580.rs", -"ui/derived-errors/issue-31997-1.rs", -"ui/derived-errors/issue-31997.rs", -"ui/derives/issue-36617.rs", -"ui/derives/issue-43023.rs", -"ui/derives/issue-91492.rs", -"ui/derives/issue-91550.rs", -"ui/derives/issue-97343.rs", -"ui/deriving/issue-103157.rs", -"ui/deriving/issue-15689-1.rs", -"ui/deriving/issue-15689-2.rs", -"ui/deriving/issue-18738.rs", -"ui/deriving/issue-19358.rs", -"ui/deriving/issue-3935.rs", -"ui/deriving/issue-58319.rs", -"ui/deriving/issue-6341.rs", -"ui/deriving/issue-89188-gat-hrtb.rs", -"ui/did_you_mean/issue-103909.rs", -"ui/did_you_mean/issue-105225-named-args.rs", -"ui/did_you_mean/issue-105225.rs", -"ui/did_you_mean/issue-114112.rs", -"ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.rs", -"ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.rs", -"ui/did_you_mean/issue-31424.rs", -"ui/did_you_mean/issue-34126.rs", -"ui/did_you_mean/issue-34337.rs", -"ui/did_you_mean/issue-35937.rs", -"ui/did_you_mean/issue-36798.rs", -"ui/did_you_mean/issue-36798_unknown_field.rs", -"ui/did_you_mean/issue-37139.rs", -"ui/did_you_mean/issue-38054-do-not-show-unresolved-names.rs", -"ui/did_you_mean/issue-38147-1.rs", -"ui/did_you_mean/issue-38147-2.rs", -"ui/did_you_mean/issue-38147-3.rs", -"ui/did_you_mean/issue-38147-4.rs", -"ui/did_you_mean/issue-39544.rs", -"ui/did_you_mean/issue-39802-show-5-trait-impls.rs", -"ui/did_you_mean/issue-40006.rs", -"ui/did_you_mean/issue-40396.rs", -"ui/did_you_mean/issue-40823.rs", -"ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.rs", -"ui/did_you_mean/issue-42599_available_fields_note.rs", -"ui/did_you_mean/issue-42764.rs", -"ui/did_you_mean/issue-43871-enum-instead-of-variant.rs", -"ui/did_you_mean/issue-46718-struct-pattern-dotdotdot.rs", -"ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs", -"ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.rs", -"ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs", -"ui/did_you_mean/issue-53280-expected-float-found-integer-literal.rs", -"ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs", -"ui/did_you_mean/issue-54109-without-witness.rs", -"ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs", -"ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs", -"ui/drop/auxiliary/issue-10028.rs", -"ui/drop/issue-100276.rs", -"ui/drop/issue-10028.rs", -"ui/drop/issue-103107.rs", -"ui/drop/issue-110682.rs", -"ui/drop/issue-17718-const-destructors.rs", -"ui/drop/issue-21486.rs", -"ui/drop/issue-23338-ensure-param-drop-order.rs", -"ui/drop/issue-23611-enum-swap-in-drop.rs", -"ui/drop/issue-2734.rs", -"ui/drop/issue-2735-2.rs", -"ui/drop/issue-2735-3.rs", -"ui/drop/issue-2735.rs", -"ui/drop/issue-30018-nopanic.rs", -"ui/drop/issue-35546.rs", -"ui/drop/issue-48962.rs", -"ui/drop/issue-90752-raw-ptr-shenanigans.rs", -"ui/drop/issue-90752.rs", -"ui/drop/issue-979.rs", -"ui/dropck/issue-24805-dropck-itemless.rs", -"ui/dropck/issue-28498-ugeh-with-lifetime-param.rs", -"ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs", -"ui/dropck/issue-28498-ugeh-with-trait-bound.rs", -"ui/dropck/issue-29844.rs", -"ui/dropck/issue-34053.rs", -"ui/dropck/issue-38868.rs", -"ui/dropck/issue-54943-1.rs", -"ui/dropck/issue-54943-2.rs", -"ui/dst/issue-113447.rs", -"ui/dst/issue-90528-unsizing-not-suggestion-110063.rs", -"ui/dst/issue-90528-unsizing-suggestion-1.rs", -"ui/dst/issue-90528-unsizing-suggestion-2.rs", -"ui/dst/issue-90528-unsizing-suggestion-3.rs", -"ui/dst/issue-90528-unsizing-suggestion-4.rs", -"ui/dyn-keyword/issue-5153.rs", -"ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs", -"ui/dyn-star/issue-102430.rs", -"ui/empty/issue-37026.rs", -"ui/entry-point/issue-118772.rs", -"ui/enum-discriminant/auxiliary/issue-41394.rs", -"ui/enum-discriminant/issue-104519.rs", -"ui/enum-discriminant/issue-41394-rpass.rs", -"ui/enum-discriminant/issue-41394.rs", -"ui/enum-discriminant/issue-43398.rs", -"ui/enum-discriminant/issue-46519.rs", -"ui/enum-discriminant/issue-50689.rs", -"ui/enum-discriminant/issue-51582.rs", -"ui/enum-discriminant/issue-61696.rs", -"ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs", -"ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs", -"ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs", -"ui/enum-discriminant/issue-70509-partial_eq.rs", -"ui/enum-discriminant/issue-72554.rs", -"ui/enum-discriminant/issue-90038.rs", -"ui/enum/issue-1821.rs", -"ui/enum/issue-42747.rs", -"ui/enum/issue-67945-1.rs", -"ui/enum/issue-67945-2.rs", -"ui/error-codes/e0119/auxiliary/issue-23563-a.rs", -"ui/error-codes/e0119/issue-23563.rs", -"ui/error-codes/e0119/issue-27403.rs", -"ui/error-codes/e0119/issue-28981.rs", -"ui/errors/issue-104621-extern-bad-file.rs", -"ui/errors/issue-104621-extern-not-file.rs", -"ui/errors/issue-89280-emitter-overflow-splice-lines.rs", -"ui/errors/issue-99572-impl-trait-on-pointer.rs", -"ui/expr/if/issue-4201.rs", -"ui/extern/auxiliary/issue-80074-macro-2.rs", -"ui/extern/auxiliary/issue-80074-macro.rs", -"ui/extern/issue-10025.rs", -"ui/extern/issue-10763.rs", -"ui/extern/issue-10764-rpass.rs", -"ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs", -"ui/extern/issue-116203.rs", -"ui/extern/issue-1251.rs", -"ui/extern/issue-13655.rs", -"ui/extern/issue-16250.rs", -"ui/extern/issue-18576.rs", -"ui/extern/issue-18819.rs", -"ui/extern/issue-28324.rs", -"ui/extern/issue-36122-accessing-externed-dst.rs", -"ui/extern/issue-47725.rs", -"ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs", -"ui/extern/issue-64655-extern-rust-must-allow-unwind.rs", -"ui/extern/issue-80074.rs", -"ui/extern/issue-95829.rs", -"ui/feature-gates/issue-43106-gating-of-bench.rs", -"ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs", -"ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs", -"ui/feature-gates/issue-43106-gating-of-deprecated.rs", -"ui/feature-gates/issue-43106-gating-of-derive-2.rs", -"ui/feature-gates/issue-43106-gating-of-derive.rs", -"ui/feature-gates/issue-43106-gating-of-macro_escape.rs", -"ui/feature-gates/issue-43106-gating-of-macro_use.rs", -"ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs", -"ui/feature-gates/issue-43106-gating-of-stable.rs", -"ui/feature-gates/issue-43106-gating-of-test.rs", -"ui/feature-gates/issue-43106-gating-of-unstable.rs", -"ui/feature-gates/issue-49983-see-issue-0.rs", -"ui/fmt/issue-103826.rs", -"ui/fmt/issue-104142.rs", -"ui/fmt/issue-23781.rs", -"ui/fmt/issue-75307.rs", -"ui/fmt/issue-86085.rs", -"ui/fmt/issue-89173.rs", -"ui/fmt/issue-91556.rs", -"ui/fn/issue-1451.rs", -"ui/fn/issue-1900.rs", -"ui/fn/issue-3044.rs", -"ui/fn/issue-3099.rs", -"ui/fn/issue-3904.rs", -"ui/fn/issue-39259.rs", -"ui/fn/issue-80179.rs", -"ui/for-loop-while/issue-1257.rs", -"ui/for-loop-while/issue-2216.rs", -"ui/for-loop-while/issue-51345.rs", -"ui/for-loop-while/issue-69841.rs", -"ui/for/issue-20605.rs", -"ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs", -"ui/foreign/issue-91370-foreign-fn-block-impl.rs", -"ui/foreign/issue-99276-same-type-lifetimes.rs", -"ui/function-pointer/issue-102289.rs", -"ui/functions-closures/closure-expected-type/issue-38714.rs", -"ui/generic-associated-types/bugs/issue-100013.rs", -"ui/generic-associated-types/bugs/issue-80626.rs", -"ui/generic-associated-types/bugs/issue-87735.rs", -"ui/generic-associated-types/bugs/issue-87755.rs", -"ui/generic-associated-types/bugs/issue-87803.rs", -"ui/generic-associated-types/bugs/issue-88382.rs", -"ui/generic-associated-types/bugs/issue-88460.rs", -"ui/generic-associated-types/bugs/issue-88526.rs", -"ui/generic-associated-types/bugs/issue-91762.rs", -"ui/generic-associated-types/issue-101020.rs", -"ui/generic-associated-types/issue-102114.rs", -"ui/generic-associated-types/issue-102333.rs", -"ui/generic-associated-types/issue-102335-gat.rs", -"ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs", -"ui/generic-associated-types/issue-47206-where-clause.rs", -"ui/generic-associated-types/issue-58694-parameter-out-of-range.rs", -"ui/generic-associated-types/issue-62326-parameter-out-of-range.rs", -"ui/generic-associated-types/issue-67424.rs", -"ui/generic-associated-types/issue-67510-pass.rs", -"ui/generic-associated-types/issue-67510.rs", -"ui/generic-associated-types/issue-68641-check-gat-bounds.rs", -"ui/generic-associated-types/issue-68642-broken-llvm-ir.rs", -"ui/generic-associated-types/issue-68643-broken-mir.rs", -"ui/generic-associated-types/issue-68644-codegen-selection.rs", -"ui/generic-associated-types/issue-68645-codegen-fulfillment.rs", -"ui/generic-associated-types/issue-68648-1.rs", -"ui/generic-associated-types/issue-68648-2.rs", -"ui/generic-associated-types/issue-68649-pass.rs", -"ui/generic-associated-types/issue-68653.rs", -"ui/generic-associated-types/issue-68656-unsized-values.rs", -"ui/generic-associated-types/issue-70303.rs", -"ui/generic-associated-types/issue-70304.rs", -"ui/generic-associated-types/issue-71176.rs", -"ui/generic-associated-types/issue-74684-1.rs", -"ui/generic-associated-types/issue-74684-2.rs", -"ui/generic-associated-types/issue-74816.rs", -"ui/generic-associated-types/issue-74824.rs", -"ui/generic-associated-types/issue-76407.rs", -"ui/generic-associated-types/issue-76535.rs", -"ui/generic-associated-types/issue-76826.rs", -"ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs", -"ui/generic-associated-types/issue-78671.rs", -"ui/generic-associated-types/issue-79422.rs", -"ui/generic-associated-types/issue-79636-1.rs", -"ui/generic-associated-types/issue-79636-2.rs", -"ui/generic-associated-types/issue-80433-reduced.rs", -"ui/generic-associated-types/issue-80433.rs", -"ui/generic-associated-types/issue-81487.rs", -"ui/generic-associated-types/issue-81712-cyclic-traits.rs", -"ui/generic-associated-types/issue-81862.rs", -"ui/generic-associated-types/issue-84931.rs", -"ui/generic-associated-types/issue-85921.rs", -"ui/generic-associated-types/issue-86218-2.rs", -"ui/generic-associated-types/issue-86218.rs", -"ui/generic-associated-types/issue-86483.rs", -"ui/generic-associated-types/issue-86787.rs", -"ui/generic-associated-types/issue-87258_a.rs", -"ui/generic-associated-types/issue-87258_b.rs", -"ui/generic-associated-types/issue-87429-2.rs", -"ui/generic-associated-types/issue-87429-associated-type-default.rs", -"ui/generic-associated-types/issue-87429-specialization.rs", -"ui/generic-associated-types/issue-87429.rs", -"ui/generic-associated-types/issue-87748.rs", -"ui/generic-associated-types/issue-87750.rs", -"ui/generic-associated-types/issue-88287.rs", -"ui/generic-associated-types/issue-88360.rs", -"ui/generic-associated-types/issue-88405.rs", -"ui/generic-associated-types/issue-88459.rs", -"ui/generic-associated-types/issue-88595.rs", -"ui/generic-associated-types/issue-89008.rs", -"ui/generic-associated-types/issue-89352.rs", -"ui/generic-associated-types/issue-90014-tait.rs", -"ui/generic-associated-types/issue-90014-tait2.rs", -"ui/generic-associated-types/issue-90014.rs", -"ui/generic-associated-types/issue-90729.rs", -"ui/generic-associated-types/issue-91139.rs", -"ui/generic-associated-types/issue-91883.rs", -"ui/generic-associated-types/issue-92033.rs", -"ui/generic-associated-types/issue-92096.rs", -"ui/generic-associated-types/issue-92280.rs", -"ui/generic-associated-types/issue-92954.rs", -"ui/generic-associated-types/issue-93141.rs", -"ui/generic-associated-types/issue-93262.rs", -"ui/generic-associated-types/issue-93341.rs", -"ui/generic-associated-types/issue-93342.rs", -"ui/generic-associated-types/issue-93874.rs", -"ui/generic-associated-types/issue-95305.rs", -"ui/generics/issue-106694.rs", -"ui/generics/issue-1112.rs", -"ui/generics/issue-2936.rs", -"ui/generics/issue-32498.rs", -"ui/generics/issue-333.rs", -"ui/generics/issue-59508-1.rs", -"ui/generics/issue-59508.rs", -"ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs", -"ui/generics/issue-61631-default-type-param-cannot-reference-self.rs", -"ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs", -"ui/generics/issue-79605.rs", -"ui/generics/issue-80512-param-reordering-with-defaults.rs", -"ui/generics/issue-83556.rs", -"ui/generics/issue-94432-garbage-ice.rs", -"ui/generics/issue-94923.rs", -"ui/generics/issue-95208-ignore-qself.rs", -"ui/generics/issue-95208.rs", -"ui/generics/issue-98432.rs", -"ui/higher-ranked/trait-bounds/issue-100689.rs", -"ui/higher-ranked/trait-bounds/issue-102899.rs", -"ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs", -"ui/higher-ranked/trait-bounds/issue-39292.rs", -"ui/higher-ranked/trait-bounds/issue-42114.rs", -"ui/higher-ranked/trait-bounds/issue-43623.rs", -"ui/higher-ranked/trait-bounds/issue-46989.rs", -"ui/higher-ranked/trait-bounds/issue-57639.rs", -"ui/higher-ranked/trait-bounds/issue-58451.rs", -"ui/higher-ranked/trait-bounds/issue-59311.rs", -"ui/higher-ranked/trait-bounds/issue-60283.rs", -"ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs", -"ui/higher-ranked/trait-bounds/issue-88446.rs", -"ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs", -"ui/higher-ranked/trait-bounds/issue-90177.rs", -"ui/higher-ranked/trait-bounds/issue-95034.rs", -"ui/higher-ranked/trait-bounds/issue-95230.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs", -"ui/hygiene/issue-15221.rs", -"ui/hygiene/issue-29746.rs", -"ui/hygiene/issue-32922.rs", -"ui/hygiene/issue-40847.rs", -"ui/hygiene/issue-44128.rs", -"ui/hygiene/issue-47311.rs", -"ui/hygiene/issue-47312.rs", -"ui/hygiene/issue-61574-const-parameters.rs", -"ui/hygiene/issue-77523-def-site-async-await.rs", -"ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs", -"ui/impl-trait/in-trait/issue-102140.rs", -"ui/impl-trait/in-trait/issue-102301.rs", -"ui/impl-trait/in-trait/issue-102571.rs", -"ui/impl-trait/issue-100075-2.rs", -"ui/impl-trait/issue-100075.rs", -"ui/impl-trait/issue-100187.rs", -"ui/impl-trait/issue-102605.rs", -"ui/impl-trait/issue-103181-1.rs", -"ui/impl-trait/issue-103181-2.rs", -"ui/impl-trait/issue-103599.rs", -"ui/impl-trait/issue-108591.rs", -"ui/impl-trait/issue-108592.rs", -"ui/impl-trait/issue-35668.rs", -"ui/impl-trait/issue-36792.rs", -"ui/impl-trait/issue-46959.rs", -"ui/impl-trait/issue-49556.rs", -"ui/impl-trait/issue-49579.rs", -"ui/impl-trait/issue-49685.rs", -"ui/impl-trait/issue-51185.rs", -"ui/impl-trait/issue-54966.rs", -"ui/impl-trait/issue-55872-1.rs", -"ui/impl-trait/issue-55872-2.rs", -"ui/impl-trait/issue-55872-3.rs", -"ui/impl-trait/issue-55872.rs", -"ui/impl-trait/issue-56445.rs", -"ui/impl-trait/issue-68532.rs", -"ui/impl-trait/issue-72911.rs", -"ui/impl-trait/issue-87450.rs", -"ui/impl-trait/issue-99073-2.rs", -"ui/impl-trait/issue-99073.rs", -"ui/impl-trait/issue-99642-2.rs", -"ui/impl-trait/issue-99642.rs", -"ui/impl-trait/issue-99914.rs", -"ui/impl-trait/issues/issue-104815.rs", -"ui/impl-trait/issues/issue-105826.rs", -"ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs", -"ui/impl-trait/issues/issue-42479.rs", -"ui/impl-trait/issues/issue-49376.rs", -"ui/impl-trait/issues/issue-52128.rs", -"ui/impl-trait/issues/issue-53457.rs", -"ui/impl-trait/issues/issue-54600.rs", -"ui/impl-trait/issues/issue-54840.rs", -"ui/impl-trait/issues/issue-54895.rs", -"ui/impl-trait/issues/issue-55608-captures-empty-region.rs", -"ui/impl-trait/issues/issue-57464-unexpected-regions.rs", -"ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs", -"ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs", -"ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs", -"ui/impl-trait/issues/issue-58504.rs", -"ui/impl-trait/issues/issue-58956.rs", -"ui/impl-trait/issues/issue-62742.rs", -"ui/impl-trait/issues/issue-65581.rs", -"ui/impl-trait/issues/issue-67830.rs", -"ui/impl-trait/issues/issue-70877.rs", -"ui/impl-trait/issues/issue-70971.rs", -"ui/impl-trait/issues/issue-74282.rs", -"ui/impl-trait/issues/issue-77987.rs", -"ui/impl-trait/issues/issue-78722-2.rs", -"ui/impl-trait/issues/issue-78722.rs", -"ui/impl-trait/issues/issue-79099.rs", -"ui/impl-trait/issues/issue-82139.rs", -"ui/impl-trait/issues/issue-83919.rs", -"ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs", -"ui/impl-trait/issues/issue-84073.rs", -"ui/impl-trait/issues/issue-84919.rs", -"ui/impl-trait/issues/issue-86201.rs", -"ui/impl-trait/issues/issue-86642.rs", -"ui/impl-trait/issues/issue-86719.rs", -"ui/impl-trait/issues/issue-86800.rs", -"ui/impl-trait/issues/issue-87295.rs", -"ui/impl-trait/issues/issue-87340.rs", -"ui/impl-trait/issues/issue-88236-2.rs", -"ui/impl-trait/issues/issue-88236.rs", -"ui/impl-trait/issues/issue-89312.rs", -"ui/impl-trait/issues/issue-92305.rs", -"ui/impl-trait/issues/issue-93788.rs", -"ui/impl-trait/issues/issue-99348-impl-compatibility.rs", -"ui/implied-bounds/issue-100690.rs", -"ui/implied-bounds/issue-101951.rs", -"ui/implied-bounds/issue-110161.rs", -"ui/imports/auxiliary/issue-114682-2-extern.rs", -"ui/imports/auxiliary/issue-114682-3-extern.rs", -"ui/imports/auxiliary/issue-114682-4-extern.rs", -"ui/imports/auxiliary/issue-114682-5-extern-1.rs", -"ui/imports/auxiliary/issue-114682-5-extern-2.rs", -"ui/imports/auxiliary/issue-114682-6-extern.rs", -"ui/imports/auxiliary/issue-119369-extern.rs", -"ui/imports/auxiliary/issue-36881-aux.rs", -"ui/imports/auxiliary/issue-52891.rs", -"ui/imports/auxiliary/issue-55811.rs", -"ui/imports/auxiliary/issue-56125.rs", -"ui/imports/auxiliary/issue-59764.rs", -"ui/imports/auxiliary/issue-85992-extern-1.rs", -"ui/imports/auxiliary/issue-85992-extern-2.rs", -"ui/imports/issue-109148.rs", -"ui/imports/issue-109343.rs", -"ui/imports/issue-113953.rs", -"ui/imports/issue-114682-1.rs", -"ui/imports/issue-114682-2.rs", -"ui/imports/issue-114682-3.rs", -"ui/imports/issue-114682-4.rs", -"ui/imports/issue-114682-5.rs", -"ui/imports/issue-114682-6.rs", -"ui/imports/issue-119369.rs", -"ui/imports/issue-13404.rs", -"ui/imports/issue-1697.rs", -"ui/imports/issue-18083.rs", -"ui/imports/issue-19498.rs", -"ui/imports/issue-24081.rs", -"ui/imports/issue-24883.rs", -"ui/imports/issue-25396.rs", -"ui/imports/issue-26873-multifile/issue-26873-multifile.rs", -"ui/imports/issue-26873-multifile/issue-26873-onefile.rs", -"ui/imports/issue-26886.rs", -"ui/imports/issue-26930.rs", -"ui/imports/issue-28134.rs", -"ui/imports/issue-28388-1.rs", -"ui/imports/issue-28388-2.rs", -"ui/imports/issue-2937.rs", -"ui/imports/issue-30560.rs", -"ui/imports/issue-31212.rs", -"ui/imports/issue-32119.rs", -"ui/imports/issue-32222.rs", -"ui/imports/issue-32354-suggest-import-rename.rs", -"ui/imports/issue-32833.rs", -"ui/imports/issue-33464.rs", -"ui/imports/issue-36881.rs", -"ui/imports/issue-37887.rs", -"ui/imports/issue-38293.rs", -"ui/imports/issue-4366-2.rs", -"ui/imports/issue-4366.rs", -"ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs", -"ui/imports/issue-45829/auxiliary/issue-45829-a.rs", -"ui/imports/issue-45829/auxiliary/issue-45829-b.rs", -"ui/imports/issue-45829/issue-45829.rs", -"ui/imports/issue-47623.rs", -"ui/imports/issue-4865-1.rs", -"ui/imports/issue-4865-2.rs", -"ui/imports/issue-4865-3.rs", -"ui/imports/issue-52891.rs", -"ui/imports/issue-53140.rs", -"ui/imports/issue-53269.rs", -"ui/imports/issue-53512.rs", -"ui/imports/issue-53565.rs", -"ui/imports/issue-55457.rs", -"ui/imports/issue-55811.rs", -"ui/imports/issue-55884-1.rs", -"ui/imports/issue-55884-2.rs", -"ui/imports/issue-56125.rs", -"ui/imports/issue-56263.rs", -"ui/imports/issue-57015.rs", -"ui/imports/issue-57539.rs", -"ui/imports/issue-59764.rs", -"ui/imports/issue-62767.rs", -"ui/imports/issue-68103.rs", -"ui/imports/issue-81413.rs", -"ui/imports/issue-8208.rs", -"ui/imports/issue-85992.rs", -"ui/imports/issue-8640.rs", -"ui/imports/issue-99695-b.rs", -"ui/imports/issue-99695.rs", -"ui/inference/issue-103587.rs", -"ui/inference/issue-104649.rs", -"ui/inference/issue-107090.rs", -"ui/inference/issue-113354.rs", -"ui/inference/issue-12028.rs", -"ui/inference/issue-28935.rs", -"ui/inference/issue-36053.rs", -"ui/inference/issue-3743.rs", -"ui/inference/issue-70082.rs", -"ui/inference/issue-70703.rs", -"ui/inference/issue-71309.rs", -"ui/inference/issue-71584.rs", -"ui/inference/issue-71732.rs", -"ui/inference/issue-72616.rs", -"ui/inference/issue-72690.rs", -"ui/inference/issue-80409.rs", -"ui/inference/issue-80816.rs", -"ui/inference/issue-81522.rs", -"ui/inference/issue-83606.rs", -"ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs", -"ui/inference/issue-86162-1.rs", -"ui/inference/issue-86162-2.rs", -"ui/inference/need_type_info/issue-103053.rs", -"ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs", -"ui/inference/need_type_info/issue-109905.rs", -"ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs", -"ui/infinite/issue-41731-infinite-macro-print.rs", -"ui/infinite/issue-41731-infinite-macro-println.rs", -"ui/intrinsics/issue-28575.rs", -"ui/intrinsics/issue-84297-reifying-copy.rs", -"ui/invalid/issue-114435-layout-type-err.rs", -"ui/issue-11881.rs", -"ui/issue-13560.rs", -"ui/issue-15924.rs", -"ui/issue-16822.rs", -"ui/issue-18502.rs", -"ui/issue-24106.rs", -"ui/issue-76387-llvm-miscompile.rs", -"ui/issues-71798.rs", -"ui/issues/auxiliary/issue-111011.rs", -"ui/issues/auxiliary/issue-11224.rs", -"ui/issues/auxiliary/issue-11508.rs", -"ui/issues/auxiliary/issue-11529.rs", -"ui/issues/auxiliary/issue-11680.rs", -"ui/issues/auxiliary/issue-12133-dylib.rs", -"ui/issues/auxiliary/issue-12133-dylib2.rs", -"ui/issues/auxiliary/issue-12133-rlib.rs", -"ui/issues/auxiliary/issue-12612-1.rs", -"ui/issues/auxiliary/issue-12612-2.rs", -"ui/issues/auxiliary/issue-12660-aux.rs", -"ui/issues/auxiliary/issue-13507.rs", -"ui/issues/auxiliary/issue-13620-1.rs", -"ui/issues/auxiliary/issue-13620-2.rs", -"ui/issues/auxiliary/issue-13872-1.rs", -"ui/issues/auxiliary/issue-13872-2.rs", -"ui/issues/auxiliary/issue-13872-3.rs", -"ui/issues/auxiliary/issue-14344-1.rs", -"ui/issues/auxiliary/issue-14344-2.rs", -"ui/issues/auxiliary/issue-14421.rs", -"ui/issues/auxiliary/issue-14422.rs", -"ui/issues/auxiliary/issue-15562.rs", -"ui/issues/auxiliary/issue-16643.rs", -"ui/issues/auxiliary/issue-16725.rs", -"ui/issues/auxiliary/issue-17662.rs", -"ui/issues/auxiliary/issue-18501.rs", -"ui/issues/auxiliary/issue-18514.rs", -"ui/issues/auxiliary/issue-18711.rs", -"ui/issues/auxiliary/issue-18913-1.rs", -"ui/issues/auxiliary/issue-18913-2.rs", -"ui/issues/auxiliary/issue-19293.rs", -"ui/issues/auxiliary/issue-19340-1.rs", -"ui/issues/auxiliary/issue-20389.rs", -"ui/issues/auxiliary/issue-21202.rs", -"ui/issues/auxiliary/issue-2170-lib.rs", -"ui/issues/auxiliary/issue-2316-a.rs", -"ui/issues/auxiliary/issue-2316-b.rs", -"ui/issues/auxiliary/issue-2380.rs", -"ui/issues/auxiliary/issue-2414-a.rs", -"ui/issues/auxiliary/issue-2414-b.rs", -"ui/issues/auxiliary/issue-2472-b.rs", -"ui/issues/auxiliary/issue-25185-1.rs", -"ui/issues/auxiliary/issue-25185-2.rs", -"ui/issues/auxiliary/issue-2526.rs", -"ui/issues/auxiliary/issue-25467.rs", -"ui/issues/auxiliary/issue-2631-a.rs", -"ui/issues/auxiliary/issue-2723-a.rs", -"ui/issues/auxiliary/issue-29265.rs", -"ui/issues/auxiliary/issue-29485.rs", -"ui/issues/auxiliary/issue-3012-1.rs", -"ui/issues/auxiliary/issue-30123-aux.rs", -"ui/issues/auxiliary/issue-3136-a.rs", -"ui/issues/auxiliary/issue-31702-1.rs", -"ui/issues/auxiliary/issue-31702-2.rs", -"ui/issues/auxiliary/issue-34796-aux.rs", -"ui/issues/auxiliary/issue-36954.rs", -"ui/issues/auxiliary/issue-38190.rs", -"ui/issues/auxiliary/issue-38226-aux.rs", -"ui/issues/auxiliary/issue-3979-traits.rs", -"ui/issues/auxiliary/issue-41053.rs", -"ui/issues/auxiliary/issue-41549.rs", -"ui/issues/auxiliary/issue-42007-s.rs", -"ui/issues/auxiliary/issue-4208-cc.rs", -"ui/issues/auxiliary/issue-4545.rs", -"ui/issues/auxiliary/issue-48984-aux.rs", -"ui/issues/auxiliary/issue-49544.rs", -"ui/issues/auxiliary/issue-51798.rs", -"ui/issues/auxiliary/issue-52489.rs", -"ui/issues/auxiliary/issue-5518.rs", -"ui/issues/auxiliary/issue-5521.rs", -"ui/issues/auxiliary/issue-56943.rs", -"ui/issues/auxiliary/issue-57271-lib.rs", -"ui/issues/auxiliary/issue-5844-aux.rs", -"ui/issues/auxiliary/issue-7178.rs", -"ui/issues/auxiliary/issue-73112.rs", -"ui/issues/auxiliary/issue-7899.rs", -"ui/issues/auxiliary/issue-8044.rs", -"ui/issues/auxiliary/issue-8259.rs", -"ui/issues/auxiliary/issue-8401.rs", -"ui/issues/auxiliary/issue-9123.rs", -"ui/issues/auxiliary/issue-9155.rs", -"ui/issues/auxiliary/issue-9188.rs", -"ui/issues/auxiliary/issue-9906.rs", -"ui/issues/auxiliary/issue-9968.rs", -"ui/issues/issue-10228.rs", -"ui/issues/issue-10291.rs", -"ui/issues/issue-102964.rs", -"ui/issues/issue-10396.rs", -"ui/issues/issue-10412.rs", -"ui/issues/issue-10436.rs", -"ui/issues/issue-10456.rs", -"ui/issues/issue-10465.rs", -"ui/issues/issue-10545.rs", -"ui/issues/issue-10638.rs", -"ui/issues/issue-10656.rs", -"ui/issues/issue-106755.rs", -"ui/issues/issue-10683.rs", -"ui/issues/issue-10718.rs", -"ui/issues/issue-10734.rs", -"ui/issues/issue-10764.rs", -"ui/issues/issue-10767.rs", -"ui/issues/issue-10802.rs", -"ui/issues/issue-10806.rs", -"ui/issues/issue-10853.rs", -"ui/issues/issue-10877.rs", -"ui/issues/issue-10902.rs", -"ui/issues/issue-11004.rs", -"ui/issues/issue-11047.rs", -"ui/issues/issue-11085.rs", -"ui/issues/issue-11192.rs", -"ui/issues/issue-11205.rs", -"ui/issues/issue-11224.rs", -"ui/issues/issue-11267.rs", -"ui/issues/issue-11374.rs", -"ui/issues/issue-11382.rs", -"ui/issues/issue-11384.rs", -"ui/issues/issue-11508.rs", -"ui/issues/issue-11529.rs", -"ui/issues/issue-11552.rs", -"ui/issues/issue-11592.rs", -"ui/issues/issue-11677.rs", -"ui/issues/issue-11680.rs", -"ui/issues/issue-11681.rs", -"ui/issues/issue-11692-1.rs", -"ui/issues/issue-11692-2.rs", -"ui/issues/issue-11709.rs", -"ui/issues/issue-11740.rs", -"ui/issues/issue-11771.rs", -"ui/issues/issue-11820.rs", -"ui/issues/issue-11844.rs", -"ui/issues/issue-11869.rs", -"ui/issues/issue-11958.rs", -"ui/issues/issue-12033.rs", -"ui/issues/issue-12041.rs", -"ui/issues/issue-12127.rs", -"ui/issues/issue-12133-1.rs", -"ui/issues/issue-12133-2.rs", -"ui/issues/issue-12133-3.rs", -"ui/issues/issue-12187-1.rs", -"ui/issues/issue-12187-2.rs", -"ui/issues/issue-12285.rs", -"ui/issues/issue-12567.rs", -"ui/issues/issue-12612.rs", -"ui/issues/issue-12660.rs", -"ui/issues/issue-12677.rs", -"ui/issues/issue-12699.rs", -"ui/issues/issue-12729.rs", -"ui/issues/issue-12744.rs", -"ui/issues/issue-12860.rs", -"ui/issues/issue-12863.rs", -"ui/issues/issue-12909.rs", -"ui/issues/issue-12920.rs", -"ui/issues/issue-13027.rs", -"ui/issues/issue-13058.rs", -"ui/issues/issue-13105.rs", -"ui/issues/issue-13167.rs", -"ui/issues/issue-13202.rs", -"ui/issues/issue-13204.rs", -"ui/issues/issue-13214.rs", -"ui/issues/issue-13259-windows-tcb-trash.rs", -"ui/issues/issue-13264.rs", -"ui/issues/issue-13323.rs", -"ui/issues/issue-13359.rs", -"ui/issues/issue-13405.rs", -"ui/issues/issue-13407.rs", -"ui/issues/issue-13434.rs", -"ui/issues/issue-13446.rs", -"ui/issues/issue-13466.rs", -"ui/issues/issue-13482-2.rs", -"ui/issues/issue-13482.rs", -"ui/issues/issue-13497-2.rs", -"ui/issues/issue-13497.rs", -"ui/issues/issue-13507-2.rs", -"ui/issues/issue-13620.rs", -"ui/issues/issue-13665.rs", -"ui/issues/issue-13703.rs", -"ui/issues/issue-13763.rs", -"ui/issues/issue-13775.rs", -"ui/issues/issue-13808.rs", -"ui/issues/issue-13847.rs", -"ui/issues/issue-13867.rs", -"ui/issues/issue-13872.rs", -"ui/issues/issue-14082.rs", -"ui/issues/issue-14091-2.rs", -"ui/issues/issue-14091.rs", -"ui/issues/issue-14092.rs", -"ui/issues/issue-14229.rs", -"ui/issues/issue-14254.rs", -"ui/issues/issue-14285.rs", -"ui/issues/issue-14308.rs", -"ui/issues/issue-14330.rs", -"ui/issues/issue-14344.rs", -"ui/issues/issue-14366.rs", -"ui/issues/issue-14382.rs", -"ui/issues/issue-14393.rs", -"ui/issues/issue-14399.rs", -"ui/issues/issue-14421.rs", -"ui/issues/issue-14422.rs", -"ui/issues/issue-14541.rs", -"ui/issues/issue-14721.rs", -"ui/issues/issue-14821.rs", -"ui/issues/issue-14845.rs", -"ui/issues/issue-14853.rs", -"ui/issues/issue-14865.rs", -"ui/issues/issue-14875.rs", -"ui/issues/issue-14901.rs", -"ui/issues/issue-14915.rs", -"ui/issues/issue-14919.rs", -"ui/issues/issue-14959.rs", -"ui/issues/issue-15034.rs", -"ui/issues/issue-15043.rs", -"ui/issues/issue-15063.rs", -"ui/issues/issue-15094.rs", -"ui/issues/issue-15104.rs", -"ui/issues/issue-15129-rpass.rs", -"ui/issues/issue-15167.rs", -"ui/issues/issue-15189.rs", -"ui/issues/issue-15207.rs", -"ui/issues/issue-15260.rs", -"ui/issues/issue-15381.rs", -"ui/issues/issue-15444.rs", -"ui/issues/issue-15523-big.rs", -"ui/issues/issue-15523.rs", -"ui/issues/issue-15562.rs", -"ui/issues/issue-15571.rs", -"ui/issues/issue-15673.rs", -"ui/issues/issue-15734.rs", -"ui/issues/issue-15735.rs", -"ui/issues/issue-15756.rs", -"ui/issues/issue-15763.rs", -"ui/issues/issue-15774.rs", -"ui/issues/issue-15783.rs", -"ui/issues/issue-15793.rs", -"ui/issues/issue-15858.rs", -"ui/issues/issue-15896.rs", -"ui/issues/issue-15965.rs", -"ui/issues/issue-16048.rs", -"ui/issues/issue-16149.rs", -"ui/issues/issue-16151.rs", -"ui/issues/issue-16256.rs", -"ui/issues/issue-16278.rs", -"ui/issues/issue-16401.rs", -"ui/issues/issue-16441.rs", -"ui/issues/issue-16452.rs", -"ui/issues/issue-16492.rs", -"ui/issues/issue-16530.rs", -"ui/issues/issue-16560.rs", -"ui/issues/issue-16562.rs", -"ui/issues/issue-16596.rs", -"ui/issues/issue-16643.rs", -"ui/issues/issue-16648.rs", -"ui/issues/issue-16668.rs", -"ui/issues/issue-16671.rs", -"ui/issues/issue-16683.rs", -"ui/issues/issue-16725.rs", -"ui/issues/issue-16739.rs", -"ui/issues/issue-16745.rs", -"ui/issues/issue-16774.rs", -"ui/issues/issue-16783.rs", -"ui/issues/issue-16819.rs", -"ui/issues/issue-16922-rpass.rs", -"ui/issues/issue-16939.rs", -"ui/issues/issue-16966.rs", -"ui/issues/issue-16994.rs", -"ui/issues/issue-17001.rs", -"ui/issues/issue-17033.rs", -"ui/issues/issue-17068.rs", -"ui/issues/issue-17121.rs", -"ui/issues/issue-17216.rs", -"ui/issues/issue-17252.rs", -"ui/issues/issue-17302.rs", -"ui/issues/issue-17322.rs", -"ui/issues/issue-17336.rs", -"ui/issues/issue-17337.rs", -"ui/issues/issue-17351.rs", -"ui/issues/issue-17361.rs", -"ui/issues/issue-17373.rs", -"ui/issues/issue-17385.rs", -"ui/issues/issue-17405.rs", -"ui/issues/issue-17441.rs", -"ui/issues/issue-17450.rs", -"ui/issues/issue-17503.rs", -"ui/issues/issue-17546.rs", -"ui/issues/issue-17551.rs", -"ui/issues/issue-17651.rs", -"ui/issues/issue-17662.rs", -"ui/issues/issue-17732.rs", -"ui/issues/issue-17734.rs", -"ui/issues/issue-17740.rs", -"ui/issues/issue-17746.rs", -"ui/issues/issue-17758.rs", -"ui/issues/issue-17771.rs", -"ui/issues/issue-17800.rs", -"ui/issues/issue-17816.rs", -"ui/issues/issue-17877.rs", -"ui/issues/issue-17897.rs", -"ui/issues/issue-17904-2.rs", -"ui/issues/issue-17904.rs", -"ui/issues/issue-17905-2.rs", -"ui/issues/issue-17905.rs", -"ui/issues/issue-17933.rs", -"ui/issues/issue-17954.rs", -"ui/issues/issue-17959.rs", -"ui/issues/issue-17994.rs", -"ui/issues/issue-17999.rs", -"ui/issues/issue-18058.rs", -"ui/issues/issue-18088.rs", -"ui/issues/issue-18107.rs", -"ui/issues/issue-18110.rs", -"ui/issues/issue-18119.rs", -"ui/issues/issue-18159.rs", -"ui/issues/issue-18173.rs", -"ui/issues/issue-18183.rs", -"ui/issues/issue-18188.rs", -"ui/issues/issue-18232.rs", -"ui/issues/issue-18352.rs", -"ui/issues/issue-18353.rs", -"ui/issues/issue-18389.rs", -"ui/issues/issue-18423.rs", -"ui/issues/issue-18446-2.rs", -"ui/issues/issue-18446.rs", -"ui/issues/issue-18464.rs", -"ui/issues/issue-18501.rs", -"ui/issues/issue-18514.rs", -"ui/issues/issue-18532.rs", -"ui/issues/issue-18539.rs", -"ui/issues/issue-18566.rs", -"ui/issues/issue-18611.rs", -"ui/issues/issue-18685.rs", -"ui/issues/issue-18711.rs", -"ui/issues/issue-18767.rs", -"ui/issues/issue-18783.rs", -"ui/issues/issue-18809.rs", -"ui/issues/issue-18845.rs", -"ui/issues/issue-18859.rs", -"ui/issues/issue-18906.rs", -"ui/issues/issue-18913.rs", -"ui/issues/issue-18919.rs", -"ui/issues/issue-18952.rs", -"ui/issues/issue-18959.rs", -"ui/issues/issue-18988.rs", -"ui/issues/issue-19001.rs", -"ui/issues/issue-19037.rs", -"ui/issues/issue-19086.rs", -"ui/issues/issue-19097.rs", -"ui/issues/issue-19098.rs", -"ui/issues/issue-19100.rs", -"ui/issues/issue-19127.rs", -"ui/issues/issue-19129-1.rs", -"ui/issues/issue-19129-2.rs", -"ui/issues/issue-19135.rs", -"ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs", -"ui/issues/issue-1920-absolute-paths/issue-1920-1.rs", -"ui/issues/issue-1920-absolute-paths/issue-1920-2.rs", -"ui/issues/issue-1920-absolute-paths/issue-1920-3.rs", -"ui/issues/issue-19244-1.rs", -"ui/issues/issue-19244-2.rs", -"ui/issues/issue-19293.rs", -"ui/issues/issue-19340-1.rs", -"ui/issues/issue-19340-2.rs", -"ui/issues/issue-19367.rs", -"ui/issues/issue-19380.rs", -"ui/issues/issue-19398.rs", -"ui/issues/issue-19404.rs", -"ui/issues/issue-19479.rs", -"ui/issues/issue-19482.rs", -"ui/issues/issue-19499.rs", -"ui/issues/issue-19601.rs", -"ui/issues/issue-19631.rs", -"ui/issues/issue-19632.rs", -"ui/issues/issue-19692.rs", -"ui/issues/issue-19734.rs", -"ui/issues/issue-19811-escape-unicode.rs", -"ui/issues/issue-19850.rs", -"ui/issues/issue-19922.rs", -"ui/issues/issue-19982.rs", -"ui/issues/issue-19991.rs", -"ui/issues/issue-20009.rs", -"ui/issues/issue-20055-box-trait.rs", -"ui/issues/issue-20055-box-unsized-array.rs", -"ui/issues/issue-20162.rs", -"ui/issues/issue-20174.rs", -"ui/issues/issue-20186.rs", -"ui/issues/issue-20225.rs", -"ui/issues/issue-20261.rs", -"ui/issues/issue-20313-rpass.rs", -"ui/issues/issue-20313.rs", -"ui/issues/issue-20389.rs", -"ui/issues/issue-20396.rs", -"ui/issues/issue-20413.rs", -"ui/issues/issue-20414.rs", -"ui/issues/issue-20427.rs", -"ui/issues/issue-20433.rs", -"ui/issues/issue-20454.rs", -"ui/issues/issue-20544.rs", -"ui/issues/issue-20575.rs", -"ui/issues/issue-20644.rs", -"ui/issues/issue-20676.rs", -"ui/issues/issue-20714.rs", -"ui/issues/issue-2074.rs", -"ui/issues/issue-20763-1.rs", -"ui/issues/issue-20763-2.rs", -"ui/issues/issue-20772.rs", -"ui/issues/issue-20797.rs", -"ui/issues/issue-20803.rs", -"ui/issues/issue-20831-debruijn.rs", -"ui/issues/issue-20847.rs", -"ui/issues/issue-20939.rs", -"ui/issues/issue-20953.rs", -"ui/issues/issue-20971.rs", -"ui/issues/issue-21033.rs", -"ui/issues/issue-21140.rs", -"ui/issues/issue-21160.rs", -"ui/issues/issue-21174-2.rs", -"ui/issues/issue-21174.rs", -"ui/issues/issue-21177.rs", -"ui/issues/issue-21202.rs", -"ui/issues/issue-21245.rs", -"ui/issues/issue-21291.rs", -"ui/issues/issue-21306.rs", -"ui/issues/issue-21332.rs", -"ui/issues/issue-21361.rs", -"ui/issues/issue-21384.rs", -"ui/issues/issue-21400.rs", -"ui/issues/issue-21402.rs", -"ui/issues/issue-21449.rs", -"ui/issues/issue-2150.rs", -"ui/issues/issue-2151.rs", -"ui/issues/issue-21546.rs", -"ui/issues/issue-21554.rs", -"ui/issues/issue-21596.rs", -"ui/issues/issue-21600.rs", -"ui/issues/issue-21622.rs", -"ui/issues/issue-21634.rs", -"ui/issues/issue-21655.rs", -"ui/issues/issue-2170-exe.rs", -"ui/issues/issue-21701.rs", -"ui/issues/issue-21763.rs", -"ui/issues/issue-21891.rs", -"ui/issues/issue-2190-1.rs", -"ui/issues/issue-21909.rs", -"ui/issues/issue-21922.rs", -"ui/issues/issue-21946.rs", -"ui/issues/issue-21950.rs", -"ui/issues/issue-21974.rs", -"ui/issues/issue-22008.rs", -"ui/issues/issue-22034.rs", -"ui/issues/issue-22036.rs", -"ui/issues/issue-2214.rs", -"ui/issues/issue-22258.rs", -"ui/issues/issue-22289.rs", -"ui/issues/issue-22312.rs", -"ui/issues/issue-22346.rs", -"ui/issues/issue-22356.rs", -"ui/issues/issue-22370.rs", -"ui/issues/issue-22403.rs", -"ui/issues/issue-22426.rs", -"ui/issues/issue-22434.rs", -"ui/issues/issue-22468.rs", -"ui/issues/issue-22471.rs", -"ui/issues/issue-22577.rs", -"ui/issues/issue-22599.rs", -"ui/issues/issue-22603.rs", -"ui/issues/issue-22629.rs", -"ui/issues/issue-22638.rs", -"ui/issues/issue-22644.rs", -"ui/issues/issue-22673.rs", -"ui/issues/issue-22684.rs", -"ui/issues/issue-22706.rs", -"ui/issues/issue-22777.rs", -"ui/issues/issue-22781.rs", -"ui/issues/issue-22789.rs", -"ui/issues/issue-2281-part1.rs", -"ui/issues/issue-22814.rs", -"ui/issues/issue-2284.rs", -"ui/issues/issue-22864-1.rs", -"ui/issues/issue-22864-2.rs", -"ui/issues/issue-22872.rs", -"ui/issues/issue-22874.rs", -"ui/issues/issue-2288.rs", -"ui/issues/issue-22886.rs", -"ui/issues/issue-22894.rs", -"ui/issues/issue-22933-1.rs", -"ui/issues/issue-22933-2.rs", -"ui/issues/issue-22992-2.rs", -"ui/issues/issue-22992.rs", -"ui/issues/issue-23024.rs", -"ui/issues/issue-23036.rs", -"ui/issues/issue-23041.rs", -"ui/issues/issue-23046.rs", -"ui/issues/issue-23073.rs", -"ui/issues/issue-2311-2.rs", -"ui/issues/issue-2311.rs", -"ui/issues/issue-2312.rs", -"ui/issues/issue-23122-1.rs", -"ui/issues/issue-23122-2.rs", -"ui/issues/issue-2316-c.rs", -"ui/issues/issue-23173.rs", -"ui/issues/issue-23189.rs", -"ui/issues/issue-23217.rs", -"ui/issues/issue-23253.rs", -"ui/issues/issue-23261.rs", -"ui/issues/issue-23281.rs", -"ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs", -"ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs", -"ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs", -"ui/issues/issue-23304-1.rs", -"ui/issues/issue-23304-2.rs", -"ui/issues/issue-23311.rs", -"ui/issues/issue-23336.rs", -"ui/issues/issue-23354-2.rs", -"ui/issues/issue-23354.rs", -"ui/issues/issue-23406.rs", -"ui/issues/issue-23433.rs", -"ui/issues/issue-23442.rs", -"ui/issues/issue-23477.rs", -"ui/issues/issue-23485.rs", -"ui/issues/issue-23491.rs", -"ui/issues/issue-23543.rs", -"ui/issues/issue-23544.rs", -"ui/issues/issue-23550.rs", -"ui/issues/issue-23589.rs", -"ui/issues/issue-23649-1.rs", -"ui/issues/issue-23649-2.rs", -"ui/issues/issue-23649-3.rs", -"ui/issues/issue-23699.rs", -"ui/issues/issue-2380-b.rs", -"ui/issues/issue-23808.rs", -"ui/issues/issue-2383.rs", -"ui/issues/issue-23891.rs", -"ui/issues/issue-23898.rs", -"ui/issues/issue-23958.rs", -"ui/issues/issue-23966.rs", -"ui/issues/issue-23992.rs", -"ui/issues/issue-24013.rs", -"ui/issues/issue-24036.rs", -"ui/issues/issue-24086.rs", -"ui/issues/issue-2414-c.rs", -"ui/issues/issue-24161.rs", -"ui/issues/issue-24227.rs", -"ui/issues/issue-2428.rs", -"ui/issues/issue-24308.rs", -"ui/issues/issue-24322.rs", -"ui/issues/issue-24352.rs", -"ui/issues/issue-24353.rs", -"ui/issues/issue-24357.rs", -"ui/issues/issue-24363.rs", -"ui/issues/issue-24365.rs", -"ui/issues/issue-24389.rs", -"ui/issues/issue-24424.rs", -"ui/issues/issue-24434.rs", -"ui/issues/issue-2445-b.rs", -"ui/issues/issue-2445.rs", -"ui/issues/issue-24533.rs", -"ui/issues/issue-24589.rs", -"ui/issues/issue-2463.rs", -"ui/issues/issue-24682.rs", -"ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs", -"ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs", -"ui/issues/issue-2470-bounds-check-overflow.rs", -"ui/issues/issue-2472.rs", -"ui/issues/issue-24779.rs", -"ui/issues/issue-24819.rs", -"ui/issues/issue-2487-a.rs", -"ui/issues/issue-24945-repeat-dash-opts.rs", -"ui/issues/issue-24947.rs", -"ui/issues/issue-24954.rs", -"ui/issues/issue-2502.rs", -"ui/issues/issue-25076.rs", -"ui/issues/issue-25089.rs", -"ui/issues/issue-25145.rs", -"ui/issues/issue-25180.rs", -"ui/issues/issue-25185.rs", -"ui/issues/issue-2526-a.rs", -"ui/issues/issue-25279.rs", -"ui/issues/issue-25343.rs", -"ui/issues/issue-25368.rs", -"ui/issues/issue-25386.rs", -"ui/issues/issue-25394.rs", -"ui/issues/issue-25467.rs", -"ui/issues/issue-25497.rs", -"ui/issues/issue-2550.rs", -"ui/issues/issue-25515.rs", -"ui/issues/issue-25549-multiple-drop.rs", -"ui/issues/issue-25579.rs", -"ui/issues/issue-25679.rs", -"ui/issues/issue-25693.rs", -"ui/issues/issue-25746-bool-transmute.rs", -"ui/issues/issue-25757.rs", -"ui/issues/issue-25810.rs", -"ui/issues/issue-2590.rs", -"ui/issues/issue-25901.rs", -"ui/issues/issue-26056.rs", -"ui/issues/issue-26093.rs", -"ui/issues/issue-26095.rs", -"ui/issues/issue-2611-3.rs", -"ui/issues/issue-26127.rs", -"ui/issues/issue-26186.rs", -"ui/issues/issue-26205.rs", -"ui/issues/issue-26217.rs", -"ui/issues/issue-26237.rs", -"ui/issues/issue-2631-b.rs", -"ui/issues/issue-2642.rs", -"ui/issues/issue-26468.rs", -"ui/issues/issue-26472.rs", -"ui/issues/issue-26484.rs", -"ui/issues/issue-26614.rs", -"ui/issues/issue-26619.rs", -"ui/issues/issue-26641.rs", -"ui/issues/issue-26646.rs", -"ui/issues/issue-26655.rs", -"ui/issues/issue-26709.rs", -"ui/issues/issue-26802.rs", -"ui/issues/issue-26805.rs", -"ui/issues/issue-26812.rs", -"ui/issues/issue-26948.rs", -"ui/issues/issue-26997.rs", -"ui/issues/issue-27008.rs", -"ui/issues/issue-27033.rs", -"ui/issues/issue-27042.rs", -"ui/issues/issue-27054-primitive-binary-ops.rs", -"ui/issues/issue-27078.rs", -"ui/issues/issue-2708.rs", -"ui/issues/issue-27105.rs", -"ui/issues/issue-2723-b.rs", -"ui/issues/issue-27240.rs", -"ui/issues/issue-27268.rs", -"ui/issues/issue-27281.rs", -"ui/issues/issue-27340.rs", -"ui/issues/issue-27401-dropflag-reinit.rs", -"ui/issues/issue-27433.rs", -"ui/issues/issue-27592.rs", -"ui/issues/issue-2761.rs", -"ui/issues/issue-27639.rs", -"ui/issues/issue-27697.rs", -"ui/issues/issue-27815.rs", -"ui/issues/issue-27842.rs", -"ui/issues/issue-27889.rs", -"ui/issues/issue-27942.rs", -"ui/issues/issue-27949.rs", -"ui/issues/issue-27997.rs", -"ui/issues/issue-28105.rs", -"ui/issues/issue-28109.rs", -"ui/issues/issue-28181.rs", -"ui/issues/issue-2823.rs", -"ui/issues/issue-28279.rs", -"ui/issues/issue-28344.rs", -"ui/issues/issue-28433.rs", -"ui/issues/issue-28472.rs", -"ui/issues/issue-2848.rs", -"ui/issues/issue-2849.rs", -"ui/issues/issue-28498-must-work-ex1.rs", -"ui/issues/issue-28498-must-work-ex2.rs", -"ui/issues/issue-28498-ugeh-ex1.rs", -"ui/issues/issue-28550.rs", -"ui/issues/issue-28561.rs", -"ui/issues/issue-28568.rs", -"ui/issues/issue-28586.rs", -"ui/issues/issue-28600.rs", -"ui/issues/issue-28625.rs", -"ui/issues/issue-28776.rs", -"ui/issues/issue-28777.rs", -"ui/issues/issue-28828.rs", -"ui/issues/issue-28839.rs", -"ui/issues/issue-28936.rs", -"ui/issues/issue-2895.rs", -"ui/issues/issue-28971.rs", -"ui/issues/issue-28983.rs", -"ui/issues/issue-28999.rs", -"ui/issues/issue-29030.rs", -"ui/issues/issue-29037.rs", -"ui/issues/issue-2904.rs", -"ui/issues/issue-29048.rs", -"ui/issues/issue-29053.rs", -"ui/issues/issue-29071-2.rs", -"ui/issues/issue-29071.rs", -"ui/issues/issue-29092.rs", -"ui/issues/issue-29147-rpass.rs", -"ui/issues/issue-29147.rs", -"ui/issues/issue-29265.rs", -"ui/issues/issue-29276.rs", -"ui/issues/issue-2935.rs", -"ui/issues/issue-29466.rs", -"ui/issues/issue-29485.rs", -"ui/issues/issue-2951.rs", -"ui/issues/issue-29516.rs", -"ui/issues/issue-29522.rs", -"ui/issues/issue-29540.rs", -"ui/issues/issue-29663.rs", -"ui/issues/issue-29668.rs", -"ui/issues/issue-29710.rs", -"ui/issues/issue-29723.rs", -"ui/issues/issue-29740.rs", -"ui/issues/issue-29743.rs", -"ui/issues/issue-29821.rs", -"ui/issues/issue-29857.rs", -"ui/issues/issue-29861.rs", -"ui/issues/issue-2989.rs", -"ui/issues/issue-29948.rs", -"ui/issues/issue-2995.rs", -"ui/issues/issue-30018-panic.rs", -"ui/issues/issue-30081.rs", -"ui/issues/issue-3012-2.rs", -"ui/issues/issue-30123.rs", -"ui/issues/issue-3021-b.rs", -"ui/issues/issue-3021-d.rs", -"ui/issues/issue-30236.rs", -"ui/issues/issue-30255.rs", -"ui/issues/issue-3026.rs", -"ui/issues/issue-3029.rs", -"ui/issues/issue-3037.rs", -"ui/issues/issue-30371.rs", -"ui/issues/issue-3038.rs", -"ui/issues/issue-30380.rs", -"ui/issues/issue-3052.rs", -"ui/issues/issue-30530.rs", -"ui/issues/issue-30589.rs", -"ui/issues/issue-30615.rs", -"ui/issues/issue-30756.rs", -"ui/issues/issue-30891.rs", -"ui/issues/issue-3091.rs", -"ui/issues/issue-31011.rs", -"ui/issues/issue-3109.rs", -"ui/issues/issue-3121.rs", -"ui/issues/issue-31260.rs", -"ui/issues/issue-31267-additional.rs", -"ui/issues/issue-31267.rs", -"ui/issues/issue-31299.rs", -"ui/issues/issue-3136-b.rs", -"ui/issues/issue-3149.rs", -"ui/issues/issue-31511.rs", -"ui/issues/issue-3154.rs", -"ui/issues/issue-31702.rs", -"ui/issues/issue-31769.rs", -"ui/issues/issue-31776.rs", -"ui/issues/issue-31910.rs", -"ui/issues/issue-32004.rs", -"ui/issues/issue-32008.rs", -"ui/issues/issue-32086.rs", -"ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.rs", -"ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.rs", -"ui/issues/issue-3214.rs", -"ui/issues/issue-3220.rs", -"ui/issues/issue-32292.rs", -"ui/issues/issue-32324.rs", -"ui/issues/issue-32326.rs", -"ui/issues/issue-32377.rs", -"ui/issues/issue-32389.rs", -"ui/issues/issue-32518.rs", -"ui/issues/issue-32655.rs", -"ui/issues/issue-32782.rs", -"ui/issues/issue-32797.rs", -"ui/issues/issue-32805.rs", -"ui/issues/issue-3290.rs", -"ui/issues/issue-32950.rs", -"ui/issues/issue-32995-2.rs", -"ui/issues/issue-32995.rs", -"ui/issues/issue-33202.rs", -"ui/issues/issue-33241.rs", -"ui/issues/issue-33287.rs", -"ui/issues/issue-33293.rs", -"ui/issues/issue-33387.rs", -"ui/issues/issue-3344.rs", -"ui/issues/issue-33461.rs", -"ui/issues/issue-33504.rs", -"ui/issues/issue-33525.rs", -"ui/issues/issue-33571.rs", -"ui/issues/issue-33687.rs", -"ui/issues/issue-33770.rs", -"ui/issues/issue-3389.rs", -"ui/issues/issue-33941.rs", -"ui/issues/issue-33992.rs", -"ui/issues/issue-34047.rs", -"ui/issues/issue-34074.rs", -"ui/issues/issue-34209.rs", -"ui/issues/issue-34229.rs", -"ui/issues/issue-3424.rs", -"ui/issues/issue-3429.rs", -"ui/issues/issue-34334.rs", -"ui/issues/issue-34349.rs", -"ui/issues/issue-34373.rs", -"ui/issues/issue-34418.rs", -"ui/issues/issue-34427.rs", -"ui/issues/issue-3447.rs", -"ui/issues/issue-34503.rs", -"ui/issues/issue-34569.rs", -"ui/issues/issue-34571.rs", -"ui/issues/issue-34751.rs", -"ui/issues/issue-3477.rs", -"ui/issues/issue-34780.rs", -"ui/issues/issue-34796.rs", -"ui/issues/issue-34839.rs", -"ui/issues/issue-3500.rs", -"ui/issues/issue-35139.rs", -"ui/issues/issue-3521-2.rs", -"ui/issues/issue-35241.rs", -"ui/issues/issue-35423.rs", -"ui/issues/issue-3556.rs", -"ui/issues/issue-35570.rs", -"ui/issues/issue-3559.rs", -"ui/issues/issue-35600.rs", -"ui/issues/issue-3574.rs", -"ui/issues/issue-35815.rs", -"ui/issues/issue-35976.rs", -"ui/issues/issue-35988.rs", -"ui/issues/issue-36023.rs", -"ui/issues/issue-36036-associated-type-layout.rs", -"ui/issues/issue-36075.rs", -"ui/issues/issue-3609.rs", -"ui/issues/issue-36116.rs", -"ui/issues/issue-36260.rs", -"ui/issues/issue-36278-prefix-nesting.rs", -"ui/issues/issue-36299.rs", -"ui/issues/issue-36379.rs", -"ui/issues/issue-36400.rs", -"ui/issues/issue-36474.rs", -"ui/issues/issue-3656.rs", -"ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs", -"ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs", -"ui/issues/issue-36744-bitcast-args-if-needed.rs", -"ui/issues/issue-36786-resolve-call.rs", -"ui/issues/issue-3680.rs", -"ui/issues/issue-36816.rs", -"ui/issues/issue-36836.rs", -"ui/issues/issue-36839.rs", -"ui/issues/issue-36856.rs", -"ui/issues/issue-36936.rs", -"ui/issues/issue-36954.rs", -"ui/issues/issue-3702-2.rs", -"ui/issues/issue-3702.rs", -"ui/issues/issue-37051.rs", -"ui/issues/issue-37109.rs", -"ui/issues/issue-37131.rs", -"ui/issues/issue-37311-type-length-limit/issue-37311.rs", -"ui/issues/issue-37510.rs", -"ui/issues/issue-3753.rs", -"ui/issues/issue-37534.rs", -"ui/issues/issue-37576.rs", -"ui/issues/issue-3763.rs", -"ui/issues/issue-37665.rs", -"ui/issues/issue-37686.rs", -"ui/issues/issue-37725.rs", -"ui/issues/issue-37733.rs", -"ui/issues/issue-3779.rs", -"ui/issues/issue-37884.rs", -"ui/issues/issue-38160.rs", -"ui/issues/issue-38190.rs", -"ui/issues/issue-38226.rs", -"ui/issues/issue-38381.rs", -"ui/issues/issue-38412.rs", -"ui/issues/issue-38437.rs", -"ui/issues/issue-38458.rs", -"ui/issues/issue-3847.rs", -"ui/issues/issue-38556.rs", -"ui/issues/issue-38727.rs", -"ui/issues/issue-3874.rs", -"ui/issues/issue-38763.rs", -"ui/issues/issue-38857.rs", -"ui/issues/issue-38875/auxiliary/issue-38875-b.rs", -"ui/issues/issue-38875/issue-38875.rs", -"ui/issues/issue-3888-2.rs", -"ui/issues/issue-38919.rs", -"ui/issues/issue-38942.rs", -"ui/issues/issue-3895.rs", -"ui/issues/issue-38954.rs", -"ui/issues/issue-38987.rs", -"ui/issues/issue-39089.rs", -"ui/issues/issue-39175.rs", -"ui/issues/issue-39211.rs", -"ui/issues/issue-39367.rs", -"ui/issues/issue-39548.rs", -"ui/issues/issue-39687.rs", -"ui/issues/issue-39709.rs", -"ui/issues/issue-3979-2.rs", -"ui/issues/issue-3979-xcrate.rs", -"ui/issues/issue-3979.rs", -"ui/issues/issue-39808.rs", -"ui/issues/issue-39827.rs", -"ui/issues/issue-39848.rs", -"ui/issues/issue-3991.rs", -"ui/issues/issue-3993.rs", -"ui/issues/issue-39970.rs", -"ui/issues/issue-39984.rs", -"ui/issues/issue-40000.rs", -"ui/issues/issue-40136.rs", -"ui/issues/issue-40235.rs", -"ui/issues/issue-4025.rs", -"ui/issues/issue-40288-2.rs", -"ui/issues/issue-40288.rs", -"ui/issues/issue-40350.rs", -"ui/issues/issue-40402-ref-hints/issue-40402-1.rs", -"ui/issues/issue-40402-ref-hints/issue-40402-2.rs", -"ui/issues/issue-40408.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs", -"ui/issues/issue-40610.rs", -"ui/issues/issue-40749.rs", -"ui/issues/issue-40782.rs", -"ui/issues/issue-40827.rs", -"ui/issues/issue-40845.rs", -"ui/issues/issue-40861.rs", -"ui/issues/issue-40883.rs", -"ui/issues/issue-40951.rs", -"ui/issues/issue-41053.rs", -"ui/issues/issue-41139.rs", -"ui/issues/issue-41213.rs", -"ui/issues/issue-41229-ref-str.rs", -"ui/issues/issue-41272.rs", -"ui/issues/issue-41298.rs", -"ui/issues/issue-41479.rs", -"ui/issues/issue-41498.rs", -"ui/issues/issue-41549.rs", -"ui/issues/issue-41604.rs", -"ui/issues/issue-41628.rs", -"ui/issues/issue-41652/auxiliary/issue-41652-b.rs", -"ui/issues/issue-41652/issue-41652.rs", -"ui/issues/issue-41677.rs", -"ui/issues/issue-41696.rs", -"ui/issues/issue-41726.rs", -"ui/issues/issue-41742.rs", -"ui/issues/issue-41744.rs", -"ui/issues/issue-41849-variance-req.rs", -"ui/issues/issue-41880.rs", -"ui/issues/issue-41888.rs", -"ui/issues/issue-41936-variance-coerce-unsized-cycle.rs", -"ui/issues/issue-41974.rs", -"ui/issues/issue-41998.rs", -"ui/issues/issue-42007.rs", -"ui/issues/issue-4208.rs", -"ui/issues/issue-42106.rs", -"ui/issues/issue-42148.rs", -"ui/issues/issue-42210.rs", -"ui/issues/issue-4228.rs", -"ui/issues/issue-42312.rs", -"ui/issues/issue-42453.rs", -"ui/issues/issue-42467.rs", -"ui/issues/issue-4252.rs", -"ui/issues/issue-42552.rs", -"ui/issues/issue-4265.rs", -"ui/issues/issue-42755.rs", -"ui/issues/issue-42796.rs", -"ui/issues/issue-42880.rs", -"ui/issues/issue-42956.rs", -"ui/issues/issue-43057.rs", -"ui/issues/issue-43205.rs", -"ui/issues/issue-43250.rs", -"ui/issues/issue-43291.rs", -"ui/issues/issue-4333.rs", -"ui/issues/issue-4335.rs", -"ui/issues/issue-43355.rs", -"ui/issues/issue-43357.rs", -"ui/issues/issue-43420-no-over-suggest.rs", -"ui/issues/issue-43424.rs", -"ui/issues/issue-43431.rs", -"ui/issues/issue-43483.rs", -"ui/issues/issue-43692.rs", -"ui/issues/issue-43806.rs", -"ui/issues/issue-43853.rs", -"ui/issues/issue-4387.rs", -"ui/issues/issue-43910.rs", -"ui/issues/issue-43923.rs", -"ui/issues/issue-43925.rs", -"ui/issues/issue-43926.rs", -"ui/issues/issue-43988.rs", -"ui/issues/issue-44023.rs", -"ui/issues/issue-44056.rs", -"ui/issues/issue-44078.rs", -"ui/issues/issue-44216-add-instant.rs", -"ui/issues/issue-44216-add-system-time.rs", -"ui/issues/issue-44216-sub-instant.rs", -"ui/issues/issue-44216-sub-system-time.rs", -"ui/issues/issue-44239.rs", -"ui/issues/issue-44247.rs", -"ui/issues/issue-44405.rs", -"ui/issues/issue-4464.rs", -"ui/issues/issue-44730.rs", -"ui/issues/issue-44851.rs", -"ui/issues/issue-4517.rs", -"ui/issues/issue-4541.rs", -"ui/issues/issue-4542.rs", -"ui/issues/issue-45425.rs", -"ui/issues/issue-4545.rs", -"ui/issues/issue-45510.rs", -"ui/issues/issue-45562.rs", -"ui/issues/issue-45697-1.rs", -"ui/issues/issue-45697.rs", -"ui/issues/issue-45730.rs", -"ui/issues/issue-45731.rs", -"ui/issues/issue-45801.rs", -"ui/issues/issue-45965.rs", -"ui/issues/issue-46069.rs", -"ui/issues/issue-46101.rs", -"ui/issues/issue-46302.rs", -"ui/issues/issue-46311.rs", -"ui/issues/issue-46332.rs", -"ui/issues/issue-46471-1.rs", -"ui/issues/issue-46472.rs", -"ui/issues/issue-46604.rs", -"ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.rs", -"ui/issues/issue-46771.rs", -"ui/issues/issue-46855.rs", -"ui/issues/issue-46964.rs", -"ui/issues/issue-46983.rs", -"ui/issues/issue-47073-zero-padded-tuple-struct-indices.rs", -"ui/issues/issue-47094.rs", -"ui/issues/issue-47184.rs", -"ui/issues/issue-47309.rs", -"ui/issues/issue-4734.rs", -"ui/issues/issue-4735.rs", -"ui/issues/issue-4736.rs", -"ui/issues/issue-47364.rs", -"ui/issues/issue-47377.rs", -"ui/issues/issue-47380.rs", -"ui/issues/issue-47486.rs", -"ui/issues/issue-4759-1.rs", -"ui/issues/issue-4759.rs", -"ui/issues/issue-47638.rs", -"ui/issues/issue-47673.rs", -"ui/issues/issue-47703-1.rs", -"ui/issues/issue-47703-tuple.rs", -"ui/issues/issue-47703.rs", -"ui/issues/issue-47715.rs", -"ui/issues/issue-47722.rs", -"ui/issues/issue-48006.rs", -"ui/issues/issue-48131.rs", -"ui/issues/issue-48132.rs", -"ui/issues/issue-48159.rs", -"ui/issues/issue-48276.rs", -"ui/issues/issue-4830.rs", -"ui/issues/issue-48364.rs", -"ui/issues/issue-48728.rs", -"ui/issues/issue-4875.rs", -"ui/issues/issue-48838.rs", -"ui/issues/issue-48984.rs", -"ui/issues/issue-49298.rs", -"ui/issues/issue-4935.rs", -"ui/issues/issue-49544.rs", -"ui/issues/issue-49632.rs", -"ui/issues/issue-4968.rs", -"ui/issues/issue-4972.rs", -"ui/issues/issue-49824.rs", -"ui/issues/issue-49854.rs", -"ui/issues/issue-49919.rs", -"ui/issues/issue-49934-errors.rs", -"ui/issues/issue-49934.rs", -"ui/issues/issue-49955.rs", -"ui/issues/issue-49973.rs", -"ui/issues/issue-50187.rs", -"ui/issues/issue-50403.rs", -"ui/issues/issue-50411.rs", -"ui/issues/issue-50415.rs", -"ui/issues/issue-50442.rs", -"ui/issues/issue-50471.rs", -"ui/issues/issue-50518.rs", -"ui/issues/issue-50571.rs", -"ui/issues/issue-50581.rs", -"ui/issues/issue-50582.rs", -"ui/issues/issue-50585.rs", -"ui/issues/issue-50600.rs", -"ui/issues/issue-50618.rs", -"ui/issues/issue-5062.rs", -"ui/issues/issue-5067.rs", -"ui/issues/issue-50688.rs", -"ui/issues/issue-50714-1.rs", -"ui/issues/issue-50714.rs", -"ui/issues/issue-50761.rs", -"ui/issues/issue-50781.rs", -"ui/issues/issue-50802.rs", -"ui/issues/issue-50811.rs", -"ui/issues/issue-5100.rs", -"ui/issues/issue-51022.rs", -"ui/issues/issue-51044.rs", -"ui/issues/issue-51102.rs", -"ui/issues/issue-51116.rs", -"ui/issues/issue-51154.rs", -"ui/issues/issue-51515.rs", -"ui/issues/issue-51632-try-desugar-incompatible-types.rs", -"ui/issues/issue-51655.rs", -"ui/issues/issue-51714.rs", -"ui/issues/issue-51798.rs", -"ui/issues/issue-51874.rs", -"ui/issues/issue-51907.rs", -"ui/issues/issue-5192.rs", -"ui/issues/issue-51947.rs", -"ui/issues/issue-52049.rs", -"ui/issues/issue-52126-assign-op-invariance.rs", -"ui/issues/issue-52262.rs", -"ui/issues/issue-5239-1.rs", -"ui/issues/issue-5239-2.rs", -"ui/issues/issue-52489.rs", -"ui/issues/issue-52533.rs", -"ui/issues/issue-52717.rs", -"ui/issues/issue-5280.rs", -"ui/issues/issue-5315.rs", -"ui/issues/issue-5321-immediates-with-bare-self.rs", -"ui/issues/issue-53251.rs", -"ui/issues/issue-53275.rs", -"ui/issues/issue-53300.rs", -"ui/issues/issue-53333.rs", -"ui/issues/issue-53348.rs", -"ui/issues/issue-53419.rs", -"ui/issues/issue-53498.rs", -"ui/issues/issue-53568.rs", -"ui/issues/issue-5358-1.rs", -"ui/issues/issue-53728.rs", -"ui/issues/issue-53843.rs", -"ui/issues/issue-54044.rs", -"ui/issues/issue-54062.rs", -"ui/issues/issue-54094.rs", -"ui/issues/issue-5439.rs", -"ui/issues/issue-54410.rs", -"ui/issues/issue-54462-mutable-noalias-correctness.rs", -"ui/issues/issue-54477-reduced-2.rs", -"ui/issues/issue-54696.rs", -"ui/issues/issue-5518.rs", -"ui/issues/issue-5521.rs", -"ui/issues/issue-55376.rs", -"ui/issues/issue-55380.rs", -"ui/issues/issue-5550.rs", -"ui/issues/issue-5554.rs", -"ui/issues/issue-55587.rs", -"ui/issues/issue-5572.rs", -"ui/issues/issue-55731.rs", -"ui/issues/issue-56128.rs", -"ui/issues/issue-56175.rs", -"ui/issues/issue-56199.rs", -"ui/issues/issue-56229.rs", -"ui/issues/issue-56237.rs", -"ui/issues/issue-5666.rs", -"ui/issues/issue-56806.rs", -"ui/issues/issue-56835.rs", -"ui/issues/issue-56870.rs", -"ui/issues/issue-5688.rs", -"ui/issues/issue-56943.rs", -"ui/issues/issue-5708.rs", -"ui/issues/issue-57156.rs", -"ui/issues/issue-57162.rs", -"ui/issues/issue-5718.rs", -"ui/issues/issue-57198-pass.rs", -"ui/issues/issue-57271.rs", -"ui/issues/issue-57362-1.rs", -"ui/issues/issue-57362-2.rs", -"ui/issues/issue-57399-self-return-impl-trait.rs", -"ui/issues/issue-5741.rs", -"ui/issues/issue-5754.rs", -"ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs", -"ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs", -"ui/issues/issue-57781.rs", -"ui/issues/issue-57924.rs", -"ui/issues/issue-58212.rs", -"ui/issues/issue-58375-monomorphize-default-impls.rs", -"ui/issues/issue-5844.rs", -"ui/issues/issue-58463.rs", -"ui/issues/issue-58712.rs", -"ui/issues/issue-58734.rs", -"ui/issues/issue-5883.rs", -"ui/issues/issue-5884.rs", -"ui/issues/issue-58857.rs", -"ui/issues/issue-5900.rs", -"ui/issues/issue-59020.rs", -"ui/issues/issue-5917.rs", -"ui/issues/issue-59326.rs", -"ui/issues/issue-59488.rs", -"ui/issues/issue-59494.rs", -"ui/issues/issue-5950.rs", -"ui/issues/issue-59756.rs", -"ui/issues/issue-5988.rs", -"ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs", -"ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs", -"ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs", -"ui/issues/issue-60218.rs", -"ui/issues/issue-60622.rs", -"ui/issues/issue-60989.rs", -"ui/issues/issue-61106.rs", -"ui/issues/issue-61108.rs", -"ui/issues/issue-6117.rs", -"ui/issues/issue-6130.rs", -"ui/issues/issue-61475.rs", -"ui/issues/issue-6153.rs", -"ui/issues/issue-61623.rs", -"ui/issues/issue-61894.rs", -"ui/issues/issue-62480.rs", -"ui/issues/issue-6318.rs", -"ui/issues/issue-6344-let.rs", -"ui/issues/issue-6344-match.rs", -"ui/issues/issue-63983.rs", -"ui/issues/issue-64430.rs", -"ui/issues/issue-64559.rs", -"ui/issues/issue-64593.rs", -"ui/issues/issue-64792-bad-unicode-ctor.rs", -"ui/issues/issue-65131.rs", -"ui/issues/issue-65230.rs", -"ui/issues/issue-65462.rs", -"ui/issues/issue-6557.rs", -"ui/issues/issue-66308.rs", -"ui/issues/issue-66353.rs", -"ui/issues/issue-66667-function-cmp-cycle.rs", -"ui/issues/issue-66702-break-outside-loop-val.rs", -"ui/issues/issue-66706.rs", -"ui/issues/issue-66923-show-error-for-correct-call.rs", -"ui/issues/issue-67039-unsound-pin-partialeq.rs", -"ui/issues/issue-6738.rs", -"ui/issues/issue-67535.rs", -"ui/issues/issue-67552.rs", -"ui/issues/issue-68010-large-zst-consts.rs", -"ui/issues/issue-68696-catch-during-unwind.rs", -"ui/issues/issue-6892.rs", -"ui/issues/issue-68951.rs", -"ui/issues/issue-6898.rs", -"ui/issues/issue-69130.rs", -"ui/issues/issue-6919.rs", -"ui/issues/issue-69306.rs", -"ui/issues/issue-6936.rs", -"ui/issues/issue-69455.rs", -"ui/issues/issue-69602-type-err-during-codegen-ice.rs", -"ui/issues/issue-69683.rs", -"ui/issues/issue-70093/issue-70093-link-directives.rs", -"ui/issues/issue-70093/issue-70093.rs", -"ui/issues/issue-7012.rs", -"ui/issues/issue-70381.rs", -"ui/issues/issue-7044.rs", -"ui/issues/issue-7061.rs", -"ui/issues/issue-70673.rs", -"ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs", -"ui/issues/issue-70746.rs", -"ui/issues/issue-7092.rs", -"ui/issues/issue-71406.rs", -"ui/issues/issue-71676-suggest-deref/issue-71676-1.rs", -"ui/issues/issue-71676-suggest-deref/issue-71676-2.rs", -"ui/issues/issue-7178.rs", -"ui/issues/issue-72002.rs", -"ui/issues/issue-72076.rs", -"ui/issues/issue-72278.rs", -"ui/issues/issue-7246.rs", -"ui/issues/issue-7268.rs", -"ui/issues/issue-72839-error-overflow.rs", -"ui/issues/issue-72933-match-stack-overflow.rs", -"ui/issues/issue-73112.rs", -"ui/issues/issue-73229.rs", -"ui/issues/issue-7344.rs", -"ui/issues/issue-7364.rs", -"ui/issues/issue-74082.rs", -"ui/issues/issue-74564-if-expr-stack-overflow.rs", -"ui/issues/issue-7519-match-unit-in-arg.rs", -"ui/issues/issue-75283.rs", -"ui/issues/issue-7563.rs", -"ui/issues/issue-75704.rs", -"ui/issues/issue-7575.rs", -"ui/issues/issue-76042.rs", -"ui/issues/issue-7607-1.rs", -"ui/issues/issue-7607-2.rs", -"ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs", -"ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs", -"ui/issues/issue-76191.rs", -"ui/issues/issue-7660.rs", -"ui/issues/issue-7663.rs", -"ui/issues/issue-7673-cast-generically-implemented-trait.rs", -"ui/issues/issue-77218/issue-77218-2.rs", -"ui/issues/issue-77218/issue-77218.rs", -"ui/issues/issue-7784.rs", -"ui/issues/issue-77919.rs", -"ui/issues/issue-78192.rs", -"ui/issues/issue-78622.rs", -"ui/issues/issue-7867.rs", -"ui/issues/issue-78957.rs", -"ui/issues/issue-7899.rs", -"ui/issues/issue-7911.rs", -"ui/issues/issue-7970a.rs", -"ui/issues/issue-8044.rs", -"ui/issues/issue-80607.rs", -"ui/issues/issue-81584.rs", -"ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs", -"ui/issues/issue-81918.rs", -"ui/issues/issue-8248.rs", -"ui/issues/issue-8249.rs", -"ui/issues/issue-8259.rs", -"ui/issues/issue-83048.rs", -"ui/issues/issue-8391.rs", -"ui/issues/issue-8398.rs", -"ui/issues/issue-8401.rs", -"ui/issues/issue-8498.rs", -"ui/issues/issue-8506.rs", -"ui/issues/issue-8521.rs", -"ui/issues/issue-85461.rs", -"ui/issues/issue-8578.rs", -"ui/issues/issue-86756.rs", -"ui/issues/issue-87199.rs", -"ui/issues/issue-8727.rs", -"ui/issues/issue-87490.rs", -"ui/issues/issue-8761.rs", -"ui/issues/issue-8767.rs", -"ui/issues/issue-87707.rs", -"ui/issues/issue-8783.rs", -"ui/issues/issue-88150.rs", -"ui/issues/issue-8860.rs", -"ui/issues/issue-8898.rs", -"ui/issues/issue-9047.rs", -"ui/issues/issue-9110.rs", -"ui/issues/issue-9123.rs", -"ui/issues/issue-9129.rs", -"ui/issues/issue-91489.rs", -"ui/issues/issue-9155.rs", -"ui/issues/issue-9188.rs", -"ui/issues/issue-9243.rs", -"ui/issues/issue-9249.rs", -"ui/issues/issue-9259.rs", -"ui/issues/issue-92741.rs", -"ui/issues/issue-9382.rs", -"ui/issues/issue-9446.rs", -"ui/issues/issue-9575.rs", -"ui/issues/issue-9719.rs", -"ui/issues/issue-9725.rs", -"ui/issues/issue-9737.rs", -"ui/issues/issue-9814.rs", -"ui/issues/issue-98299.rs", -"ui/issues/issue-9837.rs", -"ui/issues/issue-9906.rs", -"ui/issues/issue-9918.rs", -"ui/issues/issue-9942.rs", -"ui/issues/issue-9951.rs", -"ui/issues/issue-9968.rs", -"ui/issues/issue-99838.rs", -"ui/iterators/issue-28098.rs", -"ui/iterators/issue-58952-filter-type-length.rs", -"ui/lang-items/issue-19660.rs", -"ui/lang-items/issue-83471.rs", -"ui/lang-items/issue-87573.rs", -"ui/late-bound-lifetimes/issue-36381.rs", -"ui/late-bound-lifetimes/issue-47511.rs", -"ui/late-bound-lifetimes/issue-80618.rs", -"ui/layout/issue-112048-unsizing-field-order.rs", -"ui/layout/issue-112048-unsizing-niche.rs", -"ui/layout/issue-113941.rs", -"ui/layout/issue-60431-unsized-tail-behind-projection.rs", -"ui/layout/issue-84108.rs", -"ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs", -"ui/layout/issue-96185-overaligned-enum.rs", -"ui/let-else/issue-100103.rs", -"ui/let-else/issue-102317.rs", -"ui/let-else/issue-94176.rs", -"ui/let-else/issue-99975.rs", -"ui/lifetimes/auxiliary/issue-91763-aux.rs", -"ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs", -"ui/lifetimes/issue-104432-unused-lifetimes-in-expansion.rs", -"ui/lifetimes/issue-105227.rs", -"ui/lifetimes/issue-105507.rs", -"ui/lifetimes/issue-105675.rs", -"ui/lifetimes/issue-107492-default-value-for-lifetime.rs", -"ui/lifetimes/issue-107988.rs", -"ui/lifetimes/issue-17728.rs", -"ui/lifetimes/issue-19707.rs", -"ui/lifetimes/issue-26638.rs", -"ui/lifetimes/issue-34979.rs", -"ui/lifetimes/issue-36744-without-calls.rs", -"ui/lifetimes/issue-54378.rs", -"ui/lifetimes/issue-55796.rs", -"ui/lifetimes/issue-64173-unused-lifetimes.rs", -"ui/lifetimes/issue-67498.rs", -"ui/lifetimes/issue-69314.rs", -"ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs", -"ui/lifetimes/issue-76168-hr-outlives-2.rs", -"ui/lifetimes/issue-76168-hr-outlives-3.rs", -"ui/lifetimes/issue-76168-hr-outlives.rs", -"ui/lifetimes/issue-77175.rs", -"ui/lifetimes/issue-79187-2.rs", -"ui/lifetimes/issue-79187.rs", -"ui/lifetimes/issue-83737-binders-across-types.rs", -"ui/lifetimes/issue-83737-erasing-bound-vars.rs", -"ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs", -"ui/lifetimes/issue-83907-invalid-fn-like-path.rs", -"ui/lifetimes/issue-84398.rs", -"ui/lifetimes/issue-84604.rs", -"ui/lifetimes/issue-90170-elision-mismatch.rs", -"ui/lifetimes/issue-90600-expected-return-static-indirect.rs", -"ui/lifetimes/issue-91763.rs", -"ui/lifetimes/issue-93911.rs", -"ui/lifetimes/issue-95023.rs", -"ui/lifetimes/issue-97193.rs", -"ui/lifetimes/issue-97194.rs", -"ui/lifetimes/lifetime-errors/issue_74400.rs", -"ui/limits/issue-15919-32.rs", -"ui/limits/issue-15919-64.rs", -"ui/limits/issue-17913.rs", -"ui/limits/issue-55878.rs", -"ui/limits/issue-56762.rs", -"ui/limits/issue-69485-var-size-diffs-too-large.rs", -"ui/limits/issue-75158-64.rs", -"ui/linkage-attr/issue-10755.rs", -"ui/linkage-attr/issue-109144.rs", -"ui/lint/dead-code/issue-41883.rs", -"ui/lint/dead-code/issue-59003.rs", -"ui/lint/dead-code/issue-68408-false-positive.rs", -"ui/lint/dead-code/issue-85071-2.rs", -"ui/lint/dead-code/issue-85071.rs", -"ui/lint/dead-code/issue-85255.rs", -"ui/lint/issue-101284.rs", -"ui/lint/issue-102705.rs", -"ui/lint/issue-103317.rs", -"ui/lint/issue-103435-extra-parentheses.rs", -"ui/lint/issue-104392.rs", -"ui/lint/issue-104897.rs", -"ui/lint/issue-106991.rs", -"ui/lint/issue-108155.rs", -"ui/lint/issue-109152.rs", -"ui/lint/issue-109529.rs", -"ui/lint/issue-110573.rs", -"ui/lint/issue-111359.rs", -"ui/lint/issue-112489.rs", -"ui/lint/issue-117949.rs", -"ui/lint/issue-121070-let-range.rs", -"ui/lint/issue-14309.rs", -"ui/lint/issue-14837.rs", -"ui/lint/issue-17718-const-naming.rs", -"ui/lint/issue-1866.rs", -"ui/lint/issue-19102.rs", -"ui/lint/issue-20343.rs", -"ui/lint/issue-30302.rs", -"ui/lint/issue-31924-non-snake-ffi.rs", -"ui/lint/issue-34798.rs", -"ui/lint/issue-35075.rs", -"ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs", -"ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs", -"ui/lint/issue-54099-camel-case-underscore-types.rs", -"ui/lint/issue-57410-1.rs", -"ui/lint/issue-57410.rs", -"ui/lint/issue-63364.rs", -"ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs", -"ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs", -"ui/lint/issue-79546-fuel-ice.rs", -"ui/lint/issue-79744.rs", -"ui/lint/issue-80988.rs", -"ui/lint/issue-81218.rs", -"ui/lint/issue-83477.rs", -"ui/lint/issue-87274-paren-parent.rs", -"ui/lint/issue-89469.rs", -"ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs", -"ui/lint/issue-97094.rs", -"ui/lint/issue-99387.rs", -"ui/lint/let_underscore/issue-119696-err-on-fn.rs", -"ui/lint/let_underscore/issue-119697-extra-let.rs", -"ui/lint/must_not_suspend/issue-89562.rs", -"ui/lint/unused/issue-103320-must-use-ops.rs", -"ui/lint/unused/issue-104397.rs", -"ui/lint/unused/issue-105061-array-lint.rs", -"ui/lint/unused/issue-105061-should-lint.rs", -"ui/lint/unused/issue-105061.rs", -"ui/lint/unused/issue-117142-invalid-remove-parens.rs", -"ui/lint/unused/issue-117284-arg-in-macro.rs", -"ui/lint/unused/issue-119383-if-let-guard.rs", -"ui/lint/unused/issue-30730.rs", -"ui/lint/unused/issue-46576.rs", -"ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs", -"ui/lint/unused/issue-54180-unused-ref-field.rs", -"ui/lint/unused/issue-54538-unused-parens-lint.rs", -"ui/lint/unused/issue-59896.rs", -"ui/lint/unused/issue-67691-unused-field-in-or-pattern.rs", -"ui/lint/unused/issue-70041.rs", -"ui/lint/unused/issue-71290-unused-paren-binop.rs", -"ui/lint/unused/issue-74883-unused-paren-baren-yield.rs", -"ui/lint/unused/issue-81314-unused-span-ident.rs", -"ui/lint/unused/issue-85913.rs", -"ui/lint/unused/issue-88519-unused-paren.rs", -"ui/lint/unused/issue-90807-unused-paren-error.rs", -"ui/lint/unused/issue-90807-unused-paren.rs", -"ui/lint/unused/issue-92751.rs", -"ui/lint/unused/issue-96606.rs", -"ui/lint/use-redundant/issue-92904.rs", -"ui/loops/issue-1962.rs", -"ui/loops/issue-1974.rs", -"ui/loops/issue-43162.rs", -"ui/loops/issue-50576.rs", -"ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs", -"ui/loops/issue-69225-layout-repeated-checked-add.rs", -"ui/loops/issue-82916.rs", -"ui/lowering/issue-121108.rs", -"ui/lowering/issue-96847.rs", -"ui/lto/issue-100772.rs", -"ui/lto/issue-105637.rs", -"ui/lto/issue-11154.rs", -"ui/macros/auxiliary/issue-100199.rs", -"ui/macros/auxiliary/issue-19163.rs", -"ui/macros/auxiliary/issue-40469.rs", -"ui/macros/auxiliary/issue-75982.rs", -"ui/macros/issue-100199.rs", -"ui/macros/issue-102878.rs", -"ui/macros/issue-103529.rs", -"ui/macros/issue-104769-concat_bytes-invalid-literal.rs", -"ui/macros/issue-105011.rs", -"ui/macros/issue-10536.rs", -"ui/macros/issue-106837.rs", -"ui/macros/issue-109237.rs", -"ui/macros/issue-111749.rs", -"ui/macros/issue-112342-1.rs", -"ui/macros/issue-112342-2.rs", -"ui/macros/issue-118048.rs", -"ui/macros/issue-118786.rs", -"ui/macros/issue-16098.rs", -"ui/macros/issue-19163.rs", -"ui/macros/issue-21356.rs", -"ui/macros/issue-22463.rs", -"ui/macros/issue-25274.rs", -"ui/macros/issue-25385.rs", -"ui/macros/issue-26094.rs", -"ui/macros/issue-26322.rs", -"ui/macros/issue-2804-2.rs", -"ui/macros/issue-2804.rs", -"ui/macros/issue-29084.rs", -"ui/macros/issue-30007.rs", -"ui/macros/issue-30143.rs", -"ui/macros/issue-33185.rs", -"ui/macros/issue-34171.rs", -"ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs", -"ui/macros/issue-35450.rs", -"ui/macros/issue-37175.rs", -"ui/macros/issue-38715.rs", -"ui/macros/issue-39388.rs", -"ui/macros/issue-39404.rs", -"ui/macros/issue-39467.rs", -"ui/macros/issue-40469.rs", -"ui/macros/issue-40770.rs", -"ui/macros/issue-41776.rs", -"ui/macros/issue-41803.rs", -"ui/macros/issue-42954.rs", -"ui/macros/issue-44127.rs", -"ui/macros/issue-46438.rs", -"ui/macros/issue-5060.rs", -"ui/macros/issue-51848.rs", -"ui/macros/issue-52169.rs", -"ui/macros/issue-54441.rs", -"ui/macros/issue-57597.rs", -"ui/macros/issue-58490.rs", -"ui/macros/issue-61033-1.rs", -"ui/macros/issue-61033-2.rs", -"ui/macros/issue-61053-different-kleene.rs", -"ui/macros/issue-61053-duplicate-binder.rs", -"ui/macros/issue-61053-missing-repetition.rs", -"ui/macros/issue-61053-unbound.rs", -"ui/macros/issue-63102.rs", -"ui/macros/issue-6596-1.rs", -"ui/macros/issue-6596-2.rs", -"ui/macros/issue-68058.rs", -"ui/macros/issue-68060.rs", -"ui/macros/issue-69396-const-no-type-in-macro.rs", -"ui/macros/issue-69838-mods-relative-to-included-path.rs", -"ui/macros/issue-70446.rs", -"ui/macros/issue-75982-foreign-macro-weird-mod.rs", -"ui/macros/issue-77475.rs", -"ui/macros/issue-78325-inconsistent-resolution.rs", -"ui/macros/issue-78333.rs", -"ui/macros/issue-78892-substitution-in-statement-attr.rs", -"ui/macros/issue-81006.rs", -"ui/macros/issue-83340.rs", -"ui/macros/issue-83344.rs", -"ui/macros/issue-84195-lint-anon-const.rs", -"ui/macros/issue-84429-matches-edition.rs", -"ui/macros/issue-84632-eager-expansion-recursion-limit.rs", -"ui/macros/issue-86082-option-env-invalid-char.rs", -"ui/macros/issue-86865.rs", -"ui/macros/issue-8709.rs", -"ui/macros/issue-87877.rs", -"ui/macros/issue-88206.rs", -"ui/macros/issue-88228.rs", -"ui/macros/issue-8851.rs", -"ui/macros/issue-92267.rs", -"ui/macros/issue-95267.rs", -"ui/macros/issue-95533.rs", -"ui/macros/issue-98466-allow.rs", -"ui/macros/issue-98466.rs", -"ui/macros/issue-98790.rs", -"ui/macros/issue-99261.rs", -"ui/macros/issue-99265.rs", -"ui/macros/issue-99907.rs", -"ui/macros/rfc-3086-metavar-expr/issue-111904.rs", -"ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs", -"ui/malformed/issue-69341-malformed-derive-inert.rs", -"ui/marker_trait_attr/issue-61651-type-mismatch.rs", -"ui/match/issue-112438.rs", -"ui/match/issue-113012.rs", -"ui/match/issue-11319.rs", -"ui/match/issue-114691.rs", -"ui/match/issue-115681.rs", -"ui/match/issue-11940.rs", -"ui/match/issue-12552.rs", -"ui/match/issue-18060.rs", -"ui/match/issue-26251.rs", -"ui/match/issue-26996.rs", -"ui/match/issue-27021.rs", -"ui/match/issue-33498.rs", -"ui/match/issue-36401.rs", -"ui/match/issue-37598.rs", -"ui/match/issue-42679.rs", -"ui/match/issue-46920-byte-array-patterns.rs", -"ui/match/issue-5530.rs", -"ui/match/issue-56685.rs", -"ui/match/issue-70972-dyn-trait.rs", -"ui/match/issue-72680.rs", -"ui/match/issue-72896-non-partial-eq-const.rs", -"ui/match/issue-74050-end-span.rs", -"ui/match/issue-82392.rs", -"ui/match/issue-82866.rs", -"ui/match/issue-84434.rs", -"ui/match/issue-91058.rs", -"ui/match/issue-92100.rs", -"ui/methods/issue-19521.rs", -"ui/methods/issue-3707.rs", -"ui/methods/issue-7950.rs", -"ui/methods/issues/issue-105732.rs", -"ui/methods/issues/issue-61525.rs", -"ui/methods/issues/issue-84495.rs", -"ui/methods/issues/issue-90315.rs", -"ui/methods/issues/issue-94581.rs", -"ui/mir/auxiliary/issue_76375_aux.rs", -"ui/mir/issue-101844.rs", -"ui/mir/issue-102389.rs", -"ui/mir/issue-105809.rs", -"ui/mir/issue-106062.rs", -"ui/mir/issue-107678-projection-with-lifetime.rs", -"ui/mir/issue-107691.rs", -"ui/mir/issue-109004-drop-large-array.rs", -"ui/mir/issue-109743.rs", -"ui/mir/issue-112269.rs", -"ui/mir/issue-121103.rs", -"ui/mir/issue-29227.rs", -"ui/mir/issue-46845.rs", -"ui/mir/issue-60390.rs", -"ui/mir/issue-66851.rs", -"ui/mir/issue-66930.rs", -"ui/mir/issue-67639-normalization-ice.rs", -"ui/mir/issue-67710-inline-projection.rs", -"ui/mir/issue-67947.rs", -"ui/mir/issue-68841.rs", -"ui/mir/issue-71793-inline-args-storage.rs", -"ui/mir/issue-73914.rs", -"ui/mir/issue-74739.rs", -"ui/mir/issue-75053.rs", -"ui/mir/issue-75419-validation-impl-trait.rs", -"ui/mir/issue-76248.rs", -"ui/mir/issue-76375.rs", -"ui/mir/issue-76740-copy-propagation.rs", -"ui/mir/issue-76803-branches-not-same.rs", -"ui/mir/issue-77002.rs", -"ui/mir/issue-77359-simplify-arm-identity.rs", -"ui/mir/issue-77911.rs", -"ui/mir/issue-78496.rs", -"ui/mir/issue-80949.rs", -"ui/mir/issue-83499-input-output-iteration-ice.rs", -"ui/mir/issue-89485.rs", -"ui/mir/issue-91745.rs", -"ui/mir/issue-92893.rs", -"ui/mir/issue-99852.rs", -"ui/mir/issue-99866.rs", -"ui/mir/issue66339.rs", -"ui/mir/validate/issue-95978-validator-lifetime-comparison.rs", -"ui/mismatched_types/issue-106182.rs", -"ui/mismatched_types/issue-112036.rs", -"ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs", -"ui/mismatched_types/issue-118510.rs", -"ui/mismatched_types/issue-13033.rs", -"ui/mismatched_types/issue-1362.rs", -"ui/mismatched_types/issue-1448-2.rs", -"ui/mismatched_types/issue-19109.rs", -"ui/mismatched_types/issue-26480.rs", -"ui/mismatched_types/issue-35030.rs", -"ui/mismatched_types/issue-36053-2.rs", -"ui/mismatched_types/issue-38371-unfixable.rs", -"ui/mismatched_types/issue-38371.rs", -"ui/mismatched_types/issue-47706-trait.rs", -"ui/mismatched_types/issue-47706.rs", -"ui/mismatched_types/issue-74918-missing-lifetime.rs", -"ui/mismatched_types/issue-75361-mismatched-impl.rs", -"ui/mismatched_types/issue-84976.rs", -"ui/missing-trait-bounds/auxiliary/issue-69725.rs", -"ui/missing-trait-bounds/issue-35677.rs", -"ui/missing-trait-bounds/issue-69725.rs", -"ui/modules/issue-107649.rs", -"ui/modules/issue-56411-aux.rs", -"ui/modules/issue-56411.rs", -"ui/moves/issue-22536-copy-mustnt-zero.rs", -"ui/moves/issue-34721.rs", -"ui/moves/issue-46099-move-in-macro.rs", -"ui/moves/issue-72649-uninit-in-loop.rs", -"ui/moves/issue-75904-move-closure-loop.rs", -"ui/moves/issue-99470-move-out-of-some.rs", -"ui/never_type/issue-10176.rs", -"ui/never_type/issue-13352.rs", -"ui/never_type/issue-2149.rs", -"ui/never_type/issue-44402.rs", -"ui/never_type/issue-51506.rs", -"ui/never_type/issue-52443.rs", -"ui/never_type/issue-5500-1.rs", -"ui/never_type/issue-96335.rs", -"ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs", -"ui/nll/issue-112604-closure-output-normalize.rs", -"ui/nll/issue-16223.rs", -"ui/nll/issue-21114-ebfull.rs", -"ui/nll/issue-21114-kixunil.rs", -"ui/nll/issue-21232-partial-init-and-erroneous-use.rs", -"ui/nll/issue-21232-partial-init-and-use.rs", -"ui/nll/issue-22323-temp-destruction.rs", -"ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs", -"ui/nll/issue-27282-move-match-input-into-guard.rs", -"ui/nll/issue-27282-move-ref-mut-into-guard.rs", -"ui/nll/issue-27282-mutate-before-diverging-arm-1.rs", -"ui/nll/issue-27282-mutate-before-diverging-arm-2.rs", -"ui/nll/issue-27282-mutate-before-diverging-arm-3.rs", -"ui/nll/issue-27282-mutation-in-guard.rs", -"ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs", -"ui/nll/issue-27583.rs", -"ui/nll/issue-27868.rs", -"ui/nll/issue-30104.rs", -"ui/nll/issue-30438-a.rs", -"ui/nll/issue-30438-b.rs", -"ui/nll/issue-30438-c.rs", -"ui/nll/issue-31567.rs", -"ui/nll/issue-32382-index-assoc-type-with-lifetime.rs", -"ui/nll/issue-42574-diagnostic-in-nested-closure.rs", -"ui/nll/issue-43058.rs", -"ui/nll/issue-45157.rs", -"ui/nll/issue-45696-long-live-borrows-in-boxes.rs", -"ui/nll/issue-45696-no-variant-box-recur.rs", -"ui/nll/issue-45696-scribble-on-boxed-borrow.rs", -"ui/nll/issue-46023.rs", -"ui/nll/issue-46036.rs", -"ui/nll/issue-46589.rs", -"ui/nll/issue-47022.rs", -"ui/nll/issue-47153-generic-const.rs", -"ui/nll/issue-47388.rs", -"ui/nll/issue-47470.rs", -"ui/nll/issue-47589.rs", -"ui/nll/issue-48070.rs", -"ui/nll/issue-48179.rs", -"ui/nll/issue-48238.rs", -"ui/nll/issue-48623-closure.rs", -"ui/nll/issue-48623-coroutine.rs", -"ui/nll/issue-48697.rs", -"ui/nll/issue-48803.rs", -"ui/nll/issue-50343.rs", -"ui/nll/issue-50461-used-mut-from-moves.rs", -"ui/nll/issue-50716-1.rs", -"ui/nll/issue-50716.rs", -"ui/nll/issue-51191.rs", -"ui/nll/issue-51244.rs", -"ui/nll/issue-51268.rs", -"ui/nll/issue-51345-2.rs", -"ui/nll/issue-51351.rs", -"ui/nll/issue-51512.rs", -"ui/nll/issue-51770.rs", -"ui/nll/issue-52057.rs", -"ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs", -"ui/nll/issue-52078.rs", -"ui/nll/issue-52086.rs", -"ui/nll/issue-52113.rs", -"ui/nll/issue-52213.rs", -"ui/nll/issue-52533-1.rs", -"ui/nll/issue-52534-1.rs", -"ui/nll/issue-52534-2.rs", -"ui/nll/issue-52534.rs", -"ui/nll/issue-52663-span-decl-captured-variable.rs", -"ui/nll/issue-52663-trait-object.rs", -"ui/nll/issue-52669.rs", -"ui/nll/issue-52742.rs", -"ui/nll/issue-52992.rs", -"ui/nll/issue-53040.rs", -"ui/nll/issue-53119.rs", -"ui/nll/issue-53123-raw-pointer-cast.rs", -"ui/nll/issue-53570.rs", -"ui/nll/issue-53773.rs", -"ui/nll/issue-53807.rs", -"ui/nll/issue-54189.rs", -"ui/nll/issue-54302-cases.rs", -"ui/nll/issue-54302.rs", -"ui/nll/issue-54382-use-span-of-tail-of-block.rs", -"ui/nll/issue-54556-niconii.rs", -"ui/nll/issue-54556-stephaneyfx.rs", -"ui/nll/issue-54556-temps-in-tail-diagnostic.rs", -"ui/nll/issue-54556-used-vs-unused-tails.rs", -"ui/nll/issue-54556-wrap-it-up.rs", -"ui/nll/issue-54779-anon-static-lifetime.rs", -"ui/nll/issue-54943-3.rs", -"ui/nll/issue-54943.rs", -"ui/nll/issue-55288.rs", -"ui/nll/issue-55344.rs", -"ui/nll/issue-55394.rs", -"ui/nll/issue-55401.rs", -"ui/nll/issue-55511.rs", -"ui/nll/issue-55651.rs", -"ui/nll/issue-55825-const-fn.rs", -"ui/nll/issue-55850.rs", -"ui/nll/issue-57100.rs", -"ui/nll/issue-57265-return-type-wf-check.rs", -"ui/nll/issue-57280-1-flipped.rs", -"ui/nll/issue-57280-1.rs", -"ui/nll/issue-57280.rs", -"ui/nll/issue-57642-higher-ranked-subtype.rs", -"ui/nll/issue-57843.rs", -"ui/nll/issue-57960.rs", -"ui/nll/issue-57989.rs", -"ui/nll/issue-58053.rs", -"ui/nll/issue-58299.rs", -"ui/nll/issue-61311-normalize.rs", -"ui/nll/issue-61320-normalize.rs", -"ui/nll/issue-61424.rs", -"ui/nll/issue-62007-assign-const-index.rs", -"ui/nll/issue-62007-assign-differing-fields.rs", -"ui/nll/issue-63154-normalize.rs", -"ui/nll/issue-67007-escaping-data.rs", -"ui/nll/issue-68550.rs", -"ui/nll/issue-69114-static-mut-ty.rs", -"ui/nll/issue-69114-static-ty.rs", -"ui/nll/issue-73159-rpit-static.rs", -"ui/nll/issue-75777.rs", -"ui/nll/issue-78561.rs", -"ui/nll/issue-95272.rs", -"ui/nll/issue-97997.rs", -"ui/nll/issue-98170.rs", -"ui/nll/issue-98589-closures-relate-named-regions.rs", -"ui/nll/issue-98693.rs", -"ui/nll/polonius/issue-46589.rs", -"ui/nll/relate_tys/issue-48071.rs", -"ui/nll/ty-outlives/issue-53789-1.rs", -"ui/nll/ty-outlives/issue-53789-2.rs", -"ui/nll/ty-outlives/issue-55756.rs", -"ui/nll/user-annotations/issue-54124.rs", -"ui/nll/user-annotations/issue-54570-bootstrapping.rs", -"ui/nll/user-annotations/issue-55219.rs", -"ui/nll/user-annotations/issue-55241.rs", -"ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs", -"ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs", -"ui/numbers-arithmetic/issue-105626.rs", -"ui/numbers-arithmetic/issue-8460.rs", -"ui/object-safety/issue-102762.rs", -"ui/object-safety/issue-102933.rs", -"ui/object-safety/issue-106247.rs", -"ui/object-safety/issue-19538.rs", -"ui/on-unimplemented/issue-104140.rs", -"ui/or-patterns/issue-64879-trailing-before-guard.rs", -"ui/or-patterns/issue-67514-irrefutable-param.rs", -"ui/or-patterns/issue-68785-irrefutable-param-with-at.rs", -"ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs", -"ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs", -"ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs", -"ui/overloaded/issue-14958.rs", -"ui/packed/issue-118537-field-offset-ice.rs", -"ui/packed/issue-118537-field-offset.rs", -"ui/packed/issue-27060-2.rs", -"ui/packed/issue-27060.rs", -"ui/packed/issue-46152.rs", -"ui/panics/issue-47429-short-backtraces.rs", -"ui/parser/issue-116781.rs", -"ui/parser/issues/auxiliary/issue-21146-inc.rs", -"ui/parser/issues/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs", -"ui/parser/issues/auxiliary/issue-94340-inc.rs", -"ui/parser/issues/issue-100197-mut-let.rs", -"ui/parser/issues/issue-101477-enum.rs", -"ui/parser/issues/issue-101477-let.rs", -"ui/parser/issues/issue-101540.rs", -"ui/parser/issues/issue-102182-impl-trait-recover.rs", -"ui/parser/issues/issue-102806.rs", -"ui/parser/issues/issue-103143.rs", -"ui/parser/issues/issue-103381.rs", -"ui/parser/issues/issue-103425.rs", -"ui/parser/issues/issue-103451.rs", -"ui/parser/issues/issue-103748-ICE-wrong-braces.rs", -"ui/parser/issues/issue-10392-2.rs", -"ui/parser/issues/issue-10392.rs", -"ui/parser/issues/issue-104367.rs", -"ui/parser/issues/issue-104620.rs", -"ui/parser/issues/issue-104867-inc-dec-2.rs", -"ui/parser/issues/issue-104867-inc-dec.rs", -"ui/parser/issues/issue-105209.rs", -"ui/parser/issues/issue-105366.rs", -"ui/parser/issues/issue-105634.rs", -"ui/parser/issues/issue-10636-1.rs", -"ui/parser/issues/issue-10636-2.rs", -"ui/parser/issues/issue-107705.rs", -"ui/parser/issues/issue-108109-fn-missing-params.rs", -"ui/parser/issues/issue-108109-fn-trait-missing-paren.rs", -"ui/parser/issues/issue-108242-semicolon-recovery.rs", -"ui/parser/issues/issue-108495-dec.rs", -"ui/parser/issues/issue-110014.rs", -"ui/parser/issues/issue-111148.rs", -"ui/parser/issues/issue-111416.rs", -"ui/parser/issues/issue-111692.rs", -"ui/parser/issues/issue-112188.rs", -"ui/parser/issues/issue-112458.rs", -"ui/parser/issues/issue-113110-non-item-at-module-root.rs", -"ui/parser/issues/issue-113203.rs", -"ui/parser/issues/issue-113342.rs", -"ui/parser/issues/issue-114219.rs", -"ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs", -"ui/parser/issues/issue-118530-ice.rs", -"ui/parser/issues/issue-118531-ice.rs", -"ui/parser/issues/issue-13483.rs", -"ui/parser/issues/issue-14303-fncall.rs", -"ui/parser/issues/issue-14303.rs", -"ui/parser/issues/issue-15914.rs", -"ui/parser/issues/issue-15980.rs", -"ui/parser/issues/issue-1655.rs", -"ui/parser/issues/issue-17718-const-mut.rs", -"ui/parser/issues/issue-17718-parse-const.rs", -"ui/parser/issues/issue-17904-2.rs", -"ui/parser/issues/issue-17904.rs", -"ui/parser/issues/issue-1802-1.rs", -"ui/parser/issues/issue-1802-2.rs", -"ui/parser/issues/issue-19096.rs", -"ui/parser/issues/issue-19398.rs", -"ui/parser/issues/issue-20616-1.rs", -"ui/parser/issues/issue-20616-2.rs", -"ui/parser/issues/issue-20616-3.rs", -"ui/parser/issues/issue-20616-4.rs", -"ui/parser/issues/issue-20616-5.rs", -"ui/parser/issues/issue-20616-6.rs", -"ui/parser/issues/issue-20616-7.rs", -"ui/parser/issues/issue-20616-8.rs", -"ui/parser/issues/issue-20616-9.rs", -"ui/parser/issues/issue-20711-2.rs", -"ui/parser/issues/issue-20711.rs", -"ui/parser/issues/issue-21146.rs", -"ui/parser/issues/issue-21153.rs", -"ui/parser/issues/issue-21475.rs", -"ui/parser/issues/issue-22647.rs", -"ui/parser/issues/issue-22712.rs", -"ui/parser/issues/issue-2354-1.rs", -"ui/parser/issues/issue-2354.rs", -"ui/parser/issues/issue-23620-invalid-escapes.rs", -"ui/parser/issues/issue-24197.rs", -"ui/parser/issues/issue-24375.rs", -"ui/parser/issues/issue-24780.rs", -"ui/parser/issues/issue-27255.rs", -"ui/parser/issues/issue-30318.rs", -"ui/parser/issues/issue-3036.rs", -"ui/parser/issues/issue-31804.rs", -"ui/parser/issues/issue-32214.rs", -"ui/parser/issues/issue-32446.rs", -"ui/parser/issues/issue-32501.rs", -"ui/parser/issues/issue-32505.rs", -"ui/parser/issues/issue-33262.rs", -"ui/parser/issues/issue-33413.rs", -"ui/parser/issues/issue-33418.rs", -"ui/parser/issues/issue-33455.rs", -"ui/parser/issues/issue-34222-1.rs", -"ui/parser/issues/issue-34255-1.rs", -"ui/parser/issues/issue-35813-postfix-after-cast.rs", -"ui/parser/issues/issue-39616.rs", -"ui/parser/issues/issue-41155.rs", -"ui/parser/issues/issue-43196.rs", -"ui/parser/issues/issue-43692.rs", -"ui/parser/issues/issue-44021.rs", -"ui/parser/issues/issue-44406.rs", -"ui/parser/issues/issue-45296.rs", -"ui/parser/issues/issue-46186.rs", -"ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs", -"ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items.rs", -"ui/parser/issues/issue-48508-aux.rs", -"ui/parser/issues/issue-48508.rs", -"ui/parser/issues/issue-48636.rs", -"ui/parser/issues/issue-49040.rs", -"ui/parser/issues/issue-49257.rs", -"ui/parser/issues/issue-51602.rs", -"ui/parser/issues/issue-52496.rs", -"ui/parser/issues/issue-54521-1.rs", -"ui/parser/issues/issue-54521-2.rs", -"ui/parser/issues/issue-54521-3.rs", -"ui/parser/issues/issue-5544-a.rs", -"ui/parser/issues/issue-5544-b.rs", -"ui/parser/issues/issue-56031.rs", -"ui/parser/issues/issue-57198.rs", -"ui/parser/issues/issue-57684.rs", -"ui/parser/issues/issue-57819.rs", -"ui/parser/issues/issue-5806.rs", -"ui/parser/issues/issue-58094-missing-right-square-bracket.rs", -"ui/parser/issues/issue-58856-1.rs", -"ui/parser/issues/issue-58856-2.rs", -"ui/parser/issues/issue-59418.rs", -"ui/parser/issues/issue-60075.rs", -"ui/parser/issues/issue-61858.rs", -"ui/parser/issues/issue-62524.rs", -"ui/parser/issues/issue-62546.rs", -"ui/parser/issues/issue-62554.rs", -"ui/parser/issues/issue-62660.rs", -"ui/parser/issues/issue-62881.rs", -"ui/parser/issues/issue-62894.rs", -"ui/parser/issues/issue-62895.rs", -"ui/parser/issues/issue-62913.rs", -"ui/parser/issues/issue-62973.rs", -"ui/parser/issues/issue-63115-range-pat-interpolated.rs", -"ui/parser/issues/issue-63116.rs", -"ui/parser/issues/issue-63135.rs", -"ui/parser/issues/issue-64732.rs", -"ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs", -"ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs", -"ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs", -"ui/parser/issues/issue-65257-invalid-var-decl-recovery.rs", -"ui/parser/issues/issue-65846-rollback-gating-failing-matcher.rs", -"ui/parser/issues/issue-6610.rs", -"ui/parser/issues/issue-66357-unexpected-unreachable.rs", -"ui/parser/issues/issue-66473.rs", -"ui/parser/issues/issue-67146-negative-outlives-bound-syntactic-fail.rs", -"ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs", -"ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.rs", -"ui/parser/issues/issue-68091-unicode-ident-after-if.rs", -"ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs", -"ui/parser/issues/issue-68629.rs", -"ui/parser/issues/issue-68730.rs", -"ui/parser/issues/issue-68788-in-trait-item-propagation.rs", -"ui/parser/issues/issue-68890-2.rs", -"ui/parser/issues/issue-68890.rs", -"ui/parser/issues/issue-68987-unmatch-issue-1.rs", -"ui/parser/issues/issue-68987-unmatch-issue-2.rs", -"ui/parser/issues/issue-68987-unmatch-issue-3.rs", -"ui/parser/issues/issue-68987-unmatch-issue.rs", -"ui/parser/issues/issue-69259.rs", -"ui/parser/issues/issue-70050-ntliteral-accepts-negated-lit.rs", -"ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.rs", -"ui/parser/issues/issue-70388-without-witness.rs", -"ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.rs", -"ui/parser/issues/issue-70552-ascription-in-parens-after-call.rs", -"ui/parser/issues/issue-70583-block-is-empty-1.rs", -"ui/parser/issues/issue-70583-block-is-empty-2.rs", -"ui/parser/issues/issue-7222.rs", -"ui/parser/issues/issue-72253.rs", -"ui/parser/issues/issue-72373.rs", -"ui/parser/issues/issue-73568-lifetime-after-mut.rs", -"ui/parser/issues/issue-75599.rs", -"ui/parser/issues/issue-76437-async.rs", -"ui/parser/issues/issue-76437-const-async-unsafe.rs", -"ui/parser/issues/issue-76437-const-async.rs", -"ui/parser/issues/issue-76437-const.rs", -"ui/parser/issues/issue-76437-pub-crate-unsafe.rs", -"ui/parser/issues/issue-76437-unsafe.rs", -"ui/parser/issues/issue-76597.rs", -"ui/parser/issues/issue-7970b.rs", -"ui/parser/issues/issue-81804.rs", -"ui/parser/issues/issue-81806.rs", -"ui/parser/issues/issue-81827.rs", -"ui/parser/issues/issue-83639.rs", -"ui/parser/issues/issue-84104.rs", -"ui/parser/issues/issue-84117.rs", -"ui/parser/issues/issue-84148-1.rs", -"ui/parser/issues/issue-84148-2.rs", -"ui/parser/issues/issue-8537.rs", -"ui/parser/issues/issue-86895.rs", -"ui/parser/issues/issue-87086-colon-path-sep.rs", -"ui/parser/issues/issue-87197-missing-semicolon.rs", -"ui/parser/issues/issue-87635.rs", -"ui/parser/issues/issue-87694-duplicated-pub.rs", -"ui/parser/issues/issue-87694-misplaced-pub.rs", -"ui/parser/issues/issue-87812-path.rs", -"ui/parser/issues/issue-87812.rs", -"ui/parser/issues/issue-88276-unary-plus.rs", -"ui/parser/issues/issue-88583-union-as-ident.rs", -"ui/parser/issues/issue-88770.rs", -"ui/parser/issues/issue-88818.rs", -"ui/parser/issues/issue-89388.rs", -"ui/parser/issues/issue-89396.rs", -"ui/parser/issues/issue-89574.rs", -"ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs", -"ui/parser/issues/issue-90728.rs", -"ui/parser/issues/issue-90993.rs", -"ui/parser/issues/issue-91421.rs", -"ui/parser/issues/issue-91461.rs", -"ui/parser/issues/issue-93282.rs", -"ui/parser/issues/issue-93867.rs", -"ui/parser/issues/issue-94340.rs", -"ui/parser/issues/issue-98601-delimiter-error-1.rs", -"ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs", -"ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.rs", -"ui/parser/issues/issue-99910-const-let-mutually-exclusive.rs", -"ui/parser/macro/issue-33569.rs", -"ui/parser/macro/issue-37113.rs", -"ui/parser/macro/issue-37234.rs", -"ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs", -"ui/parser/shebang/issue-71471-ignore-tidy.rs", -"ui/pattern/issue-10392.rs", -"ui/pattern/issue-106552.rs", -"ui/pattern/issue-106862.rs", -"ui/pattern/issue-110508.rs", -"ui/pattern/issue-115599.rs", -"ui/pattern/issue-11577.rs", -"ui/pattern/issue-117626.rs", -"ui/pattern/issue-12582.rs", -"ui/pattern/issue-14221.rs", -"ui/pattern/issue-15080.rs", -"ui/pattern/issue-17718-patterns.rs", -"ui/pattern/issue-22546.rs", -"ui/pattern/issue-27320.rs", -"ui/pattern/issue-28992-empty.rs", -"ui/pattern/issue-52240.rs", -"ui/pattern/issue-6449.rs", -"ui/pattern/issue-66270-pat-struct-parser-recovery.rs", -"ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs", -"ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs", -"ui/pattern/issue-68393-let-pat-assoc-constant.rs", -"ui/pattern/issue-72565.rs", -"ui/pattern/issue-72574-1.rs", -"ui/pattern/issue-72574-2.rs", -"ui/pattern/issue-74539.rs", -"ui/pattern/issue-74702.rs", -"ui/pattern/issue-74954.rs", -"ui/pattern/issue-80186-mut-binding-help-suggestion.rs", -"ui/pattern/issue-8351-1.rs", -"ui/pattern/issue-8351-2.rs", -"ui/pattern/issue-88074-pat-range-type-inference-err.rs", -"ui/pattern/issue-88074-pat-range-type-inference.rs", -"ui/pattern/issue-92074-macro-ice.rs", -"ui/pattern/issue-94866.rs", -"ui/pattern/issue-95878.rs", -"ui/pattern/move-ref-patterns/issue-53840.rs", -"ui/pattern/usefulness/integer-ranges/issue-117648-overlapping_range_endpoints-false-positive.rs", -"ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs", -"ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs", -"ui/pattern/usefulness/issue-119493-type-error-ice.rs", -"ui/pattern/usefulness/issue-119778-type-error-ice.rs", -"ui/pattern/usefulness/issue-12116.rs", -"ui/pattern/usefulness/issue-12369.rs", -"ui/pattern/usefulness/issue-13727.rs", -"ui/pattern/usefulness/issue-15129.rs", -"ui/pattern/usefulness/issue-2111.rs", -"ui/pattern/usefulness/issue-30240-b.rs", -"ui/pattern/usefulness/issue-30240-rpass.rs", -"ui/pattern/usefulness/issue-30240.rs", -"ui/pattern/usefulness/issue-3096-1.rs", -"ui/pattern/usefulness/issue-3096-2.rs", -"ui/pattern/usefulness/issue-31221.rs", -"ui/pattern/usefulness/issue-31561.rs", -"ui/pattern/usefulness/issue-35609.rs", -"ui/pattern/usefulness/issue-3601.rs", -"ui/pattern/usefulness/issue-39362.rs", -"ui/pattern/usefulness/issue-40221.rs", -"ui/pattern/usefulness/issue-4321.rs", -"ui/pattern/usefulness/issue-50900.rs", -"ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs", -"ui/pattern/usefulness/issue-56379.rs", -"ui/pattern/usefulness/issue-57472.rs", -"ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs", -"ui/pattern/usefulness/issue-66501.rs", -"ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs", -"ui/pattern/usefulness/issue-72377.rs", -"ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs", -"ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs", -"ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs", -"ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs", -"ui/pattern/usefulness/issue-82772-match-box-as-struct.rs", -"ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs", -"ui/pattern/usefulness/issue-88747.rs", -"ui/polymorphization/issue-74614.rs", -"ui/polymorphization/issue-74636.rs", -"ui/privacy/auxiliary/issue-117997.rs", -"ui/privacy/auxiliary/issue-119463-extern.rs", -"ui/privacy/auxiliary/issue-17718-const-privacy.rs", -"ui/privacy/auxiliary/issue-57264-1.rs", -"ui/privacy/auxiliary/issue-57264-2.rs", -"ui/privacy/auxiliary/issue-75907.rs", -"ui/privacy/auxiliary/issue-92755.rs", -"ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs", -"ui/privacy/issue-111220-tuple-struct-fields.rs", -"ui/privacy/issue-113860-1.rs", -"ui/privacy/issue-113860-2.rs", -"ui/privacy/issue-113860.rs", -"ui/privacy/issue-11593.rs", -"ui/privacy/issue-117997.rs", -"ui/privacy/issue-119463.rs", -"ui/privacy/issue-13641.rs", -"ui/privacy/issue-17718-const-privacy.rs", -"ui/privacy/issue-29161.rs", -"ui/privacy/issue-30079.rs", -"ui/privacy/issue-46209-private-enum-variant-reexport.rs", -"ui/privacy/issue-57264-1.rs", -"ui/privacy/issue-57264-2.rs", -"ui/privacy/issue-75062-fieldless-tuple-struct.rs", -"ui/privacy/issue-75906.rs", -"ui/privacy/issue-75907.rs", -"ui/privacy/issue-75907_b.rs", -"ui/privacy/issue-79593.rs", -"ui/privacy/issue-92755.rs", -"ui/proc-macro/auxiliary/issue-104884.rs", -"ui/proc-macro/auxiliary/issue-107113.rs", -"ui/proc-macro/auxiliary/issue-118809.rs", -"ui/proc-macro/auxiliary/issue-38586.rs", -"ui/proc-macro/auxiliary/issue-39889.rs", -"ui/proc-macro/auxiliary/issue-42708.rs", -"ui/proc-macro/auxiliary/issue-50061.rs", -"ui/proc-macro/auxiliary/issue-50493.rs", -"ui/proc-macro/auxiliary/issue-59191.rs", -"ui/proc-macro/auxiliary/issue-66286.rs", -"ui/proc-macro/auxiliary/issue-75801.rs", -"ui/proc-macro/auxiliary/issue-79242.rs", -"ui/proc-macro/auxiliary/issue-79825.rs", -"ui/proc-macro/auxiliary/issue-83510.rs", -"ui/proc-macro/auxiliary/issue-91800-macro.rs", -"ui/proc-macro/issue-104884-trait-impl-sugg-err.rs", -"ui/proc-macro/issue-107113-wrap.rs", -"ui/proc-macro/issue-118455-skip-err-builtin.rs", -"ui/proc-macro/issue-118809.rs", -"ui/proc-macro/issue-36935.rs", -"ui/proc-macro/issue-37788.rs", -"ui/proc-macro/issue-38586.rs", -"ui/proc-macro/issue-39889.rs", -"ui/proc-macro/issue-42708.rs", -"ui/proc-macro/issue-50061.rs", -"ui/proc-macro/issue-50493.rs", -"ui/proc-macro/issue-53481.rs", -"ui/proc-macro/issue-59191-replace-root-with-fn.rs", -"ui/proc-macro/issue-66286.rs", -"ui/proc-macro/issue-73933-procedural-masquerade.rs", -"ui/proc-macro/issue-75734-pp-paren.rs", -"ui/proc-macro/issue-75801.rs", -"ui/proc-macro/issue-75930-derive-cfg.rs", -"ui/proc-macro/issue-76182-leading-vert-pat.rs", -"ui/proc-macro/issue-76270-panic-in-libproc-macro.rs", -"ui/proc-macro/issue-78675-captured-inner-attrs.rs", -"ui/proc-macro/issue-79148.rs", -"ui/proc-macro/issue-79242-slow-retokenize-check.rs", -"ui/proc-macro/issue-79825.rs", -"ui/proc-macro/issue-80760-empty-stmt.rs", -"ui/proc-macro/issue-81007-item-attrs.rs", -"ui/proc-macro/issue-81543-item-parse-err.rs", -"ui/proc-macro/issue-81555.rs", -"ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs", -"ui/proc-macro/issue-83510.rs", -"ui/proc-macro/issue-86781-bad-inner-doc.rs", -"ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs", -"ui/proc-macro/issue-91800.rs", -"ui/process/issue-13304.rs", -"ui/process/issue-14456.rs", -"ui/process/issue-14940.rs", -"ui/process/issue-16272.rs", -"ui/process/issue-20091.rs", -"ui/process/issue-30490.rs", -"ui/ptr_ops/issue-80309-safe.rs", -"ui/ptr_ops/issue-80309.rs", -"ui/pub/issue-33174-restricted-type-in-public-interface.rs", -"ui/query-system/issue-83479.rs", -"ui/range/issue-54505-no-literals.rs", -"ui/range/issue-54505-no-std.rs", -"ui/range/issue-54505.rs", -"ui/range/issue-73553-misinterp-range-literal.rs", -"ui/reachable/auxiliary/issue-11225-1.rs", -"ui/reachable/auxiliary/issue-11225-2.rs", -"ui/reachable/auxiliary/issue-11225-3.rs", -"ui/reachable/issue-11225-1.rs", -"ui/reachable/issue-11225-2.rs", -"ui/reachable/issue-11225-3.rs", -"ui/reachable/issue-948.rs", -"ui/recursion/issue-26548-recursion-via-normalize.rs", -"ui/recursion/issue-38591-non-regular-dropck-recursion.rs", -"ui/recursion/issue-83150.rs", -"ui/recursion/issue-86784.rs", -"ui/recursion/issue-95134.rs", -"ui/recursion_limit/issue-105700.rs", -"ui/recursion_limit/issue-40003.rs", -"ui/regions/issue-101280.rs", -"ui/regions/issue-102374.rs", -"ui/regions/issue-102392.rs", -"ui/regions/issue-11612.rs", -"ui/regions/issue-12470.rs", -"ui/regions/issue-21520.rs", -"ui/regions/issue-24085.rs", -"ui/regions/issue-26448-1.rs", -"ui/regions/issue-26448-2.rs", -"ui/regions/issue-26448-3.rs", -"ui/regions/issue-28848.rs", -"ui/regions/issue-5243.rs", -"ui/regions/issue-56537-closure-uses-region-from-container.rs", -"ui/regions/issue-6157.rs", -"ui/regions/issue-72051-member-region-hang.rs", -"ui/regions/issue-78262.rs", -"ui/repr/issue-83505-repr-simd.rs", -"ui/resolve/auxiliary/issue-112831-aux.rs", -"ui/resolve/auxiliary/issue-19452-aux.rs", -"ui/resolve/auxiliary/issue-21221-3.rs", -"ui/resolve/auxiliary/issue-21221-4.rs", -"ui/resolve/auxiliary/issue-30535.rs", -"ui/resolve/auxiliary/issue-3907.rs", -"ui/resolve/auxiliary/issue-80079.rs", -"ui/resolve/issue-100365.rs", -"ui/resolve/issue-101749-2.rs", -"ui/resolve/issue-101749.rs", -"ui/resolve/issue-10200.rs", -"ui/resolve/issue-102946.rs", -"ui/resolve/issue-103202.rs", -"ui/resolve/issue-103474.rs", -"ui/resolve/issue-104700-inner_scope.rs", -"ui/resolve/issue-105069.rs", -"ui/resolve/issue-107563-ambiguous-glob-reexports.rs", -"ui/resolve/issue-108529.rs", -"ui/resolve/issue-109153.rs", -"ui/resolve/issue-109250.rs", -"ui/resolve/issue-111312.rs", -"ui/resolve/issue-111727.rs", -"ui/resolve/issue-112472-multi-generics-suggestion.rs", -"ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs", -"ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs", -"ui/resolve/issue-116164.rs", -"ui/resolve/issue-117920.rs", -"ui/resolve/issue-118295.rs", -"ui/resolve/issue-120559.rs", -"ui/resolve/issue-12796.rs", -"ui/resolve/issue-14254.rs", -"ui/resolve/issue-16058.rs", -"ui/resolve/issue-17518.rs", -"ui/resolve/issue-18252.rs", -"ui/resolve/issue-19452.rs", -"ui/resolve/issue-21221-1.rs", -"ui/resolve/issue-21221-2.rs", -"ui/resolve/issue-21221-3.rs", -"ui/resolve/issue-21221-4.rs", -"ui/resolve/issue-22692.rs", -"ui/resolve/issue-2330.rs", -"ui/resolve/issue-23305.rs", -"ui/resolve/issue-2356.rs", -"ui/resolve/issue-23716.rs", -"ui/resolve/issue-24968.rs", -"ui/resolve/issue-26545.rs", -"ui/resolve/issue-3021-c.rs", -"ui/resolve/issue-3021.rs", -"ui/resolve/issue-30535.rs", -"ui/resolve/issue-3099-a.rs", -"ui/resolve/issue-3099-b.rs", -"ui/resolve/issue-31845.rs", -"ui/resolve/issue-33876.rs", -"ui/resolve/issue-35675.rs", -"ui/resolve/issue-3907-2.rs", -"ui/resolve/issue-3907.rs", -"ui/resolve/issue-39226.rs", -"ui/resolve/issue-39559-2.rs", -"ui/resolve/issue-39559.rs", -"ui/resolve/issue-42944.rs", -"ui/resolve/issue-49074.rs", -"ui/resolve/issue-5035-2.rs", -"ui/resolve/issue-5035.rs", -"ui/resolve/issue-50599.rs", -"ui/resolve/issue-5099.rs", -"ui/resolve/issue-54379.rs", -"ui/resolve/issue-55673.rs", -"ui/resolve/issue-57523.rs", -"ui/resolve/issue-5927.rs", -"ui/resolve/issue-60057.rs", -"ui/resolve/issue-65025-extern-static-parent-generics.rs", -"ui/resolve/issue-65035-static-with-parent-generics.rs", -"ui/resolve/issue-6642.rs", -"ui/resolve/issue-6702.rs", -"ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs", -"ui/resolve/issue-70736-async-fn-no-body-def-collector.rs", -"ui/resolve/issue-73427.rs", -"ui/resolve/issue-80079.rs", -"ui/resolve/issue-81508.rs", -"ui/resolve/issue-82156.rs", -"ui/resolve/issue-82865.rs", -"ui/resolve/issue-85348.rs", -"ui/resolve/issue-85671.rs", -"ui/resolve/issue-88472.rs", -"ui/resolve/issue-90113.rs", -"ui/return/issue-64620.rs", -"ui/return/issue-82612-return-mutable-reference.rs", -"ui/return/issue-86188-return-not-in-fn-body.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs", -"ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs", -"ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs", -"ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs", -"ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs", -"ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs", -"ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs", -"ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs", -"ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs", -"ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs", -"ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs", -"ui/rust-2018/issue-51008-1.rs", -"ui/rust-2018/issue-51008.rs", -"ui/rust-2018/issue-52202-use-suggestions.rs", -"ui/rust-2018/issue-54006.rs", -"ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-56596.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs", -"ui/rust-2018/uniform-paths/issue-54253.rs", -"ui/rust-2018/uniform-paths/issue-55779.rs", -"ui/rust-2018/uniform-paths/issue-56596-2.rs", -"ui/rust-2018/uniform-paths/issue-56596.rs", -"ui/rust-2018/uniform-paths/issue-87932.rs", -"ui/sanitizer/issue-111184-cfi-coroutine-witness.rs", -"ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs", -"ui/sanitizer/issue-72154-address-lifetime-markers.rs", -"ui/self/issue-61882-2.rs", -"ui/self/issue-61882.rs", -"ui/simd/intrinsic/issue-85855.rs", -"ui/simd/issue-105439.rs", -"ui/simd/issue-17170.rs", -"ui/simd/issue-32947.rs", -"ui/simd/issue-39720.rs", -"ui/simd/issue-85915-simd-ptrs.rs", -"ui/simd/issue-89193.rs", -"ui/single-use-lifetime/issue-104440.rs", -"ui/single-use-lifetime/issue-107998.rs", -"ui/single-use-lifetime/issue-117965.rs", -"ui/span/issue-107353.rs", -"ui/span/issue-11925.rs", -"ui/span/issue-15480.rs", -"ui/span/issue-23338-locals-die-before-temps-of-body.rs", -"ui/span/issue-23729.rs", -"ui/span/issue-23827.rs", -"ui/span/issue-24356.rs", -"ui/span/issue-24690.rs", -"ui/span/issue-24805-dropck-child-has-items-via-parent.rs", -"ui/span/issue-24805-dropck-trait-has-items.rs", -"ui/span/issue-24895-copy-clone-dropck.rs", -"ui/span/issue-25199.rs", -"ui/span/issue-26656.rs", -"ui/span/issue-27522.rs", -"ui/span/issue-29106.rs", -"ui/span/issue-29595.rs", -"ui/span/issue-33884.rs", -"ui/span/issue-34264.rs", -"ui/span/issue-35987.rs", -"ui/span/issue-36537.rs", -"ui/span/issue-37767.rs", -"ui/span/issue-39018.rs", -"ui/span/issue-39698.rs", -"ui/span/issue-40157.rs", -"ui/span/issue-42234-unknown-receiver-type.rs", -"ui/span/issue-43927-non-ADT-derive.rs", -"ui/span/issue-71363.rs", -"ui/span/issue-81800.rs", -"ui/span/issue28498-reject-ex1.rs", -"ui/span/issue28498-reject-lifetime-param.rs", -"ui/span/issue28498-reject-passed-to-fn.rs", -"ui/span/issue28498-reject-trait-bound.rs", -"ui/specialization/issue-111232.rs", -"ui/specialization/issue-33017.rs", -"ui/specialization/issue-35376.rs", -"ui/specialization/issue-36804.rs", -"ui/specialization/issue-38091-2.rs", -"ui/specialization/issue-38091.rs", -"ui/specialization/issue-39448.rs", -"ui/specialization/issue-39618.rs", -"ui/specialization/issue-40582.rs", -"ui/specialization/issue-43037.rs", -"ui/specialization/issue-44861.rs", -"ui/specialization/issue-45814.rs", -"ui/specialization/issue-50452-fail.rs", -"ui/specialization/issue-50452.rs", -"ui/specialization/issue-51892.rs", -"ui/specialization/issue-52050.rs", -"ui/specialization/issue-59435.rs", -"ui/specialization/issue-63716-parse-async.rs", -"ui/specialization/issue-68830-spurious-diagnostics.rs", -"ui/specialization/issue-70442.rs", -"ui/specialization/min_specialization/issue-79224.rs", -"ui/stability-attribute/issue-106589.rs", -"ui/stability-attribute/issue-109177.rs", -"ui/stability-attribute/issue-28075.rs", -"ui/stability-attribute/issue-28388-3.rs", -"ui/stability-attribute/issue-99286-stable-intrinsics.rs", -"ui/static/auxiliary/issue_24843.rs", -"ui/static/issue-1660.rs", -"ui/static/issue-18118-2.rs", -"ui/static/issue-18118.rs", -"ui/static/issue-24446.rs", -"ui/static/issue-24843.rs", -"ui/static/issue-34194.rs", -"ui/static/issue-5216.rs", -"ui/statics/issue-14227.rs", -"ui/statics/issue-15261.rs", -"ui/statics/issue-17233.rs", -"ui/statics/issue-17718-static-sync.rs", -"ui/statics/issue-17718-static-unsafe-interior.rs", -"ui/statics/issue-44373-2.rs", -"ui/statics/issue-44373.rs", -"ui/statics/issue-91050-1.rs", -"ui/statics/issue-91050-2.rs", -"ui/std/issue-3563-3.rs", -"ui/std/issue-81357-unsound-file-methods.rs", -"ui/stdlib-unit-tests/issue-21058.rs", -"ui/structs-enums/enum-rec/issue-17431-6.rs", -"ui/structs-enums/enum-rec/issue-17431-7.rs", -"ui/structs-enums/issue-103869.rs", -"ui/structs-enums/issue-1701.rs", -"ui/structs-enums/issue-2718-a.rs", -"ui/structs-enums/issue-3008-1.rs", -"ui/structs-enums/issue-3008-2.rs", -"ui/structs-enums/issue-3008-3.rs", -"ui/structs-enums/issue-38002.rs", -"ui/structs-enums/issue-50731.rs", -"ui/structs-enums/struct-rec/issue-17431-1.rs", -"ui/structs-enums/struct-rec/issue-17431-2.rs", -"ui/structs-enums/struct-rec/issue-17431-3.rs", -"ui/structs-enums/struct-rec/issue-17431-4.rs", -"ui/structs-enums/struct-rec/issue-17431-5.rs", -"ui/structs-enums/struct-rec/issue-74224.rs", -"ui/structs-enums/struct-rec/issue-84611.rs", -"ui/structs/issue-80853.rs", -"ui/suggestions/auxiliary/issue-61963-1.rs", -"ui/suggestions/auxiliary/issue-61963.rs", -"ui/suggestions/auxiliary/issue-81839.rs", -"ui/suggestions/issue-101065.rs", -"ui/suggestions/issue-101421.rs", -"ui/suggestions/issue-101465.rs", -"ui/suggestions/issue-101623.rs", -"ui/suggestions/issue-101984.rs", -"ui/suggestions/issue-102354.rs", -"ui/suggestions/issue-102892.rs", -"ui/suggestions/issue-102972.rs", -"ui/suggestions/issue-103112.rs", -"ui/suggestions/issue-103646.rs", -"ui/suggestions/issue-104086-suggest-let.rs", -"ui/suggestions/issue-104287.rs", -"ui/suggestions/issue-104327.rs", -"ui/suggestions/issue-104328.rs", -"ui/suggestions/issue-104961.rs", -"ui/suggestions/issue-105226.rs", -"ui/suggestions/issue-105494.rs", -"ui/suggestions/issue-105645.rs", -"ui/suggestions/issue-105761-suggest-self-for-closure.rs", -"ui/suggestions/issue-106443-sugg-clone-for-arg.rs", -"ui/suggestions/issue-106443-sugg-clone-for-bound.rs", -"ui/suggestions/issue-107860.rs", -"ui/suggestions/issue-108470.rs", -"ui/suggestions/issue-109195.rs", -"ui/suggestions/issue-109291.rs", -"ui/suggestions/issue-109396.rs", -"ui/suggestions/issue-109436.rs", -"ui/suggestions/issue-109854.rs", -"ui/suggestions/issue-109991.rs", -"ui/suggestions/issue-112590-suggest-import.rs", -"ui/suggestions/issue-114701.rs", -"ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs", -"ui/suggestions/issue-116434-2015.rs", -"ui/suggestions/issue-116434-2021.rs", -"ui/suggestions/issue-117669.rs", -"ui/suggestions/issue-21673.rs", -"ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs", -"ui/suggestions/issue-52820.rs", -"ui/suggestions/issue-53692.rs", -"ui/suggestions/issue-57672.rs", -"ui/suggestions/issue-59819.rs", -"ui/suggestions/issue-61226.rs", -"ui/suggestions/issue-61963.rs", -"ui/suggestions/issue-62843.rs", -"ui/suggestions/issue-64252-self-type.rs", -"ui/suggestions/issue-66968-suggest-sorted-words.rs", -"ui/suggestions/issue-68049-1.rs", -"ui/suggestions/issue-68049-2.rs", -"ui/suggestions/issue-71394-no-from-impl.rs", -"ui/suggestions/issue-72766.rs", -"ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs", -"ui/suggestions/issue-81098.rs", -"ui/suggestions/issue-81839.rs", -"ui/suggestions/issue-82361.rs", -"ui/suggestions/issue-82566-1.rs", -"ui/suggestions/issue-82566-2.rs", -"ui/suggestions/issue-83892.rs", -"ui/suggestions/issue-83943.rs", -"ui/suggestions/issue-84592.rs", -"ui/suggestions/issue-84700.rs", -"ui/suggestions/issue-84973-2.rs", -"ui/suggestions/issue-84973-blacklist.rs", -"ui/suggestions/issue-84973-negative.rs", -"ui/suggestions/issue-84973.rs", -"ui/suggestions/issue-85347.rs", -"ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs", -"ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs", -"ui/suggestions/issue-86100-tuple-paren-comma.rs", -"ui/suggestions/issue-86667.rs", -"ui/suggestions/issue-88696.rs", -"ui/suggestions/issue-88730.rs", -"ui/suggestions/issue-89064.rs", -"ui/suggestions/issue-89333.rs", -"ui/suggestions/issue-89640.rs", -"ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs", -"ui/suggestions/issue-90974.rs", -"ui/suggestions/issue-94171.rs", -"ui/suggestions/issue-96223.rs", -"ui/suggestions/issue-96555.rs", -"ui/suggestions/issue-97677.rs", -"ui/suggestions/issue-97704.rs", -"ui/suggestions/issue-97760.rs", -"ui/suggestions/issue-98500.rs", -"ui/suggestions/issue-98562.rs", -"ui/suggestions/issue-99080.rs", -"ui/suggestions/issue-99240-2.rs", -"ui/suggestions/issue-99240.rs", -"ui/suggestions/issue-99597.rs", -"ui/suggestions/lifetimes/issue-105544.rs", -"ui/symbol-names/issue-53912.rs", -"ui/symbol-names/issue-60925.rs", -"ui/symbol-names/issue-75326.rs", -"ui/symbol-names/issue-76365.rs", -"ui/test-attrs/custom-test-frameworks/issue-107454.rs", -"ui/test-attrs/issue-109816.rs", -"ui/test-attrs/issue-12997-1.rs", -"ui/test-attrs/issue-12997-2.rs", -"ui/test-attrs/issue-16597-empty.rs", -"ui/test-attrs/issue-16597.rs", -"ui/test-attrs/issue-20823.rs", -"ui/test-attrs/issue-34932.rs", -"ui/test-attrs/issue-36768.rs", -"ui/test-attrs/issue-52557.rs", -"ui/test-attrs/issue-53675-a-test-called-panic.rs", -"ui/threads-sendsync/issue-24313.rs", -"ui/threads-sendsync/issue-29488.rs", -"ui/threads-sendsync/issue-43733-2.rs", -"ui/threads-sendsync/issue-43733.rs", -"ui/threads-sendsync/issue-4446.rs", -"ui/threads-sendsync/issue-4448.rs", -"ui/threads-sendsync/issue-8827.rs", -"ui/threads-sendsync/issue-9396.rs", -"ui/trait-bounds/issue-119530-sugg-from-fn.rs", -"ui/trait-bounds/issue-75961.rs", -"ui/trait-bounds/issue-82038.rs", -"ui/trait-bounds/issue-93008.rs", -"ui/trait-bounds/issue-94680.rs", -"ui/trait-bounds/issue-94999.rs", -"ui/trait-bounds/issue-95640.rs", -"ui/traits/alias/issue-107747-do-not-assemble-supertraits.rs", -"ui/traits/alias/issue-108072-unmet-trait-alias-bound.rs", -"ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs", -"ui/traits/alias/issue-60021-assoc-method-resolve.rs", -"ui/traits/alias/issue-60755.rs", -"ui/traits/alias/issue-72415-assoc-const-resolve.rs", -"ui/traits/alias/issue-75983.rs", -"ui/traits/alias/issue-83613.rs", -"ui/traits/associated_type_bound/issue-51446.rs", -"ui/traits/auxiliary/issue_89119_intercrate_caching.rs", -"ui/traits/issue-103563.rs", -"ui/traits/issue-104322.rs", -"ui/traits/issue-105231.rs", -"ui/traits/issue-106072.rs", -"ui/traits/issue-117794.rs", -"ui/traits/issue-15155.rs", -"ui/traits/issue-18400.rs", -"ui/traits/issue-18412.rs", -"ui/traits/issue-20692.rs", -"ui/traits/issue-21837.rs", -"ui/traits/issue-22019.rs", -"ui/traits/issue-22110.rs", -"ui/traits/issue-22384.rs", -"ui/traits/issue-22655.rs", -"ui/traits/issue-23003-overflow.rs", -"ui/traits/issue-23003.rs", -"ui/traits/issue-23825.rs", -"ui/traits/issue-24010.rs", -"ui/traits/issue-26339.rs", -"ui/traits/issue-28576.rs", -"ui/traits/issue-32963.rs", -"ui/traits/issue-33096.rs", -"ui/traits/issue-33140-hack-boundaries.rs", -"ui/traits/issue-33140.rs", -"ui/traits/issue-33187.rs", -"ui/traits/issue-35869.rs", -"ui/traits/issue-3683.rs", -"ui/traits/issue-38033.rs", -"ui/traits/issue-38404.rs", -"ui/traits/issue-38604.rs", -"ui/traits/issue-3973.rs", -"ui/traits/issue-3979-generics.rs", -"ui/traits/issue-40085.rs", -"ui/traits/issue-4107.rs", -"ui/traits/issue-43132.rs", -"ui/traits/issue-43784-supertrait.rs", -"ui/traits/issue-5008-borrowed-traitobject-method-call.rs", -"ui/traits/issue-50480.rs", -"ui/traits/issue-52893.rs", -"ui/traits/issue-56202.rs", -"ui/traits/issue-56488.rs", -"ui/traits/issue-58344.rs", -"ui/traits/issue-59029-1.rs", -"ui/traits/issue-59029-2.rs", -"ui/traits/issue-6128.rs", -"ui/traits/issue-6334.rs", -"ui/traits/issue-65284-suggest-generic-trait-bound.rs", -"ui/traits/issue-65673.rs", -"ui/traits/issue-66768.rs", -"ui/traits/issue-68295.rs", -"ui/traits/issue-7013.rs", -"ui/traits/issue-70944.rs", -"ui/traits/issue-71036.rs", -"ui/traits/issue-71136.rs", -"ui/traits/issue-72410.rs", -"ui/traits/issue-72455.rs", -"ui/traits/issue-75627.rs", -"ui/traits/issue-77982.rs", -"ui/traits/issue-78372.rs", -"ui/traits/issue-78632.rs", -"ui/traits/issue-79458.rs", -"ui/traits/issue-8153.rs", -"ui/traits/issue-82830.rs", -"ui/traits/issue-83538-tainted-cache-after-cycle.rs", -"ui/traits/issue-84399-bad-fresh-caching.rs", -"ui/traits/issue-85360-eval-obligation-ice.rs", -"ui/traits/issue-85735.rs", -"ui/traits/issue-87558.rs", -"ui/traits/issue-89119.rs", -"ui/traits/issue-90195-2.rs", -"ui/traits/issue-90195.rs", -"ui/traits/issue-90662-projection-caching.rs", -"ui/traits/issue-91594.rs", -"ui/traits/issue-91949-hangs-on-recursion.rs", -"ui/traits/issue-92292.rs", -"ui/traits/issue-9394-inherited-calls.rs", -"ui/traits/issue-95311.rs", -"ui/traits/issue-95898.rs", -"ui/traits/issue-96664.rs", -"ui/traits/issue-96665.rs", -"ui/traits/issue-97576.rs", -"ui/traits/issue-97695-double-trivial-bound.rs", -"ui/traits/issue-99875.rs", -"ui/traits/next-solver/coherence/issue-102048.rs", -"ui/traits/next-solver/issue-118950-root-region.rs", -"ui/traits/object/issue-33140-traitobject-crate.rs", -"ui/traits/object/issue-44454-1.rs", -"ui/traits/object/issue-44454-2.rs", -"ui/traits/object/issue-44454-3.rs", -"ui/traits/suggest-dereferences/issue-39029.rs", -"ui/traits/suggest-dereferences/issue-62530.rs", -"ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs", -"ui/traits/trait-upcasting/issue-11515.rs", -"ui/traits/vtable/issue-91807.rs", -"ui/traits/vtable/issue-97381.rs", -"ui/transmutability/arrays/issue-103783-array-length.rs", -"ui/transmutability/issue-101739-1.rs", -"ui/transmutability/issue-101739-2.rs", -"ui/transmutability/issue-110467.rs", -"ui/transmutability/issue-110892.rs", -"ui/trivial-bounds/issue-73021-impossible-inline.rs", -"ui/try-block/issue-45124.rs", -"ui/try-trait/issue-32709.rs", -"ui/type-alias-enum-variants/issue-57866.rs", -"ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs", -"ui/type-alias-enum-variants/issue-63151-dead-code-lint-fields-in-patterns.rs", -"ui/type-alias-impl-trait/issue-101750.rs", -"ui/type-alias-impl-trait/issue-104817.rs", -"ui/type-alias-impl-trait/issue-109054.rs", -"ui/type-alias-impl-trait/issue-52843-closure-constrain.rs", -"ui/type-alias-impl-trait/issue-52843.rs", -"ui/type-alias-impl-trait/issue-53092-2.rs", -"ui/type-alias-impl-trait/issue-53092.rs", -"ui/type-alias-impl-trait/issue-53096.rs", -"ui/type-alias-impl-trait/issue-53398-cyclic-types.rs", -"ui/type-alias-impl-trait/issue-53598.rs", -"ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs", -"ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs", -"ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs", -"ui/type-alias-impl-trait/issue-57611-trait-alias.rs", -"ui/type-alias-impl-trait/issue-57700.rs", -"ui/type-alias-impl-trait/issue-57807-associated-type.rs", -"ui/type-alias-impl-trait/issue-57961.rs", -"ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs", -"ui/type-alias-impl-trait/issue-58662-simplified.rs", -"ui/type-alias-impl-trait/issue-58887.rs", -"ui/type-alias-impl-trait/issue-58951-2.rs", -"ui/type-alias-impl-trait/issue-58951.rs", -"ui/type-alias-impl-trait/issue-60371.rs", -"ui/type-alias-impl-trait/issue-60407.rs", -"ui/type-alias-impl-trait/issue-60564-working.rs", -"ui/type-alias-impl-trait/issue-60564.rs", -"ui/type-alias-impl-trait/issue-60662.rs", -"ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs", -"ui/type-alias-impl-trait/issue-63263-closure-return.rs", -"ui/type-alias-impl-trait/issue-63279.rs", -"ui/type-alias-impl-trait/issue-63355.rs", -"ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs", -"ui/type-alias-impl-trait/issue-65384.rs", -"ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs", -"ui/type-alias-impl-trait/issue-65918.rs", -"ui/type-alias-impl-trait/issue-66580-closure-coherence.rs", -"ui/type-alias-impl-trait/issue-67844-nested-opaque.rs", -"ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs", -"ui/type-alias-impl-trait/issue-68368-non-defining-use.rs", -"ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs", -"ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs", -"ui/type-alias-impl-trait/issue-69323.rs", -"ui/type-alias-impl-trait/issue-70121.rs", -"ui/type-alias-impl-trait/issue-72793.rs", -"ui/type-alias-impl-trait/issue-74244.rs", -"ui/type-alias-impl-trait/issue-74280.rs", -"ui/type-alias-impl-trait/issue-74761-2.rs", -"ui/type-alias-impl-trait/issue-74761.rs", -"ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs", -"ui/type-alias-impl-trait/issue-77179.rs", -"ui/type-alias-impl-trait/issue-78450.rs", -"ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs", -"ui/type-alias-impl-trait/issue-84660-unsoundness.rs", -"ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs", -"ui/type-alias-impl-trait/issue-89686.rs", -"ui/type-alias-impl-trait/issue-89952.rs", -"ui/type-alias-impl-trait/issue-90400-1.rs", -"ui/type-alias-impl-trait/issue-90400-2.rs", -"ui/type-alias-impl-trait/issue-93411.rs", -"ui/type-alias-impl-trait/issue-94429.rs", -"ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs", -"ui/type-alias-impl-trait/issue-96572-unconstrained.rs", -"ui/type-alias-impl-trait/issue-98604.rs", -"ui/type-alias-impl-trait/issue-98608.rs", -"ui/type-alias/issue-14933.rs", -"ui/type-alias/issue-37515.rs", -"ui/type-alias/issue-62263-self-in-atb.rs", -"ui/type-alias/issue-62305-self-assoc-ty.rs", -"ui/type-alias/issue-62364-self-ty-arg.rs", -"ui/type-inference/issue-113283-alllocator-trait-eq.rs", -"ui/type-inference/issue-30225.rs", -"ui/type/ascription/issue-34255-1.rs", -"ui/type/ascription/issue-47666.rs", -"ui/type/ascription/issue-54516.rs", -"ui/type/ascription/issue-60933.rs", -"ui/type/issue-100584.rs", -"ui/type/issue-101866.rs", -"ui/type/issue-102598.rs", -"ui/type/issue-103271.rs", -"ui/type/issue-58355.rs", -"ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs", -"ui/type/issue-91268.rs", -"ui/type/issue-94187-verbose-type-name.rs", -"ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs", -"ui/type/type-check/issue-22897.rs", -"ui/type/type-check/issue-40294.rs", -"ui/type/type-check/issue-41314.rs", -"ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs", -"ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs", -"ui/typeck/auxiliary/issue-29181.rs", -"ui/typeck/auxiliary/issue-36708.rs", -"ui/typeck/auxiliary/issue-81943-lib.rs", -"ui/typeck/issue-100164.rs", -"ui/typeck/issue-100246.rs", -"ui/typeck/issue-100285.rs", -"ui/typeck/issue-103899.rs", -"ui/typeck/issue-10401.rs", -"ui/typeck/issue-104510-ice.rs", -"ui/typeck/issue-104513-ice.rs", -"ui/typeck/issue-104582.rs", -"ui/typeck/issue-105946.rs", -"ui/typeck/issue-106929.rs", -"ui/typeck/issue-107087.rs", -"ui/typeck/issue-107775.rs", -"ui/typeck/issue-10969.rs", -"ui/typeck/issue-110017-format-into-help-deletes-macro.rs", -"ui/typeck/issue-110052.rs", -"ui/typeck/issue-112007-leaked-writeln-macro-internals.rs", -"ui/typeck/issue-112252-ptr-arithmetics-help.rs", -"ui/typeck/issue-112385-while-assign-lhs-place-expr-ice.rs", -"ui/typeck/issue-114423-ice-regression-in-suggestion.rs", -"ui/typeck/issue-114529-illegal-break-with-value.rs", -"ui/typeck/issue-116473-ice-wrong-span-variant-args.rs", -"ui/typeck/issue-116864.rs", -"ui/typeck/issue-120856.rs", -"ui/typeck/issue-13853-2.rs", -"ui/typeck/issue-13853-5.rs", -"ui/typeck/issue-13853.rs", -"ui/typeck/issue-16338.rs", -"ui/typeck/issue-1871.rs", -"ui/typeck/issue-18937-1.rs", -"ui/typeck/issue-18937.rs", -"ui/typeck/issue-2063-resource.rs", -"ui/typeck/issue-2063.rs", -"ui/typeck/issue-22375.rs", -"ui/typeck/issue-29124.rs", -"ui/typeck/issue-29181.rs", -"ui/typeck/issue-31173.rs", -"ui/typeck/issue-33575.rs", -"ui/typeck/issue-36708.rs", -"ui/typeck/issue-43189.rs", -"ui/typeck/issue-46112.rs", -"ui/typeck/issue-50687-ice-on-borrow.rs", -"ui/typeck/issue-52082-type-param-shadows-existing-type.rs", -"ui/typeck/issue-53712.rs", -"ui/typeck/issue-55810-must-typeck-match-pats-before-guards.rs", -"ui/typeck/issue-57404.rs", -"ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs", -"ui/typeck/issue-61711-once-caused-rustc-inf-loop.rs", -"ui/typeck/issue-65611.rs", -"ui/typeck/issue-67971.rs", -"ui/typeck/issue-68590-reborrow-through-derefmut.rs", -"ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs", -"ui/typeck/issue-72225-call-fnmut-through-derefmut.rs", -"ui/typeck/issue-73592-borrow_mut-through-deref.rs", -"ui/typeck/issue-74086.rs", -"ui/typeck/issue-74933.rs", -"ui/typeck/issue-75883.rs", -"ui/typeck/issue-75889.rs", -"ui/typeck/issue-7813.rs", -"ui/typeck/issue-79040.rs", -"ui/typeck/issue-80207-unsized-return.rs", -"ui/typeck/issue-80779.rs", -"ui/typeck/issue-81293.rs", -"ui/typeck/issue-81885.rs", -"ui/typeck/issue-81943.rs", -"ui/typeck/issue-82772.rs", -"ui/typeck/issue-83621-placeholder-static-in-extern.rs", -"ui/typeck/issue-83693.rs", -"ui/typeck/issue-84160.rs", -"ui/typeck/issue-84768.rs", -"ui/typeck/issue-84831.rs", -"ui/typeck/issue-86721-return-expr-ice.rs", -"ui/typeck/issue-87771-ice-assign-assign-to-bool.rs", -"ui/typeck/issue-87872-missing-inaccessible-field-literal.rs", -"ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs", -"ui/typeck/issue-88609.rs", -"ui/typeck/issue-88643.rs", -"ui/typeck/issue-88803-call-expr-method.rs", -"ui/typeck/issue-88844.rs", -"ui/typeck/issue-89044-wrapped-expr-method.rs", -"ui/typeck/issue-89275.rs", -"ui/typeck/issue-89806.rs", -"ui/typeck/issue-89856.rs", -"ui/typeck/issue-89935.rs", -"ui/typeck/issue-90027-async-fn-return-suggestion.rs", -"ui/typeck/issue-90101.rs", -"ui/typeck/issue-90164.rs", -"ui/typeck/issue-90319.rs", -"ui/typeck/issue-90483-inaccessible-field-adjustment.rs", -"ui/typeck/issue-90804-incorrect-reference-suggestion.rs", -"ui/typeck/issue-91210-ptr-method.rs", -"ui/typeck/issue-91267.rs", -"ui/typeck/issue-91328.rs", -"ui/typeck/issue-91334.rs", -"ui/typeck/issue-91450-inner-ty-error.rs", -"ui/typeck/issue-91633.rs", -"ui/typeck/issue-92481.rs", -"ui/typeck/issue-93486.rs", -"ui/typeck/issue-96530.rs", -"ui/typeck/issue-96738.rs", -"ui/typeck/issue-98260.rs", -"ui/typeck/issue-98982.rs", -"ui/typeof/issue-100183.rs", -"ui/typeof/issue-29184.rs", -"ui/typeof/issue-42060.rs", -"ui/unboxed-closures/issue-18652.rs", -"ui/unboxed-closures/issue-18661.rs", -"ui/unboxed-closures/issue-30906.rs", -"ui/unboxed-closures/issue-53448.rs", -"ui/underscore-imports/issue-110164.rs", -"ui/uniform-paths/auxiliary/issue-53691.rs", -"ui/uniform-paths/issue-53691.rs", -"ui/uninhabited/issue-107505.rs", -"ui/union/issue-41073.rs", -"ui/union/issue-81199.rs", -"ui/union/issue-99375.rs", -"ui/unsafe/auxiliary/issue-106126.rs", -"ui/unsafe/issue-106126-good-path-bug.rs", -"ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs", -"ui/unsafe/issue-3080.rs", -"ui/unsafe/issue-45087-unreachable-unsafe.rs", -"ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs", -"ui/unsafe/issue-47412.rs", -"ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs", -"ui/unsafe/issue-87414-query-cycle.rs", -"ui/unsized-locals/issue-30276-feature-flagged.rs", -"ui/unsized-locals/issue-30276.rs", -"ui/unsized-locals/issue-50940-with-feature.rs", -"ui/unsized-locals/issue-50940.rs", -"ui/unsized-locals/issue-67981.rs", -"ui/unsized/issue-115203.rs", -"ui/unsized/issue-115809.rs", -"ui/unsized/issue-30355.rs", -"ui/unsized/issue-40231-1.rs", -"ui/unsized/issue-40231-2.rs", -"ui/unsized/issue-71659.rs", -"ui/unsized/issue-75707.rs", -"ui/unsized/issue-75899-but-gats.rs", -"ui/unsized/issue-75899.rs", -"ui/unsized/issue-91801.rs", -"ui/unsized/issue-91803.rs", -"ui/unsized/issue-97732.rs", -"ui/use/issue-18986.rs", -"ui/use/issue-60976-extern-use-primitive-type.rs", -"ui/wf/issue-103573.rs", -"ui/wf/issue-110157.rs", -"ui/wf/issue-48638.rs", -"ui/wf/issue-87495.rs", -"ui/wf/issue-95665.rs", -"ui/wf/issue-96810.rs", -"ui/where-clauses/issue-50825-1.rs", -"ui/where-clauses/issue-50825.rs", -] +ui/abi/issue-28676.rs +ui/abi/issues/issue-22565-rust-call.rs +ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs +ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs +ui/argument-suggestions/issue-100154.rs +ui/argument-suggestions/issue-100478.rs +ui/argument-suggestions/issue-101097.rs +ui/argument-suggestions/issue-109425.rs +ui/argument-suggestions/issue-109831.rs +ui/argument-suggestions/issue-112507.rs +ui/argument-suggestions/issue-96638.rs +ui/argument-suggestions/issue-97197.rs +ui/argument-suggestions/issue-97484.rs +ui/argument-suggestions/issue-98894.rs +ui/argument-suggestions/issue-98897.rs +ui/argument-suggestions/issue-99482.rs +ui/array-slice-vec/issue-15730.rs +ui/array-slice-vec/issue-18425.rs +ui/array-slice-vec/issue-69103-extra-binding-subslice.rs +ui/asm/issue-113788.rs +ui/asm/issue-72570.rs +ui/asm/issue-85247.rs +ui/asm/issue-87802.rs +ui/asm/issue-89305.rs +ui/asm/issue-92378.rs +ui/asm/issue-97490.rs +ui/asm/issue-99071.rs +ui/asm/issue-99122-2.rs +ui/asm/issue-99122.rs +ui/asm/x86_64/issue-82869.rs +ui/asm/x86_64/issue-89875.rs +ui/asm/x86_64/issue-96797.rs +ui/associated-consts/issue-102335-const.rs +ui/associated-consts/issue-105330.rs +ui/associated-consts/issue-110933.rs +ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs +ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.rs +ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs +ui/associated-consts/issue-47814.rs +ui/associated-consts/issue-58022.rs +ui/associated-consts/issue-63496.rs +ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs +ui/associated-consts/issue-88599-ref-self.rs +ui/associated-consts/issue-93775.rs +ui/associated-consts/issue-93835.rs +ui/associated-inherent-types/issue-104260.rs +ui/associated-inherent-types/issue-109071.rs +ui/associated-inherent-types/issue-109299-1.rs +ui/associated-inherent-types/issue-109299.rs +ui/associated-inherent-types/issue-109768.rs +ui/associated-inherent-types/issue-109789.rs +ui/associated-inherent-types/issue-109790.rs +ui/associated-inherent-types/issue-111404-0.rs +ui/associated-inherent-types/issue-111404-1.rs +ui/associated-inherent-types/issue-111879-0.rs +ui/associated-inherent-types/issue-111879-1.rs +ui/associated-item/issue-105449.rs +ui/associated-item/issue-48027.rs +ui/associated-item/issue-87638.rs +ui/associated-type-bounds/issue-102335-ty.rs +ui/associated-type-bounds/issue-104916.rs +ui/associated-type-bounds/issue-61752.rs +ui/associated-type-bounds/issue-70292.rs +ui/associated-type-bounds/issue-71443-1.rs +ui/associated-type-bounds/issue-71443-2.rs +ui/associated-type-bounds/issue-73818.rs +ui/associated-type-bounds/issue-79949.rs +ui/associated-type-bounds/issue-81193.rs +ui/associated-type-bounds/issue-83017.rs +ui/associated-type-bounds/issue-99828.rs +ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs +ui/associated-types/issue-18655.rs +ui/associated-types/issue-19081.rs +ui/associated-types/issue-19883.rs +ui/associated-types/issue-20005.rs +ui/associated-types/issue-20825-2.rs +ui/associated-types/issue-20825.rs +ui/associated-types/issue-21363.rs +ui/associated-types/issue-21726.rs +ui/associated-types/issue-22037.rs +ui/associated-types/issue-22066.rs +ui/associated-types/issue-22560.rs +ui/associated-types/issue-22828.rs +ui/associated-types/issue-23208.rs +ui/associated-types/issue-23595-1.rs +ui/associated-types/issue-23595-2.rs +ui/associated-types/issue-24159.rs +ui/associated-types/issue-24204.rs +ui/associated-types/issue-24338.rs +ui/associated-types/issue-25339.rs +ui/associated-types/issue-25700-1.rs +ui/associated-types/issue-25700-2.rs +ui/associated-types/issue-25700.rs +ui/associated-types/issue-26262.rs +ui/associated-types/issue-26681.rs +ui/associated-types/issue-27675-unchecked-bounds.rs +ui/associated-types/issue-27901.rs +ui/associated-types/issue-28871.rs +ui/associated-types/issue-31597.rs +ui/associated-types/issue-32323.rs +ui/associated-types/issue-32350.rs +ui/associated-types/issue-36499.rs +ui/associated-types/issue-37808.rs +ui/associated-types/issue-37883.rs +ui/associated-types/issue-38821.rs +ui/associated-types/issue-38917.rs +ui/associated-types/issue-39532.rs +ui/associated-types/issue-40093.rs +ui/associated-types/issue-41868.rs +ui/associated-types/issue-43475.rs +ui/associated-types/issue-43784-associated-type.rs +ui/associated-types/issue-43924.rs +ui/associated-types/issue-44153.rs +ui/associated-types/issue-47139-1.rs +ui/associated-types/issue-47139-2.rs +ui/associated-types/issue-47385.rs +ui/associated-types/issue-47814.rs +ui/associated-types/issue-48010.rs +ui/associated-types/issue-48551.rs +ui/associated-types/issue-50301.rs +ui/associated-types/issue-54108.rs +ui/associated-types/issue-54182-1.rs +ui/associated-types/issue-54182-2.rs +ui/associated-types/issue-54467.rs +ui/associated-types/issue-55846.rs +ui/associated-types/issue-59324.rs +ui/associated-types/issue-62200.rs +ui/associated-types/issue-63591.rs +ui/associated-types/issue-63593.rs +ui/associated-types/issue-64848.rs +ui/associated-types/issue-64855-2.rs +ui/associated-types/issue-64855.rs +ui/associated-types/issue-65774-1.rs +ui/associated-types/issue-65774-2.rs +ui/associated-types/issue-65934.rs +ui/associated-types/issue-67684.rs +ui/associated-types/issue-69398.rs +ui/associated-types/issue-71113.rs +ui/associated-types/issue-72806.rs +ui/associated-types/issue-76179.rs +ui/associated-types/issue-82079.rs +ui/associated-types/issue-85103-layout-debug.rs +ui/associated-types/issue-87261.rs +ui/associated-types/issue-88856.rs +ui/associated-types/issue-91069.rs +ui/associated-types/issue-91231.rs +ui/associated-types/issue-91234.rs +ui/async-await/auxiliary/issue-107036.rs +ui/async-await/auxiliary/issue-72470-lib.rs +ui/async-await/in-trait/issue-102138.rs +ui/async-await/in-trait/issue-102219.rs +ui/async-await/in-trait/issue-102310.rs +ui/async-await/in-trait/issue-104678.rs +ui/async-await/issue-101715.rs +ui/async-await/issue-105501.rs +ui/async-await/issue-107036.rs +ui/async-await/issue-108572.rs +ui/async-await/issue-54239-private-type-triggers-lint.rs +ui/async-await/issue-60709.rs +ui/async-await/issue-61076.rs +ui/async-await/issue-61452.rs +ui/async-await/issue-61793.rs +ui/async-await/issue-62658.rs +ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs +ui/async-await/issue-63832-await-short-temporary-lifetime.rs +ui/async-await/issue-64130-1-sync.rs +ui/async-await/issue-64130-2-send.rs +ui/async-await/issue-64130-3-other.rs +ui/async-await/issue-64130-4-async-move.rs +ui/async-await/issue-64130-non-send-future-diags.rs +ui/async-await/issue-64391.rs +ui/async-await/issue-65634-raw-ident-suggestion.rs +ui/async-await/issue-66312.rs +ui/async-await/issue-66387-if-without-else.rs +ui/async-await/issue-67252-unnamed-future.rs +ui/async-await/issue-67651.rs +ui/async-await/issue-67765-async-diagnostic.rs +ui/async-await/issue-68112.rs +ui/async-await/issue-68523-start.rs +ui/async-await/issue-68523.rs +ui/async-await/issue-69446-fnmut-capture.rs +ui/async-await/issue-70594.rs +ui/async-await/issue-70818.rs +ui/async-await/issue-70935-complex-spans.rs +ui/async-await/issue-71137.rs +ui/async-await/issue-72442.rs +ui/async-await/issue-72470-llvm-dominate.rs +ui/async-await/issue-72590-type-error-sized.rs +ui/async-await/issue-73050.rs +ui/async-await/issue-73137.rs +ui/async-await/issue-73541-1.rs +ui/async-await/issue-73541-2.rs +ui/async-await/issue-73541-3.rs +ui/async-await/issue-73541.rs +ui/async-await/issue-73741-type-err.rs +ui/async-await/issue-74047.rs +ui/async-await/issue-74072-lifetime-name-annotations.rs +ui/async-await/issue-74497-lifetime-in-opaque.rs +ui/async-await/issue-75785-confusing-named-region.rs +ui/async-await/issue-76547.rs +ui/async-await/issue-77993-2.rs +ui/async-await/issue-78115.rs +ui/async-await/issue-84841.rs +ui/async-await/issue-86507.rs +ui/async-await/issue-93197.rs +ui/async-await/issue-93648.rs +ui/async-await/issue-98634.rs +ui/async-await/issues/auxiliary/issue-60674.rs +ui/async-await/issues/auxiliary/issue_67893.rs +ui/async-await/issues/issue-102206.rs +ui/async-await/issues/issue-107280.rs +ui/async-await/issues/issue-112225-1.rs +ui/async-await/issues/issue-112225-2.rs +ui/async-await/issues/issue-51719.rs +ui/async-await/issues/issue-51751.rs +ui/async-await/issues/issue-53249.rs +ui/async-await/issues/issue-54752-async-block.rs +ui/async-await/issues/issue-54974.rs +ui/async-await/issues/issue-55324.rs +ui/async-await/issues/issue-55809.rs +ui/async-await/issues/issue-58885.rs +ui/async-await/issues/issue-59001.rs +ui/async-await/issues/issue-59972.rs +ui/async-await/issues/issue-60518.rs +ui/async-await/issues/issue-60655-latebound-regions.rs +ui/async-await/issues/issue-60674.rs +ui/async-await/issues/issue-61187.rs +ui/async-await/issues/issue-61986.rs +ui/async-await/issues/issue-62009-1.rs +ui/async-await/issues/issue-62009-2.rs +ui/async-await/issues/issue-62097.rs +ui/async-await/issues/issue-62517-1.rs +ui/async-await/issues/issue-62517-2.rs +ui/async-await/issues/issue-63388-1.rs +ui/async-await/issues/issue-63388-2.rs +ui/async-await/issues/issue-63388-3.rs +ui/async-await/issues/issue-63388-4.rs +ui/async-await/issues/issue-64391-2.rs +ui/async-await/issues/issue-64433.rs +ui/async-await/issues/issue-64477-2.rs +ui/async-await/issues/issue-64477.rs +ui/async-await/issues/issue-64964.rs +ui/async-await/issues/issue-65159.rs +ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs +ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs +ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs +ui/async-await/issues/issue-65436-raw-ptr-not-send.rs +ui/async-await/issues/issue-66695-static-refs.rs +ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs +ui/async-await/issues/issue-67611-static-mut-refs.rs +ui/async-await/issues/issue-67893.rs +ui/async-await/issues/issue-69307-nested.rs +ui/async-await/issues/issue-69307.rs +ui/async-await/issues/issue-72312.rs +ui/async-await/issues/issue-78600.rs +ui/async-await/issues/issue-78654.rs +ui/async-await/issues/issue-78938-async-block.rs +ui/async-await/issues/issue-95307.rs +ui/async-await/return-type-notation/issue-110963-early.rs +ui/async-await/return-type-notation/issue-110963-late.rs +ui/async-await/track-caller/issue-105134.rs +ui/attributes/issue-100631.rs +ui/attributes/issue-105594-invalid-attr-validation.rs +ui/attributes/issue-115264-expr-field.rs +ui/attributes/issue-115264-pat-field.rs +ui/attributes/issue-40962.rs +ui/attributes/issue-90873.rs +ui/auto-traits/issue-117789.rs +ui/auto-traits/issue-23080-2.rs +ui/auto-traits/issue-23080.rs +ui/auto-traits/issue-83857-ub.rs +ui/auto-traits/issue-84075.rs +ui/auxiliary/issue-13560-1.rs +ui/auxiliary/issue-13560-2.rs +ui/auxiliary/issue-13560-3.rs +ui/auxiliary/issue-16822.rs +ui/auxiliary/issue-18502.rs +ui/auxiliary/issue-24106.rs +ui/auxiliary/issue-76387.rs +ui/bench/issue-32062.rs +ui/binding/issue-53114-borrow-checks.rs +ui/binding/issue-53114-safety-checks.rs +ui/binop/issue-25916.rs +ui/binop/issue-28837.rs +ui/binop/issue-3820.rs +ui/binop/issue-62375.rs +ui/binop/issue-77910-1.rs +ui/binop/issue-77910-2.rs +ui/binop/issue-93927.rs +ui/block-result/issue-11714.rs +ui/block-result/issue-13428.rs +ui/block-result/issue-13624.rs +ui/block-result/issue-20862.rs +ui/block-result/issue-22645.rs +ui/block-result/issue-3563.rs +ui/block-result/issue-5500.rs +ui/borrowck/issue-101119.rs +ui/borrowck/issue-102209.rs +ui/borrowck/issue-103095.rs +ui/borrowck/issue-103250.rs +ui/borrowck/issue-103624.rs +ui/borrowck/issue-104639-lifetime-order.rs +ui/borrowck/issue-10876.rs +ui/borrowck/issue-109271-pass-self-into-closure.rs +ui/borrowck/issue-111554.rs +ui/borrowck/issue-114374-invalid-help-fmt-args.rs +ui/borrowck/issue-11493.rs +ui/borrowck/issue-115259-suggest-iter-mut.rs +ui/borrowck/issue-119915-bad-clone-suggestion.rs +ui/borrowck/issue-17263.rs +ui/borrowck/issue-17545.rs +ui/borrowck/issue-17718-static-move.rs +ui/borrowck/issue-20801.rs +ui/borrowck/issue-23338-params-outlive-temps-of-body.rs +ui/borrowck/issue-24267-flow-exit.rs +ui/borrowck/issue-25793.rs +ui/borrowck/issue-28934.rs +ui/borrowck/issue-29166.rs +ui/borrowck/issue-31287-drop-in-guard.rs +ui/borrowck/issue-33819.rs +ui/borrowck/issue-36082.rs +ui/borrowck/issue-41962.rs +ui/borrowck/issue-42344.rs +ui/borrowck/issue-45199.rs +ui/borrowck/issue-45983.rs +ui/borrowck/issue-46095.rs +ui/borrowck/issue-46471.rs +ui/borrowck/issue-47215-ice-from-drop-elab.rs +ui/borrowck/issue-47646.rs +ui/borrowck/issue-51117.rs +ui/borrowck/issue-51301.rs +ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs +ui/borrowck/issue-51415.rs +ui/borrowck/issue-52713-bug.rs +ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs +ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs +ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs +ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs +ui/borrowck/issue-54499-field-mutation-of-moved-out.rs +ui/borrowck/issue-54499-field-mutation-of-never-init.rs +ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs +ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs +ui/borrowck/issue-58776-borrowck-scans-children.rs +ui/borrowck/issue-62007-assign-box.rs +ui/borrowck/issue-62007-assign-field.rs +ui/borrowck/issue-62107-match-arm-scopes.rs +ui/borrowck/issue-62387-suggest-iter-mut-2.rs +ui/borrowck/issue-62387-suggest-iter-mut.rs +ui/borrowck/issue-64453.rs +ui/borrowck/issue-69789-iterator-mut-suggestion.rs +ui/borrowck/issue-70919-drop-in-loop.rs +ui/borrowck/issue-71546.rs +ui/borrowck/issue-7573.rs +ui/borrowck/issue-80772.rs +ui/borrowck/issue-81365-1.rs +ui/borrowck/issue-81365-10.rs +ui/borrowck/issue-81365-11.rs +ui/borrowck/issue-81365-2.rs +ui/borrowck/issue-81365-3.rs +ui/borrowck/issue-81365-4.rs +ui/borrowck/issue-81365-5.rs +ui/borrowck/issue-81365-6.rs +ui/borrowck/issue-81365-7.rs +ui/borrowck/issue-81365-8.rs +ui/borrowck/issue-81365-9.rs +ui/borrowck/issue-81899.rs +ui/borrowck/issue-82032.rs +ui/borrowck/issue-82126-mismatched-subst-and-hir.rs +ui/borrowck/issue-82462.rs +ui/borrowck/issue-83309-ice-immut-in-for-loop.rs +ui/borrowck/issue-83760.rs +ui/borrowck/issue-83924.rs +ui/borrowck/issue-85581.rs +ui/borrowck/issue-85765-closure.rs +ui/borrowck/issue-85765.rs +ui/borrowck/issue-87456-point-to-closure.rs +ui/borrowck/issue-88434-minimal-example.rs +ui/borrowck/issue-88434-removal-index-should-be-less.rs +ui/borrowck/issue-91206.rs +ui/borrowck/issue-92015.rs +ui/borrowck/issue-92157.rs +ui/borrowck/issue-93078.rs +ui/borrowck/issue-93093.rs +ui/borrowck/issue-95079-missing-move-in-nested-closure.rs +ui/box/issue-82446.rs +ui/box/issue-95036.rs +ui/c-variadic/issue-32201.rs +ui/c-variadic/issue-86053-1.rs +ui/c-variadic/issue-86053-2.rs +ui/cast/issue-106883-is-empty.rs +ui/cast/issue-10991.rs +ui/cast/issue-17444.rs +ui/cast/issue-84213.rs +ui/cast/issue-85586.rs +ui/cast/issue-88621.rs +ui/cast/issue-89497.rs +ui/closure-expected-type/issue-24421.rs +ui/closure_context/issue-26046-fn-mut.rs +ui/closure_context/issue-26046-fn-once.rs +ui/closure_context/issue-42065.rs +ui/closures/2229_closure_analysis/issue-118144.rs +ui/closures/2229_closure_analysis/issue-87378.rs +ui/closures/2229_closure_analysis/issue-87987.rs +ui/closures/2229_closure_analysis/issue-88118-2.rs +ui/closures/2229_closure_analysis/issue-88476.rs +ui/closures/2229_closure_analysis/issue-89606.rs +ui/closures/2229_closure_analysis/issue-90465.rs +ui/closures/2229_closure_analysis/issue-92724-needsdrop-query-cycle.rs +ui/closures/2229_closure_analysis/issue_88118.rs +ui/closures/2229_closure_analysis/match/issue-87097.rs +ui/closures/2229_closure_analysis/match/issue-87426.rs +ui/closures/2229_closure_analysis/match/issue-87988.rs +ui/closures/2229_closure_analysis/match/issue-88331.rs +ui/closures/2229_closure_analysis/migrations/issue-78720.rs +ui/closures/2229_closure_analysis/migrations/issue-86753.rs +ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs +ui/closures/2229_closure_analysis/run_pass/issue-87378.rs +ui/closures/2229_closure_analysis/run_pass/issue-88372.rs +ui/closures/2229_closure_analysis/run_pass/issue-88431.rs +ui/closures/2229_closure_analysis/run_pass/issue-88476.rs +ui/closures/issue-101696.rs +ui/closures/issue-102089-multiple-opaque-cast.rs +ui/closures/issue-10398.rs +ui/closures/issue-10682.rs +ui/closures/issue-109188.rs +ui/closures/issue-111932.rs +ui/closures/issue-113087.rs +ui/closures/issue-11873.rs +ui/closures/issue-1460.rs +ui/closures/issue-23012-supertrait-signature-inference.rs +ui/closures/issue-25439.rs +ui/closures/issue-41366.rs +ui/closures/issue-42463.rs +ui/closures/issue-46742.rs +ui/closures/issue-48109.rs +ui/closures/issue-52437.rs +ui/closures/issue-67123.rs +ui/closures/issue-6801.rs +ui/closures/issue-68025.rs +ui/closures/issue-72408-nested-closures-exponential.rs +ui/closures/issue-78720.rs +ui/closures/issue-80313-mutable-borrow-in-closure.rs +ui/closures/issue-80313-mutable-borrow-in-move-closure.rs +ui/closures/issue-80313-mutation-in-closure.rs +ui/closures/issue-80313-mutation-in-move-closure.rs +ui/closures/issue-81700-mut-borrow.rs +ui/closures/issue-82438-mut-without-upvar.rs +ui/closures/issue-84044-drop-non-mut.rs +ui/closures/issue-84128.rs +ui/closures/issue-868.rs +ui/closures/issue-87461.rs +ui/closures/issue-87814-1.rs +ui/closures/issue-87814-2.rs +ui/closures/issue-90871.rs +ui/closures/issue-97607.rs +ui/closures/issue-99565.rs +ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs +ui/codegen/auxiliary/issue-97708-aux.rs +ui/codegen/issue-101585-128bit-repeat.rs +ui/codegen/issue-16602-1.rs +ui/codegen/issue-16602-2.rs +ui/codegen/issue-16602-3.rs +ui/codegen/issue-27859.rs +ui/codegen/issue-28950.rs +ui/codegen/issue-55976.rs +ui/codegen/issue-63787.rs +ui/codegen/issue-64401.rs +ui/codegen/issue-79865-llvm-miscompile.rs +ui/codegen/issue-82833-slice-miscompile.rs +ui/codegen/issue-82859-slice-miscompile.rs +ui/codegen/issue-88043-bb-does-not-have-terminator.rs +ui/codegen/issue-97708.rs +ui/codegen/issue-99551.rs +ui/codemap_tests/issue-11715.rs +ui/codemap_tests/issue-28308.rs +ui/coercion/auxiliary/issue-39823.rs +ui/coercion/issue-101066.rs +ui/coercion/issue-14589.rs +ui/coercion/issue-26905-rpass.rs +ui/coercion/issue-26905.rs +ui/coercion/issue-36007.rs +ui/coercion/issue-37655.rs +ui/coercion/issue-3794.rs +ui/coercion/issue-39823.rs +ui/coercion/issue-53475.rs +ui/coercion/issue-73886.rs +ui/coercion/issue-88097.rs +ui/coherence/issue-85026.rs +ui/coherence/issue-99663-2.rs +ui/coherence/issue-99663.rs +ui/command/issue-10626.rs +ui/compare-method/issue-90444.rs +ui/conditional-compilation/issue-34028.rs +ui/confuse-field-and-method/issue-18343.rs +ui/confuse-field-and-method/issue-2392.rs +ui/confuse-field-and-method/issue-32128.rs +ui/confuse-field-and-method/issue-33784.rs +ui/const-generics/generic_arg_infer/issue-91614.rs +ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs +ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs +ui/const-generics/generic_const_exprs/issue-100217.rs +ui/const-generics/generic_const_exprs/issue-100360.rs +ui/const-generics/generic_const_exprs/issue-102074.rs +ui/const-generics/generic_const_exprs/issue-102768.rs +ui/const-generics/generic_const_exprs/issue-105257.rs +ui/const-generics/generic_const_exprs/issue-105608.rs +ui/const-generics/generic_const_exprs/issue-109141.rs +ui/const-generics/generic_const_exprs/issue-62504.rs +ui/const-generics/generic_const_exprs/issue-69654.rs +ui/const-generics/generic_const_exprs/issue-72787.rs +ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.rs +ui/const-generics/generic_const_exprs/issue-73298.rs +ui/const-generics/generic_const_exprs/issue-73899.rs +ui/const-generics/generic_const_exprs/issue-74634.rs +ui/const-generics/generic_const_exprs/issue-74713.rs +ui/const-generics/generic_const_exprs/issue-76595.rs +ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs +ui/const-generics/generic_const_exprs/issue-80561-incorrect-param-env.rs +ui/const-generics/generic_const_exprs/issue-80742.rs +ui/const-generics/generic_const_exprs/issue-82268.rs +ui/const-generics/generic_const_exprs/issue-83765.rs +ui/const-generics/generic_const_exprs/issue-83972.rs +ui/const-generics/generic_const_exprs/issue-84408.rs +ui/const-generics/generic_const_exprs/issue-84669.rs +ui/const-generics/generic_const_exprs/issue-85848.rs +ui/const-generics/generic_const_exprs/issue-86710.rs +ui/const-generics/generic_const_exprs/issue-89851.rs +ui/const-generics/generic_const_exprs/issue-90847.rs +ui/const-generics/generic_const_exprs/issue-94287.rs +ui/const-generics/generic_const_exprs/issue-94293.rs +ui/const-generics/generic_const_exprs/issue-96699.rs +ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs +ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs +ui/const-generics/generic_const_exprs/issue-99647.rs +ui/const-generics/generic_const_exprs/issue-99705.rs +ui/const-generics/infer/issue-77092.rs +ui/const-generics/issue-102124.rs +ui/const-generics/issue-105689.rs +ui/const-generics/issue-106419-struct-with-multiple-const-params.rs +ui/const-generics/issue-112505-overflow.rs +ui/const-generics/issue-46511.rs +ui/const-generics/issue-66451.rs +ui/const-generics/issue-70408.rs +ui/const-generics/issue-80471.rs +ui/const-generics/issue-93647.rs +ui/const-generics/issue-97007.rs +ui/const-generics/issues/issue-100313.rs +ui/const-generics/issues/issue-105037.rs +ui/const-generics/issues/issue-105821.rs +ui/const-generics/issues/issue-56445-1.rs +ui/const-generics/issues/issue-56445-2.rs +ui/const-generics/issues/issue-56445-3.rs +ui/const-generics/issues/issue-60818-struct-constructors.rs +ui/const-generics/issues/issue-61336-1.rs +ui/const-generics/issues/issue-61336-2.rs +ui/const-generics/issues/issue-61336.rs +ui/const-generics/issues/issue-61422.rs +ui/const-generics/issues/issue-61432.rs +ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +ui/const-generics/issues/issue-62878.rs +ui/const-generics/issues/issue-63322-forbid-dyn.rs +ui/const-generics/issues/issue-64519.rs +ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs +ui/const-generics/issues/issue-66906.rs +ui/const-generics/issues/issue-67185-1.rs +ui/const-generics/issues/issue-67185-2.rs +ui/const-generics/issues/issue-67375.rs +ui/const-generics/issues/issue-67739.rs +ui/const-generics/issues/issue-67945-1.rs +ui/const-generics/issues/issue-67945-2.rs +ui/const-generics/issues/issue-67945-3.rs +ui/const-generics/issues/issue-67945-4.rs +ui/const-generics/issues/issue-68104-print-stack-overflow.rs +ui/const-generics/issues/issue-68366.rs +ui/const-generics/issues/issue-68596.rs +ui/const-generics/issues/issue-68615-adt.rs +ui/const-generics/issues/issue-68615-array.rs +ui/const-generics/issues/issue-69654-run-pass.rs +ui/const-generics/issues/issue-70125-1.rs +ui/const-generics/issues/issue-70125-2.rs +ui/const-generics/issues/issue-70167.rs +ui/const-generics/issues/issue-70180-1-stalled_on.rs +ui/const-generics/issues/issue-70180-2-stalled_on.rs +ui/const-generics/issues/issue-70225.rs +ui/const-generics/issues/issue-70273-assoc-fn.rs +ui/const-generics/issues/issue-71169.rs +ui/const-generics/issues/issue-71202.rs +ui/const-generics/issues/issue-71381.rs +ui/const-generics/issues/issue-71382.rs +ui/const-generics/issues/issue-71547.rs +ui/const-generics/issues/issue-71611.rs +ui/const-generics/issues/issue-71986.rs +ui/const-generics/issues/issue-72352.rs +ui/const-generics/issues/issue-72845.rs +ui/const-generics/issues/issue-73120.rs +ui/const-generics/issues/issue-73260.rs +ui/const-generics/issues/issue-73491.rs +ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs +ui/const-generics/issues/issue-74101.rs +ui/const-generics/issues/issue-74255.rs +ui/const-generics/issues/issue-74906.rs +ui/const-generics/issues/issue-74950.rs +ui/const-generics/issues/issue-75047.rs +ui/const-generics/issues/issue-75299.rs +ui/const-generics/issues/issue-76701-ty-param-in-const.rs +ui/const-generics/issues/issue-79674.rs +ui/const-generics/issues/issue-80062.rs +ui/const-generics/issues/issue-80375.rs +ui/const-generics/issues/issue-82956.rs +ui/const-generics/issues/issue-83249.rs +ui/const-generics/issues/issue-83288.rs +ui/const-generics/issues/issue-83466.rs +ui/const-generics/issues/issue-83765.rs +ui/const-generics/issues/issue-84659.rs +ui/const-generics/issues/issue-85031-2.rs +ui/const-generics/issues/issue-86033.rs +ui/const-generics/issues/issue-86530.rs +ui/const-generics/issues/issue-86535-2.rs +ui/const-generics/issues/issue-86535.rs +ui/const-generics/issues/issue-86820.rs +ui/const-generics/issues/issue-87076.rs +ui/const-generics/issues/issue-87470.rs +ui/const-generics/issues/issue-87493.rs +ui/const-generics/issues/issue-87964.rs +ui/const-generics/issues/issue-88119.rs +ui/const-generics/issues/issue-88468.rs +ui/const-generics/issues/issue-88997.rs +ui/const-generics/issues/issue-89146.rs +ui/const-generics/issues/issue-89304.rs +ui/const-generics/issues/issue-89320.rs +ui/const-generics/issues/issue-89334.rs +ui/const-generics/issues/issue-90318.rs +ui/const-generics/issues/issue-90364.rs +ui/const-generics/issues/issue-90455.rs +ui/const-generics/issues/issue-92186.rs +ui/const-generics/issues/issue-96654.rs +ui/const-generics/issues/issue-97278.rs +ui/const-generics/issues/issue-97634.rs +ui/const-generics/issues/issue-98629.rs +ui/const-generics/issues/issue-99641.rs +ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs +ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs +ui/const-generics/parser-error-recovery/issue-89013-type.rs +ui/const-generics/parser-error-recovery/issue-89013.rs +ui/const-generics/type-dependent/issue-61936.rs +ui/const-generics/type-dependent/issue-63695.rs +ui/const-generics/type-dependent/issue-67144-1.rs +ui/const-generics/type-dependent/issue-67144-2.rs +ui/const-generics/type-dependent/issue-69816.rs +ui/const-generics/type-dependent/issue-70217.rs +ui/const-generics/type-dependent/issue-70507.rs +ui/const-generics/type-dependent/issue-70586.rs +ui/const-generics/type-dependent/issue-71348.rs +ui/const-generics/type-dependent/issue-71382.rs +ui/const-generics/type-dependent/issue-71805.rs +ui/const-generics/type-dependent/issue-73730.rs +ui/const_prop/issue-102553.rs +ui/const_prop/issue-86351.rs +ui/consts/auxiliary/issue-17718-aux.rs +ui/consts/auxiliary/issue-63226.rs +ui/consts/const-eval/issue-100878.rs +ui/consts/const-eval/issue-104390.rs +ui/consts/const-eval/issue-114994-fail.rs +ui/consts/const-eval/issue-114994.rs +ui/consts/const-eval/issue-43197.rs +ui/consts/const-eval/issue-44578.rs +ui/consts/const-eval/issue-47971.rs +ui/consts/const-eval/issue-49296.rs +ui/consts/const-eval/issue-50706.rs +ui/consts/const-eval/issue-50814-2.rs +ui/consts/const-eval/issue-50814.rs +ui/consts/const-eval/issue-51300.rs +ui/consts/const-eval/issue-52475.rs +ui/consts/const-eval/issue-53157.rs +ui/consts/const-eval/issue-53401.rs +ui/consts/const-eval/issue-55541.rs +ui/consts/const-eval/issue-64908.rs +ui/consts/const-eval/issue-64970.rs +ui/consts/const-eval/issue-65394.rs +ui/consts/const-eval/issue-70723.rs +ui/consts/const-eval/issue-70804-fn-subtyping.rs +ui/consts/const-eval/issue-84957-const-str-as-bytes.rs +ui/consts/const-eval/issue-85155.rs +ui/consts/const-eval/issue-85907.rs +ui/consts/const-eval/issue-91827-extern-types-field-offset.rs +ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs +ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs +ui/consts/const-mut-refs/issue-76510.rs +ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.rs +ui/consts/const_in_pattern/issue-44333.rs +ui/consts/const_in_pattern/issue-53708.rs +ui/consts/const_in_pattern/issue-62614.rs +ui/consts/const_in_pattern/issue-65466.rs +ui/consts/const_in_pattern/issue-73431.rs +ui/consts/control-flow/issue-46843.rs +ui/consts/control-flow/issue-50577.rs +ui/consts/extra-const-ub/issue-100771.rs +ui/consts/extra-const-ub/issue-101034.rs +ui/consts/issue-102117.rs +ui/consts/issue-103790.rs +ui/consts/issue-104155.rs +ui/consts/issue-104396.rs +ui/consts/issue-104609.rs +ui/consts/issue-104768.rs +ui/consts/issue-105536-const-val-roundtrip-ptr-eq.rs +ui/consts/issue-116186.rs +ui/consts/issue-13837.rs +ui/consts/issue-13902.rs +ui/consts/issue-16538.rs +ui/consts/issue-17074.rs +ui/consts/issue-17458.rs +ui/consts/issue-17718-borrow-interior.rs +ui/consts/issue-17718-const-bad-values.rs +ui/consts/issue-17718-const-borrow.rs +ui/consts/issue-17718-constants-not-static.rs +ui/consts/issue-17718-references.rs +ui/consts/issue-17718.rs +ui/consts/issue-17756.rs +ui/consts/issue-18294.rs +ui/consts/issue-19244.rs +ui/consts/issue-21562.rs +ui/consts/issue-21721.rs +ui/consts/issue-23833.rs +ui/consts/issue-23968-const-not-overflow.rs +ui/consts/issue-25826.rs +ui/consts/issue-27890.rs +ui/consts/issue-28113.rs +ui/consts/issue-28822.rs +ui/consts/issue-29798.rs +ui/consts/issue-29914-2.rs +ui/consts/issue-29914-3.rs +ui/consts/issue-29914.rs +ui/consts/issue-29927-1.rs +ui/consts/issue-29927.rs +ui/consts/issue-32829-2.rs +ui/consts/issue-32829.rs +ui/consts/issue-33537.rs +ui/consts/issue-33903.rs +ui/consts/issue-3521.rs +ui/consts/issue-36163.rs +ui/consts/issue-37222.rs +ui/consts/issue-37550-1.rs +ui/consts/issue-37550.rs +ui/consts/issue-37991.rs +ui/consts/issue-39161-bogus-error.rs +ui/consts/issue-39974.rs +ui/consts/issue-43105.rs +ui/consts/issue-44255.rs +ui/consts/issue-44415.rs +ui/consts/issue-46553.rs +ui/consts/issue-47789.rs +ui/consts/issue-50439.rs +ui/consts/issue-52023-array-size-pointer-cast.rs +ui/consts/issue-52060.rs +ui/consts/issue-54224.rs +ui/consts/issue-54348.rs +ui/consts/issue-54387.rs +ui/consts/issue-54582.rs +ui/consts/issue-54954.rs +ui/consts/issue-56164.rs +ui/consts/issue-58435-ice-with-assoc-const.rs +ui/consts/issue-62045.rs +ui/consts/issue-63226.rs +ui/consts/issue-63952.rs +ui/consts/issue-64059.rs +ui/consts/issue-64506.rs +ui/consts/issue-64662.rs +ui/consts/issue-65348.rs +ui/consts/issue-66342.rs +ui/consts/issue-66345.rs +ui/consts/issue-66397.rs +ui/consts/issue-66693-panic-in-array-len.rs +ui/consts/issue-66693.rs +ui/consts/issue-66787.rs +ui/consts/issue-67529.rs +ui/consts/issue-67640.rs +ui/consts/issue-67641.rs +ui/consts/issue-67696-const-prop-ice.rs +ui/consts/issue-67862.rs +ui/consts/issue-68264-overflow.rs +ui/consts/issue-68542-closure-in-array-len.rs +ui/consts/issue-68684.rs +ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs +ui/consts/issue-69310-array-size-lit-wrong-ty.rs +ui/consts/issue-69312.rs +ui/consts/issue-69488.rs +ui/consts/issue-69532.rs +ui/consts/issue-6991.rs +ui/consts/issue-70773-mir-typeck-lt-norm.rs +ui/consts/issue-70942-trait-vs-impl-mismatch.rs +ui/consts/issue-73976-monomorphic.rs +ui/consts/issue-73976-polymorphic.rs +ui/consts/issue-76064.rs +ui/consts/issue-77062-large-zst-array.rs +ui/consts/issue-78655.rs +ui/consts/issue-79137-monomorphic.rs +ui/consts/issue-79137-toogeneric.rs +ui/consts/issue-79152-const-array-index.rs +ui/consts/issue-79690.rs +ui/consts/issue-87046.rs +ui/consts/issue-88071.rs +ui/consts/issue-88649.rs +ui/consts/issue-89088.rs +ui/consts/issue-90762.rs +ui/consts/issue-90870.rs +ui/consts/issue-90878-2.rs +ui/consts/issue-90878-3.rs +ui/consts/issue-90878.rs +ui/consts/issue-91434.rs +ui/consts/issue-91560.rs +ui/consts/issue-94371.rs +ui/consts/issue-94675.rs +ui/consts/issue-96169.rs +ui/coroutine/issue-102645.rs +ui/coroutine/issue-105084.rs +ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs +ui/coroutine/issue-113279.rs +ui/coroutine/issue-44197.rs +ui/coroutine/issue-45729-unsafe-in-coroutine.rs +ui/coroutine/issue-48048.rs +ui/coroutine/issue-52304.rs +ui/coroutine/issue-52398.rs +ui/coroutine/issue-53548-1.rs +ui/coroutine/issue-53548.rs +ui/coroutine/issue-57017.rs +ui/coroutine/issue-57084.rs +ui/coroutine/issue-57478.rs +ui/coroutine/issue-58888.rs +ui/coroutine/issue-61442-stmt-expr-with-drop.rs +ui/coroutine/issue-62506-two_awaits.rs +ui/coroutine/issue-64620-yield-array-element.rs +ui/coroutine/issue-68112.rs +ui/coroutine/issue-69017.rs +ui/coroutine/issue-69039.rs +ui/coroutine/issue-87142.rs +ui/coroutine/issue-88653.rs +ui/coroutine/issue-91477.rs +ui/coroutine/issue-93161.rs +ui/cross-crate/issue-64872/issue-64872.rs +ui/cycle-trait/issue-12511.rs +ui/debuginfo/issue-105386-debuginfo-ub.rs +ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs +ui/deprecation/issue-84637-deprecated-associated-function.rs +ui/derived-errors/issue-30580.rs +ui/derived-errors/issue-31997-1.rs +ui/derived-errors/issue-31997.rs +ui/derives/issue-36617.rs +ui/derives/issue-43023.rs +ui/derives/issue-91492.rs +ui/derives/issue-91550.rs +ui/derives/issue-97343.rs +ui/deriving/issue-103157.rs +ui/deriving/issue-15689-1.rs +ui/deriving/issue-15689-2.rs +ui/deriving/issue-18738.rs +ui/deriving/issue-19358.rs +ui/deriving/issue-3935.rs +ui/deriving/issue-58319.rs +ui/deriving/issue-6341.rs +ui/deriving/issue-89188-gat-hrtb.rs +ui/did_you_mean/issue-103909.rs +ui/did_you_mean/issue-105225-named-args.rs +ui/did_you_mean/issue-105225.rs +ui/did_you_mean/issue-114112.rs +ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.rs +ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.rs +ui/did_you_mean/issue-31424.rs +ui/did_you_mean/issue-34126.rs +ui/did_you_mean/issue-34337.rs +ui/did_you_mean/issue-35937.rs +ui/did_you_mean/issue-36798.rs +ui/did_you_mean/issue-36798_unknown_field.rs +ui/did_you_mean/issue-37139.rs +ui/did_you_mean/issue-38054-do-not-show-unresolved-names.rs +ui/did_you_mean/issue-38147-1.rs +ui/did_you_mean/issue-38147-2.rs +ui/did_you_mean/issue-38147-3.rs +ui/did_you_mean/issue-38147-4.rs +ui/did_you_mean/issue-39544.rs +ui/did_you_mean/issue-39802-show-5-trait-impls.rs +ui/did_you_mean/issue-40006.rs +ui/did_you_mean/issue-40396.rs +ui/did_you_mean/issue-40823.rs +ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.rs +ui/did_you_mean/issue-42599_available_fields_note.rs +ui/did_you_mean/issue-42764.rs +ui/did_you_mean/issue-43871-enum-instead-of-variant.rs +ui/did_you_mean/issue-46718-struct-pattern-dotdotdot.rs +ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs +ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.rs +ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs +ui/did_you_mean/issue-53280-expected-float-found-integer-literal.rs +ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs +ui/did_you_mean/issue-54109-without-witness.rs +ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs +ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs +ui/drop/auxiliary/issue-10028.rs +ui/drop/issue-100276.rs +ui/drop/issue-10028.rs +ui/drop/issue-103107.rs +ui/drop/issue-110682.rs +ui/drop/issue-17718-const-destructors.rs +ui/drop/issue-21486.rs +ui/drop/issue-23338-ensure-param-drop-order.rs +ui/drop/issue-23611-enum-swap-in-drop.rs +ui/drop/issue-2734.rs +ui/drop/issue-2735-2.rs +ui/drop/issue-2735-3.rs +ui/drop/issue-2735.rs +ui/drop/issue-30018-nopanic.rs +ui/drop/issue-35546.rs +ui/drop/issue-48962.rs +ui/drop/issue-90752-raw-ptr-shenanigans.rs +ui/drop/issue-90752.rs +ui/drop/issue-979.rs +ui/dropck/issue-24805-dropck-itemless.rs +ui/dropck/issue-28498-ugeh-with-lifetime-param.rs +ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs +ui/dropck/issue-28498-ugeh-with-trait-bound.rs +ui/dropck/issue-29844.rs +ui/dropck/issue-34053.rs +ui/dropck/issue-38868.rs +ui/dropck/issue-54943-1.rs +ui/dropck/issue-54943-2.rs +ui/dst/issue-113447.rs +ui/dst/issue-90528-unsizing-not-suggestion-110063.rs +ui/dst/issue-90528-unsizing-suggestion-1.rs +ui/dst/issue-90528-unsizing-suggestion-2.rs +ui/dst/issue-90528-unsizing-suggestion-3.rs +ui/dst/issue-90528-unsizing-suggestion-4.rs +ui/dyn-keyword/issue-5153.rs +ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs +ui/dyn-star/issue-102430.rs +ui/empty/issue-37026.rs +ui/entry-point/issue-118772.rs +ui/enum-discriminant/auxiliary/issue-41394.rs +ui/enum-discriminant/issue-104519.rs +ui/enum-discriminant/issue-41394-rpass.rs +ui/enum-discriminant/issue-41394.rs +ui/enum-discriminant/issue-43398.rs +ui/enum-discriminant/issue-46519.rs +ui/enum-discriminant/issue-50689.rs +ui/enum-discriminant/issue-51582.rs +ui/enum-discriminant/issue-61696.rs +ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs +ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs +ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +ui/enum-discriminant/issue-70509-partial_eq.rs +ui/enum-discriminant/issue-72554.rs +ui/enum-discriminant/issue-90038.rs +ui/enum/issue-1821.rs +ui/enum/issue-42747.rs +ui/enum/issue-67945-1.rs +ui/enum/issue-67945-2.rs +ui/error-codes/e0119/auxiliary/issue-23563-a.rs +ui/error-codes/e0119/issue-23563.rs +ui/error-codes/e0119/issue-27403.rs +ui/error-codes/e0119/issue-28981.rs +ui/errors/issue-104621-extern-bad-file.rs +ui/errors/issue-104621-extern-not-file.rs +ui/errors/issue-89280-emitter-overflow-splice-lines.rs +ui/errors/issue-99572-impl-trait-on-pointer.rs +ui/expr/if/issue-4201.rs +ui/extern/auxiliary/issue-80074-macro-2.rs +ui/extern/auxiliary/issue-80074-macro.rs +ui/extern/issue-10025.rs +ui/extern/issue-10763.rs +ui/extern/issue-10764-rpass.rs +ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs +ui/extern/issue-116203.rs +ui/extern/issue-1251.rs +ui/extern/issue-13655.rs +ui/extern/issue-16250.rs +ui/extern/issue-18576.rs +ui/extern/issue-18819.rs +ui/extern/issue-28324.rs +ui/extern/issue-36122-accessing-externed-dst.rs +ui/extern/issue-47725.rs +ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs +ui/extern/issue-64655-extern-rust-must-allow-unwind.rs +ui/extern/issue-80074.rs +ui/extern/issue-95829.rs +ui/feature-gates/issue-43106-gating-of-bench.rs +ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +ui/feature-gates/issue-43106-gating-of-deprecated.rs +ui/feature-gates/issue-43106-gating-of-derive-2.rs +ui/feature-gates/issue-43106-gating-of-derive.rs +ui/feature-gates/issue-43106-gating-of-macro_escape.rs +ui/feature-gates/issue-43106-gating-of-macro_use.rs +ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs +ui/feature-gates/issue-43106-gating-of-stable.rs +ui/feature-gates/issue-43106-gating-of-test.rs +ui/feature-gates/issue-43106-gating-of-unstable.rs +ui/feature-gates/issue-49983-see-issue-0.rs +ui/fmt/issue-103826.rs +ui/fmt/issue-104142.rs +ui/fmt/issue-23781.rs +ui/fmt/issue-75307.rs +ui/fmt/issue-86085.rs +ui/fmt/issue-89173.rs +ui/fmt/issue-91556.rs +ui/fn/issue-1451.rs +ui/fn/issue-1900.rs +ui/fn/issue-3044.rs +ui/fn/issue-3099.rs +ui/fn/issue-3904.rs +ui/fn/issue-39259.rs +ui/fn/issue-80179.rs +ui/for-loop-while/issue-1257.rs +ui/for-loop-while/issue-2216.rs +ui/for-loop-while/issue-51345.rs +ui/for-loop-while/issue-69841.rs +ui/for/issue-20605.rs +ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs +ui/foreign/issue-91370-foreign-fn-block-impl.rs +ui/foreign/issue-99276-same-type-lifetimes.rs +ui/function-pointer/issue-102289.rs +ui/functions-closures/closure-expected-type/issue-38714.rs +ui/generic-associated-types/bugs/issue-100013.rs +ui/generic-associated-types/bugs/issue-80626.rs +ui/generic-associated-types/bugs/issue-87735.rs +ui/generic-associated-types/bugs/issue-87755.rs +ui/generic-associated-types/bugs/issue-87803.rs +ui/generic-associated-types/bugs/issue-88382.rs +ui/generic-associated-types/bugs/issue-88460.rs +ui/generic-associated-types/bugs/issue-88526.rs +ui/generic-associated-types/bugs/issue-91762.rs +ui/generic-associated-types/issue-101020.rs +ui/generic-associated-types/issue-102114.rs +ui/generic-associated-types/issue-102333.rs +ui/generic-associated-types/issue-102335-gat.rs +ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs +ui/generic-associated-types/issue-47206-where-clause.rs +ui/generic-associated-types/issue-58694-parameter-out-of-range.rs +ui/generic-associated-types/issue-62326-parameter-out-of-range.rs +ui/generic-associated-types/issue-67424.rs +ui/generic-associated-types/issue-67510-pass.rs +ui/generic-associated-types/issue-67510.rs +ui/generic-associated-types/issue-68641-check-gat-bounds.rs +ui/generic-associated-types/issue-68642-broken-llvm-ir.rs +ui/generic-associated-types/issue-68643-broken-mir.rs +ui/generic-associated-types/issue-68644-codegen-selection.rs +ui/generic-associated-types/issue-68645-codegen-fulfillment.rs +ui/generic-associated-types/issue-68648-1.rs +ui/generic-associated-types/issue-68648-2.rs +ui/generic-associated-types/issue-68649-pass.rs +ui/generic-associated-types/issue-68653.rs +ui/generic-associated-types/issue-68656-unsized-values.rs +ui/generic-associated-types/issue-70303.rs +ui/generic-associated-types/issue-70304.rs +ui/generic-associated-types/issue-71176.rs +ui/generic-associated-types/issue-74684-1.rs +ui/generic-associated-types/issue-74684-2.rs +ui/generic-associated-types/issue-74816.rs +ui/generic-associated-types/issue-74824.rs +ui/generic-associated-types/issue-76407.rs +ui/generic-associated-types/issue-76535.rs +ui/generic-associated-types/issue-76826.rs +ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs +ui/generic-associated-types/issue-78671.rs +ui/generic-associated-types/issue-79422.rs +ui/generic-associated-types/issue-79636-1.rs +ui/generic-associated-types/issue-79636-2.rs +ui/generic-associated-types/issue-80433-reduced.rs +ui/generic-associated-types/issue-80433.rs +ui/generic-associated-types/issue-81487.rs +ui/generic-associated-types/issue-81712-cyclic-traits.rs +ui/generic-associated-types/issue-81862.rs +ui/generic-associated-types/issue-84931.rs +ui/generic-associated-types/issue-85921.rs +ui/generic-associated-types/issue-86218-2.rs +ui/generic-associated-types/issue-86218.rs +ui/generic-associated-types/issue-86483.rs +ui/generic-associated-types/issue-86787.rs +ui/generic-associated-types/issue-87258_a.rs +ui/generic-associated-types/issue-87258_b.rs +ui/generic-associated-types/issue-87429-2.rs +ui/generic-associated-types/issue-87429-associated-type-default.rs +ui/generic-associated-types/issue-87429-specialization.rs +ui/generic-associated-types/issue-87429.rs +ui/generic-associated-types/issue-87748.rs +ui/generic-associated-types/issue-87750.rs +ui/generic-associated-types/issue-88287.rs +ui/generic-associated-types/issue-88360.rs +ui/generic-associated-types/issue-88405.rs +ui/generic-associated-types/issue-88459.rs +ui/generic-associated-types/issue-88595.rs +ui/generic-associated-types/issue-89008.rs +ui/generic-associated-types/issue-89352.rs +ui/generic-associated-types/issue-90014-tait.rs +ui/generic-associated-types/issue-90014-tait2.rs +ui/generic-associated-types/issue-90014.rs +ui/generic-associated-types/issue-90729.rs +ui/generic-associated-types/issue-91139.rs +ui/generic-associated-types/issue-91883.rs +ui/generic-associated-types/issue-92033.rs +ui/generic-associated-types/issue-92096.rs +ui/generic-associated-types/issue-92280.rs +ui/generic-associated-types/issue-92954.rs +ui/generic-associated-types/issue-93141.rs +ui/generic-associated-types/issue-93262.rs +ui/generic-associated-types/issue-93341.rs +ui/generic-associated-types/issue-93342.rs +ui/generic-associated-types/issue-93874.rs +ui/generic-associated-types/issue-95305.rs +ui/generics/issue-106694.rs +ui/generics/issue-1112.rs +ui/generics/issue-2936.rs +ui/generics/issue-32498.rs +ui/generics/issue-333.rs +ui/generics/issue-59508-1.rs +ui/generics/issue-59508.rs +ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs +ui/generics/issue-61631-default-type-param-cannot-reference-self.rs +ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs +ui/generics/issue-79605.rs +ui/generics/issue-80512-param-reordering-with-defaults.rs +ui/generics/issue-83556.rs +ui/generics/issue-94432-garbage-ice.rs +ui/generics/issue-94923.rs +ui/generics/issue-95208-ignore-qself.rs +ui/generics/issue-95208.rs +ui/generics/issue-98432.rs +ui/higher-ranked/trait-bounds/issue-100689.rs +ui/higher-ranked/trait-bounds/issue-102899.rs +ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs +ui/higher-ranked/trait-bounds/issue-39292.rs +ui/higher-ranked/trait-bounds/issue-42114.rs +ui/higher-ranked/trait-bounds/issue-43623.rs +ui/higher-ranked/trait-bounds/issue-46989.rs +ui/higher-ranked/trait-bounds/issue-57639.rs +ui/higher-ranked/trait-bounds/issue-58451.rs +ui/higher-ranked/trait-bounds/issue-59311.rs +ui/higher-ranked/trait-bounds/issue-60283.rs +ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs +ui/higher-ranked/trait-bounds/issue-88446.rs +ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs +ui/higher-ranked/trait-bounds/issue-90177.rs +ui/higher-ranked/trait-bounds/issue-95034.rs +ui/higher-ranked/trait-bounds/issue-95230.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs +ui/hygiene/issue-15221.rs +ui/hygiene/issue-29746.rs +ui/hygiene/issue-32922.rs +ui/hygiene/issue-40847.rs +ui/hygiene/issue-44128.rs +ui/hygiene/issue-47311.rs +ui/hygiene/issue-47312.rs +ui/hygiene/issue-61574-const-parameters.rs +ui/hygiene/issue-77523-def-site-async-await.rs +ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs +ui/impl-trait/in-trait/issue-102140.rs +ui/impl-trait/in-trait/issue-102301.rs +ui/impl-trait/in-trait/issue-102571.rs +ui/impl-trait/issue-100075-2.rs +ui/impl-trait/issue-100075.rs +ui/impl-trait/issue-100187.rs +ui/impl-trait/issue-102605.rs +ui/impl-trait/issue-103181-1.rs +ui/impl-trait/issue-103181-2.rs +ui/impl-trait/issue-103599.rs +ui/impl-trait/issue-108591.rs +ui/impl-trait/issue-108592.rs +ui/impl-trait/issue-35668.rs +ui/impl-trait/issue-36792.rs +ui/impl-trait/issue-46959.rs +ui/impl-trait/issue-49556.rs +ui/impl-trait/issue-49579.rs +ui/impl-trait/issue-49685.rs +ui/impl-trait/issue-51185.rs +ui/impl-trait/issue-54966.rs +ui/impl-trait/issue-55872-1.rs +ui/impl-trait/issue-55872-2.rs +ui/impl-trait/issue-55872-3.rs +ui/impl-trait/issue-55872.rs +ui/impl-trait/issue-56445.rs +ui/impl-trait/issue-68532.rs +ui/impl-trait/issue-72911.rs +ui/impl-trait/issue-87450.rs +ui/impl-trait/issue-99073-2.rs +ui/impl-trait/issue-99073.rs +ui/impl-trait/issue-99642-2.rs +ui/impl-trait/issue-99642.rs +ui/impl-trait/issue-99914.rs +ui/impl-trait/issues/issue-104815.rs +ui/impl-trait/issues/issue-105826.rs +ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs +ui/impl-trait/issues/issue-42479.rs +ui/impl-trait/issues/issue-49376.rs +ui/impl-trait/issues/issue-52128.rs +ui/impl-trait/issues/issue-53457.rs +ui/impl-trait/issues/issue-54600.rs +ui/impl-trait/issues/issue-54840.rs +ui/impl-trait/issues/issue-54895.rs +ui/impl-trait/issues/issue-55608-captures-empty-region.rs +ui/impl-trait/issues/issue-57464-unexpected-regions.rs +ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs +ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs +ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs +ui/impl-trait/issues/issue-58504.rs +ui/impl-trait/issues/issue-58956.rs +ui/impl-trait/issues/issue-62742.rs +ui/impl-trait/issues/issue-65581.rs +ui/impl-trait/issues/issue-67830.rs +ui/impl-trait/issues/issue-70877.rs +ui/impl-trait/issues/issue-70971.rs +ui/impl-trait/issues/issue-74282.rs +ui/impl-trait/issues/issue-77987.rs +ui/impl-trait/issues/issue-78722-2.rs +ui/impl-trait/issues/issue-78722.rs +ui/impl-trait/issues/issue-79099.rs +ui/impl-trait/issues/issue-82139.rs +ui/impl-trait/issues/issue-83919.rs +ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs +ui/impl-trait/issues/issue-84073.rs +ui/impl-trait/issues/issue-84919.rs +ui/impl-trait/issues/issue-86201.rs +ui/impl-trait/issues/issue-86642.rs +ui/impl-trait/issues/issue-86719.rs +ui/impl-trait/issues/issue-86800.rs +ui/impl-trait/issues/issue-87295.rs +ui/impl-trait/issues/issue-87340.rs +ui/impl-trait/issues/issue-88236-2.rs +ui/impl-trait/issues/issue-88236.rs +ui/impl-trait/issues/issue-89312.rs +ui/impl-trait/issues/issue-92305.rs +ui/impl-trait/issues/issue-93788.rs +ui/impl-trait/issues/issue-99348-impl-compatibility.rs +ui/implied-bounds/issue-100690.rs +ui/implied-bounds/issue-101951.rs +ui/implied-bounds/issue-110161.rs +ui/imports/auxiliary/issue-114682-2-extern.rs +ui/imports/auxiliary/issue-114682-3-extern.rs +ui/imports/auxiliary/issue-114682-4-extern.rs +ui/imports/auxiliary/issue-114682-5-extern-1.rs +ui/imports/auxiliary/issue-114682-5-extern-2.rs +ui/imports/auxiliary/issue-114682-6-extern.rs +ui/imports/auxiliary/issue-119369-extern.rs +ui/imports/auxiliary/issue-36881-aux.rs +ui/imports/auxiliary/issue-52891.rs +ui/imports/auxiliary/issue-55811.rs +ui/imports/auxiliary/issue-56125.rs +ui/imports/auxiliary/issue-59764.rs +ui/imports/auxiliary/issue-85992-extern-1.rs +ui/imports/auxiliary/issue-85992-extern-2.rs +ui/imports/issue-109148.rs +ui/imports/issue-109343.rs +ui/imports/issue-113953.rs +ui/imports/issue-114682-1.rs +ui/imports/issue-114682-2.rs +ui/imports/issue-114682-3.rs +ui/imports/issue-114682-4.rs +ui/imports/issue-114682-5.rs +ui/imports/issue-114682-6.rs +ui/imports/issue-119369.rs +ui/imports/issue-13404.rs +ui/imports/issue-1697.rs +ui/imports/issue-18083.rs +ui/imports/issue-19498.rs +ui/imports/issue-24081.rs +ui/imports/issue-24883.rs +ui/imports/issue-25396.rs +ui/imports/issue-26873-multifile/issue-26873-multifile.rs +ui/imports/issue-26873-multifile/issue-26873-onefile.rs +ui/imports/issue-26886.rs +ui/imports/issue-26930.rs +ui/imports/issue-28134.rs +ui/imports/issue-28388-1.rs +ui/imports/issue-28388-2.rs +ui/imports/issue-2937.rs +ui/imports/issue-30560.rs +ui/imports/issue-31212.rs +ui/imports/issue-32119.rs +ui/imports/issue-32222.rs +ui/imports/issue-32354-suggest-import-rename.rs +ui/imports/issue-32833.rs +ui/imports/issue-33464.rs +ui/imports/issue-36881.rs +ui/imports/issue-37887.rs +ui/imports/issue-38293.rs +ui/imports/issue-4366-2.rs +ui/imports/issue-4366.rs +ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs +ui/imports/issue-45829/auxiliary/issue-45829-a.rs +ui/imports/issue-45829/auxiliary/issue-45829-b.rs +ui/imports/issue-45829/issue-45829.rs +ui/imports/issue-47623.rs +ui/imports/issue-4865-1.rs +ui/imports/issue-4865-2.rs +ui/imports/issue-4865-3.rs +ui/imports/issue-52891.rs +ui/imports/issue-53140.rs +ui/imports/issue-53269.rs +ui/imports/issue-53512.rs +ui/imports/issue-53565.rs +ui/imports/issue-55457.rs +ui/imports/issue-55811.rs +ui/imports/issue-55884-1.rs +ui/imports/issue-55884-2.rs +ui/imports/issue-56125.rs +ui/imports/issue-56263.rs +ui/imports/issue-57015.rs +ui/imports/issue-57539.rs +ui/imports/issue-59764.rs +ui/imports/issue-62767.rs +ui/imports/issue-68103.rs +ui/imports/issue-81413.rs +ui/imports/issue-8208.rs +ui/imports/issue-85992.rs +ui/imports/issue-8640.rs +ui/imports/issue-99695-b.rs +ui/imports/issue-99695.rs +ui/inference/issue-103587.rs +ui/inference/issue-104649.rs +ui/inference/issue-107090.rs +ui/inference/issue-113354.rs +ui/inference/issue-12028.rs +ui/inference/issue-28935.rs +ui/inference/issue-36053.rs +ui/inference/issue-3743.rs +ui/inference/issue-70082.rs +ui/inference/issue-70703.rs +ui/inference/issue-71309.rs +ui/inference/issue-71584.rs +ui/inference/issue-71732.rs +ui/inference/issue-72616.rs +ui/inference/issue-72690.rs +ui/inference/issue-80409.rs +ui/inference/issue-80816.rs +ui/inference/issue-81522.rs +ui/inference/issue-83606.rs +ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs +ui/inference/issue-86162-1.rs +ui/inference/issue-86162-2.rs +ui/inference/need_type_info/issue-103053.rs +ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs +ui/inference/need_type_info/issue-109905.rs +ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs +ui/infinite/issue-41731-infinite-macro-print.rs +ui/infinite/issue-41731-infinite-macro-println.rs +ui/intrinsics/issue-28575.rs +ui/intrinsics/issue-84297-reifying-copy.rs +ui/invalid/issue-114435-layout-type-err.rs +ui/issue-11881.rs +ui/issue-13560.rs +ui/issue-15924.rs +ui/issue-16822.rs +ui/issue-18502.rs +ui/issue-24106.rs +ui/issue-76387-llvm-miscompile.rs +ui/issues-71798.rs +ui/issues/auxiliary/issue-111011.rs +ui/issues/auxiliary/issue-11224.rs +ui/issues/auxiliary/issue-11508.rs +ui/issues/auxiliary/issue-11529.rs +ui/issues/auxiliary/issue-11680.rs +ui/issues/auxiliary/issue-12612-1.rs +ui/issues/auxiliary/issue-12612-2.rs +ui/issues/auxiliary/issue-12660-aux.rs +ui/issues/auxiliary/issue-13507.rs +ui/issues/auxiliary/issue-13620-1.rs +ui/issues/auxiliary/issue-13620-2.rs +ui/issues/auxiliary/issue-14344-1.rs +ui/issues/auxiliary/issue-14344-2.rs +ui/issues/auxiliary/issue-14421.rs +ui/issues/auxiliary/issue-14422.rs +ui/issues/auxiliary/issue-15562.rs +ui/issues/auxiliary/issue-16643.rs +ui/issues/auxiliary/issue-16725.rs +ui/issues/auxiliary/issue-17662.rs +ui/issues/auxiliary/issue-18501.rs +ui/issues/auxiliary/issue-18514.rs +ui/issues/auxiliary/issue-18711.rs +ui/issues/auxiliary/issue-18913-1.rs +ui/issues/auxiliary/issue-18913-2.rs +ui/issues/auxiliary/issue-19293.rs +ui/issues/auxiliary/issue-19340-1.rs +ui/issues/auxiliary/issue-20389.rs +ui/issues/auxiliary/issue-21202.rs +ui/issues/auxiliary/issue-2170-lib.rs +ui/issues/auxiliary/issue-2316-a.rs +ui/issues/auxiliary/issue-2316-b.rs +ui/issues/auxiliary/issue-2380.rs +ui/issues/auxiliary/issue-2414-a.rs +ui/issues/auxiliary/issue-2414-b.rs +ui/issues/auxiliary/issue-2472-b.rs +ui/issues/auxiliary/issue-25185-1.rs +ui/issues/auxiliary/issue-25185-2.rs +ui/issues/auxiliary/issue-2526.rs +ui/issues/auxiliary/issue-25467.rs +ui/issues/auxiliary/issue-2631-a.rs +ui/issues/auxiliary/issue-2723-a.rs +ui/issues/auxiliary/issue-29265.rs +ui/issues/auxiliary/issue-29485.rs +ui/issues/auxiliary/issue-3012-1.rs +ui/issues/auxiliary/issue-30123-aux.rs +ui/issues/auxiliary/issue-3136-a.rs +ui/issues/auxiliary/issue-31702-1.rs +ui/issues/auxiliary/issue-31702-2.rs +ui/issues/auxiliary/issue-34796-aux.rs +ui/issues/auxiliary/issue-36954.rs +ui/issues/auxiliary/issue-38190.rs +ui/issues/auxiliary/issue-38226-aux.rs +ui/issues/auxiliary/issue-3979-traits.rs +ui/issues/auxiliary/issue-41053.rs +ui/issues/auxiliary/issue-41549.rs +ui/issues/auxiliary/issue-42007-s.rs +ui/issues/auxiliary/issue-4208-cc.rs +ui/issues/auxiliary/issue-4545.rs +ui/issues/auxiliary/issue-48984-aux.rs +ui/issues/auxiliary/issue-49544.rs +ui/issues/auxiliary/issue-51798.rs +ui/issues/auxiliary/issue-52489.rs +ui/issues/auxiliary/issue-5518.rs +ui/issues/auxiliary/issue-5521.rs +ui/issues/auxiliary/issue-56943.rs +ui/issues/auxiliary/issue-57271-lib.rs +ui/issues/auxiliary/issue-5844-aux.rs +ui/issues/auxiliary/issue-7178.rs +ui/issues/auxiliary/issue-73112.rs +ui/issues/auxiliary/issue-7899.rs +ui/issues/auxiliary/issue-8044.rs +ui/issues/auxiliary/issue-8259.rs +ui/issues/auxiliary/issue-8401.rs +ui/issues/auxiliary/issue-9123.rs +ui/issues/auxiliary/issue-9155.rs +ui/issues/auxiliary/issue-9188.rs +ui/issues/auxiliary/issue-9906.rs +ui/issues/auxiliary/issue-9968.rs +ui/issues/issue-10228.rs +ui/issues/issue-10291.rs +ui/issues/issue-102964.rs +ui/issues/issue-10396.rs +ui/issues/issue-10412.rs +ui/issues/issue-10436.rs +ui/issues/issue-10456.rs +ui/issues/issue-10465.rs +ui/issues/issue-10545.rs +ui/issues/issue-10638.rs +ui/issues/issue-10656.rs +ui/issues/issue-106755.rs +ui/issues/issue-10683.rs +ui/issues/issue-10718.rs +ui/issues/issue-10734.rs +ui/issues/issue-10764.rs +ui/issues/issue-10767.rs +ui/issues/issue-10802.rs +ui/issues/issue-10806.rs +ui/issues/issue-10853.rs +ui/issues/issue-10877.rs +ui/issues/issue-10902.rs +ui/issues/issue-11004.rs +ui/issues/issue-11047.rs +ui/issues/issue-11085.rs +ui/issues/issue-11192.rs +ui/issues/issue-11205.rs +ui/issues/issue-11224.rs +ui/issues/issue-11267.rs +ui/issues/issue-11374.rs +ui/issues/issue-11382.rs +ui/issues/issue-11384.rs +ui/issues/issue-11508.rs +ui/issues/issue-11529.rs +ui/issues/issue-11552.rs +ui/issues/issue-11592.rs +ui/issues/issue-11677.rs +ui/issues/issue-11680.rs +ui/issues/issue-11681.rs +ui/issues/issue-11692-1.rs +ui/issues/issue-11692-2.rs +ui/issues/issue-11709.rs +ui/issues/issue-11740.rs +ui/issues/issue-11771.rs +ui/issues/issue-11820.rs +ui/issues/issue-11844.rs +ui/issues/issue-11869.rs +ui/issues/issue-11958.rs +ui/issues/issue-12033.rs +ui/issues/issue-12041.rs +ui/issues/issue-12127.rs +ui/issues/issue-12187-1.rs +ui/issues/issue-12187-2.rs +ui/issues/issue-12285.rs +ui/issues/issue-12567.rs +ui/issues/issue-12612.rs +ui/issues/issue-12660.rs +ui/issues/issue-12677.rs +ui/issues/issue-12699.rs +ui/issues/issue-12729.rs +ui/issues/issue-12744.rs +ui/issues/issue-12860.rs +ui/issues/issue-12863.rs +ui/issues/issue-12909.rs +ui/issues/issue-12920.rs +ui/issues/issue-13027.rs +ui/issues/issue-13058.rs +ui/issues/issue-13105.rs +ui/issues/issue-13167.rs +ui/issues/issue-13202.rs +ui/issues/issue-13204.rs +ui/issues/issue-13214.rs +ui/issues/issue-13259-windows-tcb-trash.rs +ui/issues/issue-13264.rs +ui/issues/issue-13323.rs +ui/issues/issue-13359.rs +ui/issues/issue-13405.rs +ui/issues/issue-13407.rs +ui/issues/issue-13434.rs +ui/issues/issue-13446.rs +ui/issues/issue-13466.rs +ui/issues/issue-13482-2.rs +ui/issues/issue-13482.rs +ui/issues/issue-13497-2.rs +ui/issues/issue-13497.rs +ui/issues/issue-13507-2.rs +ui/issues/issue-13620.rs +ui/issues/issue-13665.rs +ui/issues/issue-13703.rs +ui/issues/issue-13763.rs +ui/issues/issue-13775.rs +ui/issues/issue-13808.rs +ui/issues/issue-13847.rs +ui/issues/issue-13867.rs +ui/issues/issue-14082.rs +ui/issues/issue-14091-2.rs +ui/issues/issue-14091.rs +ui/issues/issue-14092.rs +ui/issues/issue-14229.rs +ui/issues/issue-14254.rs +ui/issues/issue-14285.rs +ui/issues/issue-14308.rs +ui/issues/issue-14330.rs +ui/issues/issue-14344.rs +ui/issues/issue-14366.rs +ui/issues/issue-14382.rs +ui/issues/issue-14393.rs +ui/issues/issue-14399.rs +ui/issues/issue-14421.rs +ui/issues/issue-14422.rs +ui/issues/issue-14541.rs +ui/issues/issue-14721.rs +ui/issues/issue-14821.rs +ui/issues/issue-14845.rs +ui/issues/issue-14853.rs +ui/issues/issue-14865.rs +ui/issues/issue-14875.rs +ui/issues/issue-14901.rs +ui/issues/issue-14915.rs +ui/issues/issue-14919.rs +ui/issues/issue-14959.rs +ui/issues/issue-15034.rs +ui/issues/issue-15043.rs +ui/issues/issue-15063.rs +ui/issues/issue-15094.rs +ui/issues/issue-15104.rs +ui/issues/issue-15129-rpass.rs +ui/issues/issue-15167.rs +ui/issues/issue-15189.rs +ui/issues/issue-15207.rs +ui/issues/issue-15260.rs +ui/issues/issue-15381.rs +ui/issues/issue-15444.rs +ui/issues/issue-15523-big.rs +ui/issues/issue-15523.rs +ui/issues/issue-15562.rs +ui/issues/issue-15571.rs +ui/issues/issue-15673.rs +ui/issues/issue-15734.rs +ui/issues/issue-15735.rs +ui/issues/issue-15756.rs +ui/issues/issue-15763.rs +ui/issues/issue-15774.rs +ui/issues/issue-15783.rs +ui/issues/issue-15793.rs +ui/issues/issue-15858.rs +ui/issues/issue-15896.rs +ui/issues/issue-15965.rs +ui/issues/issue-16048.rs +ui/issues/issue-16149.rs +ui/issues/issue-16151.rs +ui/issues/issue-16256.rs +ui/issues/issue-16278.rs +ui/issues/issue-16401.rs +ui/issues/issue-16441.rs +ui/issues/issue-16452.rs +ui/issues/issue-16492.rs +ui/issues/issue-16530.rs +ui/issues/issue-16560.rs +ui/issues/issue-16562.rs +ui/issues/issue-16596.rs +ui/issues/issue-16643.rs +ui/issues/issue-16648.rs +ui/issues/issue-16668.rs +ui/issues/issue-16671.rs +ui/issues/issue-16683.rs +ui/issues/issue-16725.rs +ui/issues/issue-16739.rs +ui/issues/issue-16745.rs +ui/issues/issue-16774.rs +ui/issues/issue-16783.rs +ui/issues/issue-16819.rs +ui/issues/issue-16922-rpass.rs +ui/issues/issue-16939.rs +ui/issues/issue-16966.rs +ui/issues/issue-16994.rs +ui/issues/issue-17001.rs +ui/issues/issue-17033.rs +ui/issues/issue-17068.rs +ui/issues/issue-17121.rs +ui/issues/issue-17216.rs +ui/issues/issue-17252.rs +ui/issues/issue-17302.rs +ui/issues/issue-17322.rs +ui/issues/issue-17336.rs +ui/issues/issue-17337.rs +ui/issues/issue-17351.rs +ui/issues/issue-17361.rs +ui/issues/issue-17373.rs +ui/issues/issue-17385.rs +ui/issues/issue-17405.rs +ui/issues/issue-17441.rs +ui/issues/issue-17450.rs +ui/issues/issue-17503.rs +ui/issues/issue-17546.rs +ui/issues/issue-17551.rs +ui/issues/issue-17651.rs +ui/issues/issue-17662.rs +ui/issues/issue-17732.rs +ui/issues/issue-17734.rs +ui/issues/issue-17740.rs +ui/issues/issue-17746.rs +ui/issues/issue-17758.rs +ui/issues/issue-17771.rs +ui/issues/issue-17800.rs +ui/issues/issue-17816.rs +ui/issues/issue-17877.rs +ui/issues/issue-17897.rs +ui/issues/issue-17904-2.rs +ui/issues/issue-17904.rs +ui/issues/issue-17905-2.rs +ui/issues/issue-17905.rs +ui/issues/issue-17933.rs +ui/issues/issue-17954.rs +ui/issues/issue-17959.rs +ui/issues/issue-17994.rs +ui/issues/issue-17999.rs +ui/issues/issue-18058.rs +ui/issues/issue-18088.rs +ui/issues/issue-18107.rs +ui/issues/issue-18110.rs +ui/issues/issue-18119.rs +ui/issues/issue-18159.rs +ui/issues/issue-18173.rs +ui/issues/issue-18183.rs +ui/issues/issue-18188.rs +ui/issues/issue-18232.rs +ui/issues/issue-18352.rs +ui/issues/issue-18353.rs +ui/issues/issue-18389.rs +ui/issues/issue-18423.rs +ui/issues/issue-18446-2.rs +ui/issues/issue-18446.rs +ui/issues/issue-18464.rs +ui/issues/issue-18501.rs +ui/issues/issue-18514.rs +ui/issues/issue-18532.rs +ui/issues/issue-18539.rs +ui/issues/issue-18566.rs +ui/issues/issue-18611.rs +ui/issues/issue-18685.rs +ui/issues/issue-18711.rs +ui/issues/issue-18767.rs +ui/issues/issue-18783.rs +ui/issues/issue-18809.rs +ui/issues/issue-18845.rs +ui/issues/issue-18859.rs +ui/issues/issue-18906.rs +ui/issues/issue-18913.rs +ui/issues/issue-18919.rs +ui/issues/issue-18952.rs +ui/issues/issue-18959.rs +ui/issues/issue-18988.rs +ui/issues/issue-19001.rs +ui/issues/issue-19037.rs +ui/issues/issue-19086.rs +ui/issues/issue-19097.rs +ui/issues/issue-19098.rs +ui/issues/issue-19100.rs +ui/issues/issue-19127.rs +ui/issues/issue-19129-1.rs +ui/issues/issue-19129-2.rs +ui/issues/issue-19135.rs +ui/issues/issue-19244-1.rs +ui/issues/issue-19244-2.rs +ui/issues/issue-19293.rs +ui/issues/issue-19340-1.rs +ui/issues/issue-19340-2.rs +ui/issues/issue-19367.rs +ui/issues/issue-19380.rs +ui/issues/issue-19398.rs +ui/issues/issue-19404.rs +ui/issues/issue-19479.rs +ui/issues/issue-19482.rs +ui/issues/issue-19499.rs +ui/issues/issue-19601.rs +ui/issues/issue-19631.rs +ui/issues/issue-19632.rs +ui/issues/issue-19692.rs +ui/issues/issue-19734.rs +ui/issues/issue-19811-escape-unicode.rs +ui/issues/issue-19850.rs +ui/issues/issue-19922.rs +ui/issues/issue-19982.rs +ui/issues/issue-19991.rs +ui/issues/issue-20009.rs +ui/issues/issue-20055-box-trait.rs +ui/issues/issue-20055-box-unsized-array.rs +ui/issues/issue-20162.rs +ui/issues/issue-20174.rs +ui/issues/issue-20186.rs +ui/issues/issue-20225.rs +ui/issues/issue-20261.rs +ui/issues/issue-20313-rpass.rs +ui/issues/issue-20313.rs +ui/issues/issue-20389.rs +ui/issues/issue-20396.rs +ui/issues/issue-20413.rs +ui/issues/issue-20414.rs +ui/issues/issue-20427.rs +ui/issues/issue-20433.rs +ui/issues/issue-20454.rs +ui/issues/issue-20544.rs +ui/issues/issue-20575.rs +ui/issues/issue-20644.rs +ui/issues/issue-20676.rs +ui/issues/issue-20714.rs +ui/issues/issue-2074.rs +ui/issues/issue-20763-1.rs +ui/issues/issue-20763-2.rs +ui/issues/issue-20772.rs +ui/issues/issue-20797.rs +ui/issues/issue-20803.rs +ui/issues/issue-20831-debruijn.rs +ui/issues/issue-20847.rs +ui/issues/issue-20939.rs +ui/issues/issue-20953.rs +ui/issues/issue-20971.rs +ui/issues/issue-21033.rs +ui/issues/issue-21140.rs +ui/issues/issue-21160.rs +ui/issues/issue-21174-2.rs +ui/issues/issue-21174.rs +ui/issues/issue-21177.rs +ui/issues/issue-21202.rs +ui/issues/issue-21245.rs +ui/issues/issue-21291.rs +ui/issues/issue-21306.rs +ui/issues/issue-21332.rs +ui/issues/issue-21361.rs +ui/issues/issue-21384.rs +ui/issues/issue-21400.rs +ui/issues/issue-21402.rs +ui/issues/issue-21449.rs +ui/issues/issue-2150.rs +ui/issues/issue-2151.rs +ui/issues/issue-21546.rs +ui/issues/issue-21554.rs +ui/issues/issue-21600.rs +ui/issues/issue-21622.rs +ui/issues/issue-21634.rs +ui/issues/issue-21655.rs +ui/issues/issue-2170-exe.rs +ui/issues/issue-21701.rs +ui/issues/issue-21763.rs +ui/issues/issue-21891.rs +ui/issues/issue-2190-1.rs +ui/issues/issue-21909.rs +ui/issues/issue-21922.rs +ui/issues/issue-21946.rs +ui/issues/issue-21950.rs +ui/issues/issue-21974.rs +ui/issues/issue-22008.rs +ui/issues/issue-22034.rs +ui/issues/issue-22036.rs +ui/issues/issue-2214.rs +ui/issues/issue-22258.rs +ui/issues/issue-22289.rs +ui/issues/issue-22312.rs +ui/issues/issue-22346.rs +ui/issues/issue-22356.rs +ui/issues/issue-22370.rs +ui/issues/issue-22403.rs +ui/issues/issue-22426.rs +ui/issues/issue-22434.rs +ui/issues/issue-22468.rs +ui/issues/issue-22471.rs +ui/issues/issue-22577.rs +ui/issues/issue-22599.rs +ui/issues/issue-22603.rs +ui/issues/issue-22629.rs +ui/issues/issue-22638.rs +ui/issues/issue-22644.rs +ui/issues/issue-22673.rs +ui/issues/issue-22684.rs +ui/issues/issue-22706.rs +ui/issues/issue-22777.rs +ui/issues/issue-22781.rs +ui/issues/issue-22789.rs +ui/issues/issue-2281-part1.rs +ui/issues/issue-22814.rs +ui/issues/issue-2284.rs +ui/issues/issue-22864-1.rs +ui/issues/issue-22864-2.rs +ui/issues/issue-22872.rs +ui/issues/issue-22874.rs +ui/issues/issue-2288.rs +ui/issues/issue-22886.rs +ui/issues/issue-22894.rs +ui/issues/issue-22933-1.rs +ui/issues/issue-22933-2.rs +ui/issues/issue-22992-2.rs +ui/issues/issue-22992.rs +ui/issues/issue-23024.rs +ui/issues/issue-23036.rs +ui/issues/issue-23041.rs +ui/issues/issue-23046.rs +ui/issues/issue-23073.rs +ui/issues/issue-2311-2.rs +ui/issues/issue-2311.rs +ui/issues/issue-2312.rs +ui/issues/issue-23122-1.rs +ui/issues/issue-23122-2.rs +ui/issues/issue-2316-c.rs +ui/issues/issue-23173.rs +ui/issues/issue-23189.rs +ui/issues/issue-23217.rs +ui/issues/issue-23253.rs +ui/issues/issue-23261.rs +ui/issues/issue-23281.rs +ui/issues/issue-23304-1.rs +ui/issues/issue-23304-2.rs +ui/issues/issue-23311.rs +ui/issues/issue-23336.rs +ui/issues/issue-23354-2.rs +ui/issues/issue-23354.rs +ui/issues/issue-23406.rs +ui/issues/issue-23433.rs +ui/issues/issue-23442.rs +ui/issues/issue-23477.rs +ui/issues/issue-23485.rs +ui/issues/issue-23491.rs +ui/issues/issue-23543.rs +ui/issues/issue-23544.rs +ui/issues/issue-23550.rs +ui/issues/issue-23589.rs +ui/issues/issue-23699.rs +ui/issues/issue-2380-b.rs +ui/issues/issue-23808.rs +ui/issues/issue-2383.rs +ui/issues/issue-23891.rs +ui/issues/issue-23898.rs +ui/issues/issue-23958.rs +ui/issues/issue-23966.rs +ui/issues/issue-23992.rs +ui/issues/issue-24013.rs +ui/issues/issue-24036.rs +ui/issues/issue-24086.rs +ui/issues/issue-2414-c.rs +ui/issues/issue-24161.rs +ui/issues/issue-24227.rs +ui/issues/issue-2428.rs +ui/issues/issue-24308.rs +ui/issues/issue-24322.rs +ui/issues/issue-24352.rs +ui/issues/issue-24353.rs +ui/issues/issue-24357.rs +ui/issues/issue-24363.rs +ui/issues/issue-24365.rs +ui/issues/issue-24389.rs +ui/issues/issue-24424.rs +ui/issues/issue-24434.rs +ui/issues/issue-2445-b.rs +ui/issues/issue-2445.rs +ui/issues/issue-24533.rs +ui/issues/issue-24589.rs +ui/issues/issue-2463.rs +ui/issues/issue-24682.rs +ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs +ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs +ui/issues/issue-2470-bounds-check-overflow.rs +ui/issues/issue-2472.rs +ui/issues/issue-24779.rs +ui/issues/issue-24819.rs +ui/issues/issue-2487-a.rs +ui/issues/issue-24945-repeat-dash-opts.rs +ui/issues/issue-24947.rs +ui/issues/issue-24954.rs +ui/issues/issue-2502.rs +ui/issues/issue-25076.rs +ui/issues/issue-25089.rs +ui/issues/issue-25145.rs +ui/issues/issue-25180.rs +ui/issues/issue-25185.rs +ui/issues/issue-2526-a.rs +ui/issues/issue-25279.rs +ui/issues/issue-25343.rs +ui/issues/issue-25368.rs +ui/issues/issue-25386.rs +ui/issues/issue-25394.rs +ui/issues/issue-25467.rs +ui/issues/issue-25497.rs +ui/issues/issue-2550.rs +ui/issues/issue-25515.rs +ui/issues/issue-25549-multiple-drop.rs +ui/issues/issue-25579.rs +ui/issues/issue-25679.rs +ui/issues/issue-25693.rs +ui/issues/issue-25746-bool-transmute.rs +ui/issues/issue-25757.rs +ui/issues/issue-25810.rs +ui/issues/issue-2590.rs +ui/issues/issue-25901.rs +ui/issues/issue-26056.rs +ui/issues/issue-26093.rs +ui/issues/issue-26095.rs +ui/issues/issue-26127.rs +ui/issues/issue-26186.rs +ui/issues/issue-26205.rs +ui/issues/issue-26217.rs +ui/issues/issue-26237.rs +ui/issues/issue-2631-b.rs +ui/issues/issue-2642.rs +ui/issues/issue-26468.rs +ui/issues/issue-26472.rs +ui/issues/issue-26484.rs +ui/issues/issue-26614.rs +ui/issues/issue-26619.rs +ui/issues/issue-26641.rs +ui/issues/issue-26646.rs +ui/issues/issue-26655.rs +ui/issues/issue-26709.rs +ui/issues/issue-26802.rs +ui/issues/issue-26805.rs +ui/issues/issue-26812.rs +ui/issues/issue-26948.rs +ui/issues/issue-26997.rs +ui/issues/issue-27008.rs +ui/issues/issue-27033.rs +ui/issues/issue-27042.rs +ui/issues/issue-27054-primitive-binary-ops.rs +ui/issues/issue-27078.rs +ui/issues/issue-2708.rs +ui/issues/issue-27105.rs +ui/issues/issue-2723-b.rs +ui/issues/issue-27240.rs +ui/issues/issue-27268.rs +ui/issues/issue-27281.rs +ui/issues/issue-27340.rs +ui/issues/issue-27401-dropflag-reinit.rs +ui/issues/issue-27433.rs +ui/issues/issue-27592.rs +ui/issues/issue-2761.rs +ui/issues/issue-27639.rs +ui/issues/issue-27697.rs +ui/issues/issue-27815.rs +ui/issues/issue-27842.rs +ui/issues/issue-27889.rs +ui/issues/issue-27942.rs +ui/issues/issue-27949.rs +ui/issues/issue-27997.rs +ui/issues/issue-28105.rs +ui/issues/issue-28109.rs +ui/issues/issue-28181.rs +ui/issues/issue-2823.rs +ui/issues/issue-28279.rs +ui/issues/issue-28344.rs +ui/issues/issue-28433.rs +ui/issues/issue-28472.rs +ui/issues/issue-2848.rs +ui/issues/issue-2849.rs +ui/issues/issue-28498-must-work-ex1.rs +ui/issues/issue-28498-must-work-ex2.rs +ui/issues/issue-28498-ugeh-ex1.rs +ui/issues/issue-28550.rs +ui/issues/issue-28561.rs +ui/issues/issue-28568.rs +ui/issues/issue-28586.rs +ui/issues/issue-28600.rs +ui/issues/issue-28625.rs +ui/issues/issue-28776.rs +ui/issues/issue-28777.rs +ui/issues/issue-28828.rs +ui/issues/issue-28839.rs +ui/issues/issue-28936.rs +ui/issues/issue-2895.rs +ui/issues/issue-28971.rs +ui/issues/issue-28983.rs +ui/issues/issue-28999.rs +ui/issues/issue-29030.rs +ui/issues/issue-29037.rs +ui/issues/issue-2904.rs +ui/issues/issue-29048.rs +ui/issues/issue-29053.rs +ui/issues/issue-29071-2.rs +ui/issues/issue-29071.rs +ui/issues/issue-29092.rs +ui/issues/issue-29147-rpass.rs +ui/issues/issue-29147.rs +ui/issues/issue-29265.rs +ui/issues/issue-29276.rs +ui/issues/issue-2935.rs +ui/issues/issue-29466.rs +ui/issues/issue-29485.rs +ui/issues/issue-2951.rs +ui/issues/issue-29516.rs +ui/issues/issue-29522.rs +ui/issues/issue-29540.rs +ui/issues/issue-29663.rs +ui/issues/issue-29668.rs +ui/issues/issue-29710.rs +ui/issues/issue-29723.rs +ui/issues/issue-29740.rs +ui/issues/issue-29743.rs +ui/issues/issue-29821.rs +ui/issues/issue-29857.rs +ui/issues/issue-29861.rs +ui/issues/issue-2989.rs +ui/issues/issue-29948.rs +ui/issues/issue-2995.rs +ui/issues/issue-30018-panic.rs +ui/issues/issue-30081.rs +ui/issues/issue-3012-2.rs +ui/issues/issue-30123.rs +ui/issues/issue-3021-b.rs +ui/issues/issue-3021-d.rs +ui/issues/issue-30236.rs +ui/issues/issue-30255.rs +ui/issues/issue-3026.rs +ui/issues/issue-3029.rs +ui/issues/issue-3037.rs +ui/issues/issue-30371.rs +ui/issues/issue-3038.rs +ui/issues/issue-30380.rs +ui/issues/issue-3052.rs +ui/issues/issue-30530.rs +ui/issues/issue-30589.rs +ui/issues/issue-30615.rs +ui/issues/issue-30756.rs +ui/issues/issue-30891.rs +ui/issues/issue-3091.rs +ui/issues/issue-31011.rs +ui/issues/issue-3109.rs +ui/issues/issue-3121.rs +ui/issues/issue-31260.rs +ui/issues/issue-31267-additional.rs +ui/issues/issue-31267.rs +ui/issues/issue-31299.rs +ui/issues/issue-3136-b.rs +ui/issues/issue-3149.rs +ui/issues/issue-31511.rs +ui/issues/issue-3154.rs +ui/issues/issue-31702.rs +ui/issues/issue-31769.rs +ui/issues/issue-31776.rs +ui/issues/issue-31910.rs +ui/issues/issue-32004.rs +ui/issues/issue-32008.rs +ui/issues/issue-32086.rs +ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.rs +ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.rs +ui/issues/issue-3214.rs +ui/issues/issue-3220.rs +ui/issues/issue-32292.rs +ui/issues/issue-32324.rs +ui/issues/issue-32326.rs +ui/issues/issue-32377.rs +ui/issues/issue-32389.rs +ui/issues/issue-32518.rs +ui/issues/issue-32655.rs +ui/issues/issue-32782.rs +ui/issues/issue-32797.rs +ui/issues/issue-32805.rs +ui/issues/issue-3290.rs +ui/issues/issue-32950.rs +ui/issues/issue-32995-2.rs +ui/issues/issue-32995.rs +ui/issues/issue-33202.rs +ui/issues/issue-33241.rs +ui/issues/issue-33287.rs +ui/issues/issue-33293.rs +ui/issues/issue-33387.rs +ui/issues/issue-3344.rs +ui/issues/issue-33461.rs +ui/issues/issue-33504.rs +ui/issues/issue-33525.rs +ui/issues/issue-33571.rs +ui/issues/issue-33687.rs +ui/issues/issue-33770.rs +ui/issues/issue-3389.rs +ui/issues/issue-33941.rs +ui/issues/issue-33992.rs +ui/issues/issue-34047.rs +ui/issues/issue-34074.rs +ui/issues/issue-34209.rs +ui/issues/issue-34229.rs +ui/issues/issue-3424.rs +ui/issues/issue-3429.rs +ui/issues/issue-34334.rs +ui/issues/issue-34349.rs +ui/issues/issue-34373.rs +ui/issues/issue-34418.rs +ui/issues/issue-34427.rs +ui/issues/issue-3447.rs +ui/issues/issue-34503.rs +ui/issues/issue-34569.rs +ui/issues/issue-34571.rs +ui/issues/issue-34751.rs +ui/issues/issue-3477.rs +ui/issues/issue-34780.rs +ui/issues/issue-34796.rs +ui/issues/issue-34839.rs +ui/issues/issue-3500.rs +ui/issues/issue-35139.rs +ui/issues/issue-3521-2.rs +ui/issues/issue-35241.rs +ui/issues/issue-35423.rs +ui/issues/issue-3556.rs +ui/issues/issue-35570.rs +ui/issues/issue-3559.rs +ui/issues/issue-35600.rs +ui/issues/issue-3574.rs +ui/issues/issue-35815.rs +ui/issues/issue-35976.rs +ui/issues/issue-35988.rs +ui/issues/issue-36023.rs +ui/issues/issue-36036-associated-type-layout.rs +ui/issues/issue-36075.rs +ui/issues/issue-3609.rs +ui/issues/issue-36116.rs +ui/issues/issue-36260.rs +ui/issues/issue-36278-prefix-nesting.rs +ui/issues/issue-36299.rs +ui/issues/issue-36379.rs +ui/issues/issue-36400.rs +ui/issues/issue-36474.rs +ui/issues/issue-3656.rs +ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs +ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs +ui/issues/issue-36744-bitcast-args-if-needed.rs +ui/issues/issue-36786-resolve-call.rs +ui/issues/issue-3680.rs +ui/issues/issue-36816.rs +ui/issues/issue-36836.rs +ui/issues/issue-36839.rs +ui/issues/issue-36856.rs +ui/issues/issue-36936.rs +ui/issues/issue-36954.rs +ui/issues/issue-3702-2.rs +ui/issues/issue-3702.rs +ui/issues/issue-37051.rs +ui/issues/issue-37109.rs +ui/issues/issue-37131.rs +ui/issues/issue-37311-type-length-limit/issue-37311.rs +ui/issues/issue-37510.rs +ui/issues/issue-3753.rs +ui/issues/issue-37534.rs +ui/issues/issue-37576.rs +ui/issues/issue-3763.rs +ui/issues/issue-37665.rs +ui/issues/issue-37686.rs +ui/issues/issue-37725.rs +ui/issues/issue-37733.rs +ui/issues/issue-3779.rs +ui/issues/issue-37884.rs +ui/issues/issue-38160.rs +ui/issues/issue-38190.rs +ui/issues/issue-38226.rs +ui/issues/issue-38381.rs +ui/issues/issue-38412.rs +ui/issues/issue-38437.rs +ui/issues/issue-38458.rs +ui/issues/issue-3847.rs +ui/issues/issue-38556.rs +ui/issues/issue-38727.rs +ui/issues/issue-3874.rs +ui/issues/issue-38763.rs +ui/issues/issue-38857.rs +ui/issues/issue-38875/auxiliary/issue-38875-b.rs +ui/issues/issue-38875/issue-38875.rs +ui/issues/issue-3888-2.rs +ui/issues/issue-38919.rs +ui/issues/issue-38942.rs +ui/issues/issue-3895.rs +ui/issues/issue-38954.rs +ui/issues/issue-38987.rs +ui/issues/issue-39089.rs +ui/issues/issue-39175.rs +ui/issues/issue-39211.rs +ui/issues/issue-39367.rs +ui/issues/issue-39548.rs +ui/issues/issue-39687.rs +ui/issues/issue-39709.rs +ui/issues/issue-3979-2.rs +ui/issues/issue-3979-xcrate.rs +ui/issues/issue-3979.rs +ui/issues/issue-39808.rs +ui/issues/issue-39827.rs +ui/issues/issue-39848.rs +ui/issues/issue-3991.rs +ui/issues/issue-3993.rs +ui/issues/issue-39970.rs +ui/issues/issue-39984.rs +ui/issues/issue-40000.rs +ui/issues/issue-40136.rs +ui/issues/issue-40235.rs +ui/issues/issue-4025.rs +ui/issues/issue-40288-2.rs +ui/issues/issue-40288.rs +ui/issues/issue-40350.rs +ui/issues/issue-40402-ref-hints/issue-40402-1.rs +ui/issues/issue-40402-ref-hints/issue-40402-2.rs +ui/issues/issue-40408.rs +ui/issues/issue-40610.rs +ui/issues/issue-40749.rs +ui/issues/issue-40782.rs +ui/issues/issue-40827.rs +ui/issues/issue-40845.rs +ui/issues/issue-40861.rs +ui/issues/issue-40883.rs +ui/issues/issue-40951.rs +ui/issues/issue-41053.rs +ui/issues/issue-41139.rs +ui/issues/issue-41213.rs +ui/issues/issue-41229-ref-str.rs +ui/issues/issue-41272.rs +ui/issues/issue-41298.rs +ui/issues/issue-41479.rs +ui/issues/issue-41498.rs +ui/issues/issue-41549.rs +ui/issues/issue-41604.rs +ui/issues/issue-41628.rs +ui/issues/issue-41652/auxiliary/issue-41652-b.rs +ui/issues/issue-41652/issue-41652.rs +ui/issues/issue-41677.rs +ui/issues/issue-41696.rs +ui/issues/issue-41726.rs +ui/issues/issue-41742.rs +ui/issues/issue-41744.rs +ui/issues/issue-41849-variance-req.rs +ui/issues/issue-41880.rs +ui/issues/issue-41888.rs +ui/issues/issue-41936-variance-coerce-unsized-cycle.rs +ui/issues/issue-41974.rs +ui/issues/issue-41998.rs +ui/issues/issue-42007.rs +ui/issues/issue-4208.rs +ui/issues/issue-42106.rs +ui/issues/issue-42148.rs +ui/issues/issue-42210.rs +ui/issues/issue-4228.rs +ui/issues/issue-42312.rs +ui/issues/issue-42453.rs +ui/issues/issue-42467.rs +ui/issues/issue-4252.rs +ui/issues/issue-42552.rs +ui/issues/issue-4265.rs +ui/issues/issue-42755.rs +ui/issues/issue-42796.rs +ui/issues/issue-42880.rs +ui/issues/issue-42956.rs +ui/issues/issue-43057.rs +ui/issues/issue-43205.rs +ui/issues/issue-43250.rs +ui/issues/issue-43291.rs +ui/issues/issue-4333.rs +ui/issues/issue-4335.rs +ui/issues/issue-43355.rs +ui/issues/issue-43357.rs +ui/issues/issue-43420-no-over-suggest.rs +ui/issues/issue-43424.rs +ui/issues/issue-43431.rs +ui/issues/issue-43483.rs +ui/issues/issue-43692.rs +ui/issues/issue-43806.rs +ui/issues/issue-43853.rs +ui/issues/issue-4387.rs +ui/issues/issue-43910.rs +ui/issues/issue-43923.rs +ui/issues/issue-43925.rs +ui/issues/issue-43926.rs +ui/issues/issue-43988.rs +ui/issues/issue-44023.rs +ui/issues/issue-44056.rs +ui/issues/issue-44078.rs +ui/issues/issue-44216-add-instant.rs +ui/issues/issue-44216-add-system-time.rs +ui/issues/issue-44216-sub-instant.rs +ui/issues/issue-44216-sub-system-time.rs +ui/issues/issue-44239.rs +ui/issues/issue-44247.rs +ui/issues/issue-44405.rs +ui/issues/issue-4464.rs +ui/issues/issue-44730.rs +ui/issues/issue-44851.rs +ui/issues/issue-4517.rs +ui/issues/issue-4541.rs +ui/issues/issue-4542.rs +ui/issues/issue-45425.rs +ui/issues/issue-4545.rs +ui/issues/issue-45510.rs +ui/issues/issue-45562.rs +ui/issues/issue-45697-1.rs +ui/issues/issue-45697.rs +ui/issues/issue-45730.rs +ui/issues/issue-45731.rs +ui/issues/issue-45801.rs +ui/issues/issue-45965.rs +ui/issues/issue-46069.rs +ui/issues/issue-46101.rs +ui/issues/issue-46302.rs +ui/issues/issue-46311.rs +ui/issues/issue-46332.rs +ui/issues/issue-46471-1.rs +ui/issues/issue-46472.rs +ui/issues/issue-46604.rs +ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.rs +ui/issues/issue-46771.rs +ui/issues/issue-46855.rs +ui/issues/issue-46964.rs +ui/issues/issue-46983.rs +ui/issues/issue-47073-zero-padded-tuple-struct-indices.rs +ui/issues/issue-47094.rs +ui/issues/issue-47184.rs +ui/issues/issue-47309.rs +ui/issues/issue-4734.rs +ui/issues/issue-4735.rs +ui/issues/issue-4736.rs +ui/issues/issue-47364.rs +ui/issues/issue-47377.rs +ui/issues/issue-47380.rs +ui/issues/issue-47486.rs +ui/issues/issue-4759-1.rs +ui/issues/issue-4759.rs +ui/issues/issue-47638.rs +ui/issues/issue-47673.rs +ui/issues/issue-47703-1.rs +ui/issues/issue-47703-tuple.rs +ui/issues/issue-47703.rs +ui/issues/issue-47715.rs +ui/issues/issue-47722.rs +ui/issues/issue-48006.rs +ui/issues/issue-48131.rs +ui/issues/issue-48132.rs +ui/issues/issue-48159.rs +ui/issues/issue-48276.rs +ui/issues/issue-4830.rs +ui/issues/issue-48364.rs +ui/issues/issue-48728.rs +ui/issues/issue-4875.rs +ui/issues/issue-48838.rs +ui/issues/issue-48984.rs +ui/issues/issue-49298.rs +ui/issues/issue-4935.rs +ui/issues/issue-49544.rs +ui/issues/issue-49632.rs +ui/issues/issue-4968.rs +ui/issues/issue-4972.rs +ui/issues/issue-49824.rs +ui/issues/issue-49854.rs +ui/issues/issue-49919.rs +ui/issues/issue-49934-errors.rs +ui/issues/issue-49934.rs +ui/issues/issue-49955.rs +ui/issues/issue-49973.rs +ui/issues/issue-50187.rs +ui/issues/issue-50403.rs +ui/issues/issue-50411.rs +ui/issues/issue-50415.rs +ui/issues/issue-50442.rs +ui/issues/issue-50471.rs +ui/issues/issue-50518.rs +ui/issues/issue-50571.rs +ui/issues/issue-50581.rs +ui/issues/issue-50582.rs +ui/issues/issue-50585.rs +ui/issues/issue-50600.rs +ui/issues/issue-50618.rs +ui/issues/issue-5062.rs +ui/issues/issue-5067.rs +ui/issues/issue-50688.rs +ui/issues/issue-50714-1.rs +ui/issues/issue-50714.rs +ui/issues/issue-50761.rs +ui/issues/issue-50781.rs +ui/issues/issue-50802.rs +ui/issues/issue-50811.rs +ui/issues/issue-5100.rs +ui/issues/issue-51022.rs +ui/issues/issue-51044.rs +ui/issues/issue-51102.rs +ui/issues/issue-51116.rs +ui/issues/issue-51154.rs +ui/issues/issue-51515.rs +ui/issues/issue-51632-try-desugar-incompatible-types.rs +ui/issues/issue-51655.rs +ui/issues/issue-51714.rs +ui/issues/issue-51798.rs +ui/issues/issue-51874.rs +ui/issues/issue-51907.rs +ui/issues/issue-5192.rs +ui/issues/issue-51947.rs +ui/issues/issue-52049.rs +ui/issues/issue-52126-assign-op-invariance.rs +ui/issues/issue-52262.rs +ui/issues/issue-5239-1.rs +ui/issues/issue-5239-2.rs +ui/issues/issue-52489.rs +ui/issues/issue-52533.rs +ui/issues/issue-52717.rs +ui/issues/issue-5280.rs +ui/issues/issue-5315.rs +ui/issues/issue-5321-immediates-with-bare-self.rs +ui/issues/issue-53251.rs +ui/issues/issue-53275.rs +ui/issues/issue-53300.rs +ui/issues/issue-53333.rs +ui/issues/issue-53348.rs +ui/issues/issue-53419.rs +ui/issues/issue-53498.rs +ui/issues/issue-53568.rs +ui/issues/issue-5358-1.rs +ui/issues/issue-53728.rs +ui/issues/issue-53843.rs +ui/issues/issue-54044.rs +ui/issues/issue-54062.rs +ui/issues/issue-54094.rs +ui/issues/issue-5439.rs +ui/issues/issue-54410.rs +ui/issues/issue-54462-mutable-noalias-correctness.rs +ui/issues/issue-54477-reduced-2.rs +ui/issues/issue-54696.rs +ui/issues/issue-5518.rs +ui/issues/issue-5521.rs +ui/issues/issue-55376.rs +ui/issues/issue-55380.rs +ui/issues/issue-5550.rs +ui/issues/issue-5554.rs +ui/issues/issue-55587.rs +ui/issues/issue-5572.rs +ui/issues/issue-55731.rs +ui/issues/issue-56128.rs +ui/issues/issue-56175.rs +ui/issues/issue-56199.rs +ui/issues/issue-56229.rs +ui/issues/issue-56237.rs +ui/issues/issue-5666.rs +ui/issues/issue-56806.rs +ui/issues/issue-56835.rs +ui/issues/issue-56870.rs +ui/issues/issue-5688.rs +ui/issues/issue-56943.rs +ui/issues/issue-5708.rs +ui/issues/issue-57156.rs +ui/issues/issue-57162.rs +ui/issues/issue-5718.rs +ui/issues/issue-57198-pass.rs +ui/issues/issue-57271.rs +ui/issues/issue-57362-1.rs +ui/issues/issue-57362-2.rs +ui/issues/issue-57399-self-return-impl-trait.rs +ui/issues/issue-5741.rs +ui/issues/issue-5754.rs +ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs +ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs +ui/issues/issue-57781.rs +ui/issues/issue-57924.rs +ui/issues/issue-58212.rs +ui/issues/issue-58375-monomorphize-default-impls.rs +ui/issues/issue-5844.rs +ui/issues/issue-58463.rs +ui/issues/issue-58712.rs +ui/issues/issue-58734.rs +ui/issues/issue-5883.rs +ui/issues/issue-5884.rs +ui/issues/issue-58857.rs +ui/issues/issue-5900.rs +ui/issues/issue-59020.rs +ui/issues/issue-5917.rs +ui/issues/issue-59326.rs +ui/issues/issue-59488.rs +ui/issues/issue-59494.rs +ui/issues/issue-5950.rs +ui/issues/issue-59756.rs +ui/issues/issue-5988.rs +ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs +ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs +ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs +ui/issues/issue-60218.rs +ui/issues/issue-60622.rs +ui/issues/issue-60989.rs +ui/issues/issue-61106.rs +ui/issues/issue-61108.rs +ui/issues/issue-6117.rs +ui/issues/issue-6130.rs +ui/issues/issue-61475.rs +ui/issues/issue-6153.rs +ui/issues/issue-61623.rs +ui/issues/issue-61894.rs +ui/issues/issue-62480.rs +ui/issues/issue-6318.rs +ui/issues/issue-6344-let.rs +ui/issues/issue-6344-match.rs +ui/issues/issue-63983.rs +ui/issues/issue-64430.rs +ui/issues/issue-64559.rs +ui/issues/issue-64593.rs +ui/issues/issue-64792-bad-unicode-ctor.rs +ui/issues/issue-65131.rs +ui/issues/issue-65230.rs +ui/issues/issue-65462.rs +ui/issues/issue-6557.rs +ui/issues/issue-66308.rs +ui/issues/issue-66353.rs +ui/issues/issue-66667-function-cmp-cycle.rs +ui/issues/issue-66702-break-outside-loop-val.rs +ui/issues/issue-66706.rs +ui/issues/issue-66923-show-error-for-correct-call.rs +ui/issues/issue-67039-unsound-pin-partialeq.rs +ui/issues/issue-6738.rs +ui/issues/issue-67535.rs +ui/issues/issue-67552.rs +ui/issues/issue-68010-large-zst-consts.rs +ui/issues/issue-68696-catch-during-unwind.rs +ui/issues/issue-6892.rs +ui/issues/issue-68951.rs +ui/issues/issue-6898.rs +ui/issues/issue-69130.rs +ui/issues/issue-6919.rs +ui/issues/issue-69306.rs +ui/issues/issue-6936.rs +ui/issues/issue-69455.rs +ui/issues/issue-69602-type-err-during-codegen-ice.rs +ui/issues/issue-69683.rs +ui/issues/issue-70093/issue-70093-link-directives.rs +ui/issues/issue-70093/issue-70093.rs +ui/issues/issue-7012.rs +ui/issues/issue-70381.rs +ui/issues/issue-7044.rs +ui/issues/issue-7061.rs +ui/issues/issue-70673.rs +ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs +ui/issues/issue-70746.rs +ui/issues/issue-7092.rs +ui/issues/issue-71406.rs +ui/issues/issue-71676-suggest-deref/issue-71676-1.rs +ui/issues/issue-71676-suggest-deref/issue-71676-2.rs +ui/issues/issue-7178.rs +ui/issues/issue-72002.rs +ui/issues/issue-72076.rs +ui/issues/issue-72278.rs +ui/issues/issue-7246.rs +ui/issues/issue-7268.rs +ui/issues/issue-72839-error-overflow.rs +ui/issues/issue-72933-match-stack-overflow.rs +ui/issues/issue-73112.rs +ui/issues/issue-73229.rs +ui/issues/issue-7344.rs +ui/issues/issue-7364.rs +ui/issues/issue-74082.rs +ui/issues/issue-74564-if-expr-stack-overflow.rs +ui/issues/issue-7519-match-unit-in-arg.rs +ui/issues/issue-75283.rs +ui/issues/issue-7563.rs +ui/issues/issue-75704.rs +ui/issues/issue-7575.rs +ui/issues/issue-76042.rs +ui/issues/issue-7607-1.rs +ui/issues/issue-7607-2.rs +ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs +ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs +ui/issues/issue-76191.rs +ui/issues/issue-7660.rs +ui/issues/issue-7663.rs +ui/issues/issue-7673-cast-generically-implemented-trait.rs +ui/issues/issue-77218/issue-77218-2.rs +ui/issues/issue-77218/issue-77218.rs +ui/issues/issue-7784.rs +ui/issues/issue-77919.rs +ui/issues/issue-78192.rs +ui/issues/issue-78622.rs +ui/issues/issue-7867.rs +ui/issues/issue-78957.rs +ui/issues/issue-7899.rs +ui/issues/issue-7911.rs +ui/issues/issue-7970a.rs +ui/issues/issue-8044.rs +ui/issues/issue-80607.rs +ui/issues/issue-81584.rs +ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs +ui/issues/issue-81918.rs +ui/issues/issue-8248.rs +ui/issues/issue-8249.rs +ui/issues/issue-8259.rs +ui/issues/issue-83048.rs +ui/issues/issue-8391.rs +ui/issues/issue-8398.rs +ui/issues/issue-8401.rs +ui/issues/issue-8498.rs +ui/issues/issue-8506.rs +ui/issues/issue-8521.rs +ui/issues/issue-85461.rs +ui/issues/issue-8578.rs +ui/issues/issue-86756.rs +ui/issues/issue-87199.rs +ui/issues/issue-8727.rs +ui/issues/issue-87490.rs +ui/issues/issue-8761.rs +ui/issues/issue-8767.rs +ui/issues/issue-87707.rs +ui/issues/issue-8783.rs +ui/issues/issue-88150.rs +ui/issues/issue-8860.rs +ui/issues/issue-8898.rs +ui/issues/issue-9047.rs +ui/issues/issue-9110.rs +ui/issues/issue-9123.rs +ui/issues/issue-9129.rs +ui/issues/issue-91489.rs +ui/issues/issue-9155.rs +ui/issues/issue-9188.rs +ui/issues/issue-9243.rs +ui/issues/issue-9249.rs +ui/issues/issue-9259.rs +ui/issues/issue-92741.rs +ui/issues/issue-9382.rs +ui/issues/issue-9446.rs +ui/issues/issue-9575.rs +ui/issues/issue-9719.rs +ui/issues/issue-9725.rs +ui/issues/issue-9737.rs +ui/issues/issue-9814.rs +ui/issues/issue-98299.rs +ui/issues/issue-9837.rs +ui/issues/issue-9906.rs +ui/issues/issue-9918.rs +ui/issues/issue-9942.rs +ui/issues/issue-9951.rs +ui/issues/issue-9968.rs +ui/issues/issue-99838.rs +ui/iterators/issue-28098.rs +ui/iterators/issue-58952-filter-type-length.rs +ui/lang-items/issue-19660.rs +ui/lang-items/issue-83471.rs +ui/lang-items/issue-87573.rs +ui/late-bound-lifetimes/issue-36381.rs +ui/late-bound-lifetimes/issue-47511.rs +ui/late-bound-lifetimes/issue-80618.rs +ui/layout/issue-112048-unsizing-field-order.rs +ui/layout/issue-112048-unsizing-niche.rs +ui/layout/issue-113941.rs +ui/layout/issue-60431-unsized-tail-behind-projection.rs +ui/layout/issue-84108.rs +ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs +ui/layout/issue-96185-overaligned-enum.rs +ui/let-else/issue-100103.rs +ui/let-else/issue-102317.rs +ui/let-else/issue-94176.rs +ui/let-else/issue-99975.rs +ui/lifetimes/auxiliary/issue-91763-aux.rs +ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs +ui/lifetimes/issue-104432-unused-lifetimes-in-expansion.rs +ui/lifetimes/issue-105227.rs +ui/lifetimes/issue-105507.rs +ui/lifetimes/issue-105675.rs +ui/lifetimes/issue-107492-default-value-for-lifetime.rs +ui/lifetimes/issue-107988.rs +ui/lifetimes/issue-17728.rs +ui/lifetimes/issue-19707.rs +ui/lifetimes/issue-26638.rs +ui/lifetimes/issue-34979.rs +ui/lifetimes/issue-36744-without-calls.rs +ui/lifetimes/issue-54378.rs +ui/lifetimes/issue-55796.rs +ui/lifetimes/issue-64173-unused-lifetimes.rs +ui/lifetimes/issue-67498.rs +ui/lifetimes/issue-69314.rs +ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs +ui/lifetimes/issue-76168-hr-outlives-2.rs +ui/lifetimes/issue-76168-hr-outlives-3.rs +ui/lifetimes/issue-76168-hr-outlives.rs +ui/lifetimes/issue-77175.rs +ui/lifetimes/issue-79187-2.rs +ui/lifetimes/issue-79187.rs +ui/lifetimes/issue-83737-binders-across-types.rs +ui/lifetimes/issue-83737-erasing-bound-vars.rs +ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs +ui/lifetimes/issue-83907-invalid-fn-like-path.rs +ui/lifetimes/issue-84398.rs +ui/lifetimes/issue-84604.rs +ui/lifetimes/issue-90170-elision-mismatch.rs +ui/lifetimes/issue-90600-expected-return-static-indirect.rs +ui/lifetimes/issue-91763.rs +ui/lifetimes/issue-93911.rs +ui/lifetimes/issue-95023.rs +ui/lifetimes/issue-97193.rs +ui/lifetimes/issue-97194.rs +ui/lifetimes/lifetime-errors/issue_74400.rs +ui/limits/issue-15919-32.rs +ui/limits/issue-15919-64.rs +ui/limits/issue-17913.rs +ui/limits/issue-55878.rs +ui/limits/issue-56762.rs +ui/limits/issue-69485-var-size-diffs-too-large.rs +ui/limits/issue-75158-64.rs +ui/linkage-attr/auxiliary/issue-12133-dylib.rs +ui/linkage-attr/auxiliary/issue-12133-dylib2.rs +ui/linkage-attr/auxiliary/issue-12133-rlib.rs +ui/linkage-attr/issue-10755.rs +ui/linkage-attr/issue-109144.rs +ui/linkage-attr/issue-12133-1.rs +ui/linkage-attr/issue-12133-2.rs +ui/linkage-attr/issue-12133-3.rs +ui/lint/dead-code/issue-41883.rs +ui/lint/dead-code/issue-59003.rs +ui/lint/dead-code/issue-68408-false-positive.rs +ui/lint/dead-code/issue-85071-2.rs +ui/lint/dead-code/issue-85071.rs +ui/lint/dead-code/issue-85255.rs +ui/lint/issue-101284.rs +ui/lint/issue-102705.rs +ui/lint/issue-103317.rs +ui/lint/issue-103435-extra-parentheses.rs +ui/lint/issue-104392.rs +ui/lint/issue-104897.rs +ui/lint/issue-106991.rs +ui/lint/issue-108155.rs +ui/lint/issue-109152.rs +ui/lint/issue-109529.rs +ui/lint/issue-110573.rs +ui/lint/issue-111359.rs +ui/lint/issue-112489.rs +ui/lint/issue-117949.rs +ui/lint/issue-121070-let-range.rs +ui/lint/issue-14309.rs +ui/lint/issue-14837.rs +ui/lint/issue-17718-const-naming.rs +ui/lint/issue-1866.rs +ui/lint/issue-19102.rs +ui/lint/issue-20343.rs +ui/lint/issue-30302.rs +ui/lint/issue-31924-non-snake-ffi.rs +ui/lint/issue-34798.rs +ui/lint/issue-35075.rs +ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs +ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs +ui/lint/issue-54099-camel-case-underscore-types.rs +ui/lint/issue-57410-1.rs +ui/lint/issue-57410.rs +ui/lint/issue-63364.rs +ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs +ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs +ui/lint/issue-79546-fuel-ice.rs +ui/lint/issue-79744.rs +ui/lint/issue-80988.rs +ui/lint/issue-81218.rs +ui/lint/issue-83477.rs +ui/lint/issue-87274-paren-parent.rs +ui/lint/issue-89469.rs +ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs +ui/lint/issue-97094.rs +ui/lint/issue-99387.rs +ui/lint/let_underscore/issue-119696-err-on-fn.rs +ui/lint/let_underscore/issue-119697-extra-let.rs +ui/lint/must_not_suspend/issue-89562.rs +ui/lint/unused/issue-103320-must-use-ops.rs +ui/lint/unused/issue-104397.rs +ui/lint/unused/issue-105061-array-lint.rs +ui/lint/unused/issue-105061-should-lint.rs +ui/lint/unused/issue-105061.rs +ui/lint/unused/issue-117142-invalid-remove-parens.rs +ui/lint/unused/issue-117284-arg-in-macro.rs +ui/lint/unused/issue-119383-if-let-guard.rs +ui/lint/unused/issue-30730.rs +ui/lint/unused/issue-46576.rs +ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs +ui/lint/unused/issue-54180-unused-ref-field.rs +ui/lint/unused/issue-54538-unused-parens-lint.rs +ui/lint/unused/issue-59896.rs +ui/lint/unused/issue-67691-unused-field-in-or-pattern.rs +ui/lint/unused/issue-70041.rs +ui/lint/unused/issue-71290-unused-paren-binop.rs +ui/lint/unused/issue-74883-unused-paren-baren-yield.rs +ui/lint/unused/issue-81314-unused-span-ident.rs +ui/lint/unused/issue-85913.rs +ui/lint/unused/issue-88519-unused-paren.rs +ui/lint/unused/issue-90807-unused-paren-error.rs +ui/lint/unused/issue-90807-unused-paren.rs +ui/lint/unused/issue-92751.rs +ui/lint/unused/issue-96606.rs +ui/lint/use-redundant/issue-92904.rs +ui/loops/issue-1962.rs +ui/loops/issue-1974.rs +ui/loops/issue-43162.rs +ui/loops/issue-50576.rs +ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs +ui/loops/issue-69225-layout-repeated-checked-add.rs +ui/loops/issue-82916.rs +ui/lowering/issue-121108.rs +ui/lowering/issue-96847.rs +ui/lto/issue-100772.rs +ui/lto/issue-105637.rs +ui/lto/issue-11154.rs +ui/macros/auxiliary/issue-100199.rs +ui/macros/auxiliary/issue-19163.rs +ui/macros/auxiliary/issue-40469.rs +ui/macros/auxiliary/issue-75982.rs +ui/macros/issue-100199.rs +ui/macros/issue-102878.rs +ui/macros/issue-103529.rs +ui/macros/issue-104769-concat_bytes-invalid-literal.rs +ui/macros/issue-105011.rs +ui/macros/issue-10536.rs +ui/macros/issue-106837.rs +ui/macros/issue-109237.rs +ui/macros/issue-111749.rs +ui/macros/issue-112342-1.rs +ui/macros/issue-112342-2.rs +ui/macros/issue-118048.rs +ui/macros/issue-118786.rs +ui/macros/issue-16098.rs +ui/macros/issue-19163.rs +ui/macros/issue-21356.rs +ui/macros/issue-22463.rs +ui/macros/issue-25274.rs +ui/macros/issue-25385.rs +ui/macros/issue-26094.rs +ui/macros/issue-26322.rs +ui/macros/issue-2804-2.rs +ui/macros/issue-2804.rs +ui/macros/issue-29084.rs +ui/macros/issue-30007.rs +ui/macros/issue-30143.rs +ui/macros/issue-33185.rs +ui/macros/issue-34171.rs +ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs +ui/macros/issue-35450.rs +ui/macros/issue-37175.rs +ui/macros/issue-38715.rs +ui/macros/issue-39388.rs +ui/macros/issue-39404.rs +ui/macros/issue-39467.rs +ui/macros/issue-40469.rs +ui/macros/issue-40770.rs +ui/macros/issue-41776.rs +ui/macros/issue-41803.rs +ui/macros/issue-42954.rs +ui/macros/issue-44127.rs +ui/macros/issue-46438.rs +ui/macros/issue-5060.rs +ui/macros/issue-51848.rs +ui/macros/issue-52169.rs +ui/macros/issue-54441.rs +ui/macros/issue-57597.rs +ui/macros/issue-58490.rs +ui/macros/issue-61033-1.rs +ui/macros/issue-61033-2.rs +ui/macros/issue-61053-different-kleene.rs +ui/macros/issue-61053-duplicate-binder.rs +ui/macros/issue-61053-missing-repetition.rs +ui/macros/issue-61053-unbound.rs +ui/macros/issue-63102.rs +ui/macros/issue-6596-1.rs +ui/macros/issue-6596-2.rs +ui/macros/issue-68058.rs +ui/macros/issue-68060.rs +ui/macros/issue-69396-const-no-type-in-macro.rs +ui/macros/issue-69838-mods-relative-to-included-path.rs +ui/macros/issue-70446.rs +ui/macros/issue-75982-foreign-macro-weird-mod.rs +ui/macros/issue-77475.rs +ui/macros/issue-78325-inconsistent-resolution.rs +ui/macros/issue-78333.rs +ui/macros/issue-78892-substitution-in-statement-attr.rs +ui/macros/issue-81006.rs +ui/macros/issue-83340.rs +ui/macros/issue-83344.rs +ui/macros/issue-84195-lint-anon-const.rs +ui/macros/issue-84429-matches-edition.rs +ui/macros/issue-84632-eager-expansion-recursion-limit.rs +ui/macros/issue-86082-option-env-invalid-char.rs +ui/macros/issue-86865.rs +ui/macros/issue-8709.rs +ui/macros/issue-87877.rs +ui/macros/issue-88206.rs +ui/macros/issue-88228.rs +ui/macros/issue-8851.rs +ui/macros/issue-92267.rs +ui/macros/issue-95267.rs +ui/macros/issue-95533.rs +ui/macros/issue-98466-allow.rs +ui/macros/issue-98466.rs +ui/macros/issue-98790.rs +ui/macros/issue-99261.rs +ui/macros/issue-99265.rs +ui/macros/issue-99907.rs +ui/macros/rfc-3086-metavar-expr/issue-111904.rs +ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs +ui/malformed/issue-69341-malformed-derive-inert.rs +ui/marker_trait_attr/issue-61651-type-mismatch.rs +ui/match/issue-112438.rs +ui/match/issue-113012.rs +ui/match/issue-11319.rs +ui/match/issue-114691.rs +ui/match/issue-115681.rs +ui/match/issue-11940.rs +ui/match/issue-12552.rs +ui/match/issue-18060.rs +ui/match/issue-26251.rs +ui/match/issue-26996.rs +ui/match/issue-27021.rs +ui/match/issue-33498.rs +ui/match/issue-36401.rs +ui/match/issue-37598.rs +ui/match/issue-42679.rs +ui/match/issue-46920-byte-array-patterns.rs +ui/match/issue-5530.rs +ui/match/issue-56685.rs +ui/match/issue-70972-dyn-trait.rs +ui/match/issue-72680.rs +ui/match/issue-72896-non-partial-eq-const.rs +ui/match/issue-74050-end-span.rs +ui/match/issue-82392.rs +ui/match/issue-82866.rs +ui/match/issue-84434.rs +ui/match/issue-91058.rs +ui/match/issue-92100.rs +ui/methods/issue-19521.rs +ui/methods/issue-3707.rs +ui/methods/issue-7950.rs +ui/methods/issues/issue-105732.rs +ui/methods/issues/issue-61525.rs +ui/methods/issues/issue-84495.rs +ui/methods/issues/issue-90315.rs +ui/methods/issues/issue-94581.rs +ui/mir/auxiliary/issue_76375_aux.rs +ui/mir/issue-101844.rs +ui/mir/issue-102389.rs +ui/mir/issue-105809.rs +ui/mir/issue-106062.rs +ui/mir/issue-107678-projection-with-lifetime.rs +ui/mir/issue-107691.rs +ui/mir/issue-109004-drop-large-array.rs +ui/mir/issue-109743.rs +ui/mir/issue-112269.rs +ui/mir/issue-121103.rs +ui/mir/issue-29227.rs +ui/mir/issue-46845.rs +ui/mir/issue-60390.rs +ui/mir/issue-66851.rs +ui/mir/issue-66930.rs +ui/mir/issue-67639-normalization-ice.rs +ui/mir/issue-67710-inline-projection.rs +ui/mir/issue-67947.rs +ui/mir/issue-68841.rs +ui/mir/issue-71793-inline-args-storage.rs +ui/mir/issue-73914.rs +ui/mir/issue-74739.rs +ui/mir/issue-75053.rs +ui/mir/issue-75419-validation-impl-trait.rs +ui/mir/issue-76248.rs +ui/mir/issue-76375.rs +ui/mir/issue-76740-copy-propagation.rs +ui/mir/issue-76803-branches-not-same.rs +ui/mir/issue-77002.rs +ui/mir/issue-77359-simplify-arm-identity.rs +ui/mir/issue-77911.rs +ui/mir/issue-78496.rs +ui/mir/issue-80949.rs +ui/mir/issue-83499-input-output-iteration-ice.rs +ui/mir/issue-89485.rs +ui/mir/issue-91745.rs +ui/mir/issue-92893.rs +ui/mir/issue-99852.rs +ui/mir/issue-99866.rs +ui/mir/issue66339.rs +ui/mir/validate/issue-95978-validator-lifetime-comparison.rs +ui/mismatched_types/issue-106182.rs +ui/mismatched_types/issue-112036.rs +ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs +ui/mismatched_types/issue-118510.rs +ui/mismatched_types/issue-13033.rs +ui/mismatched_types/issue-1362.rs +ui/mismatched_types/issue-1448-2.rs +ui/mismatched_types/issue-19109.rs +ui/mismatched_types/issue-26480.rs +ui/mismatched_types/issue-35030.rs +ui/mismatched_types/issue-36053-2.rs +ui/mismatched_types/issue-38371-unfixable.rs +ui/mismatched_types/issue-38371.rs +ui/mismatched_types/issue-47706-trait.rs +ui/mismatched_types/issue-47706.rs +ui/mismatched_types/issue-74918-missing-lifetime.rs +ui/mismatched_types/issue-75361-mismatched-impl.rs +ui/mismatched_types/issue-84976.rs +ui/missing-trait-bounds/auxiliary/issue-69725.rs +ui/missing-trait-bounds/issue-35677.rs +ui/missing-trait-bounds/issue-69725.rs +ui/modules/auxiliary/issue-13872-1.rs +ui/modules/auxiliary/issue-13872-2.rs +ui/modules/auxiliary/issue-13872-3.rs +ui/modules/auxiliary/issue-1920.rs +ui/modules/issue-107649.rs +ui/modules/issue-13872.rs +ui/modules/issue-1920-1.rs +ui/modules/issue-1920-2.rs +ui/modules/issue-1920-3.rs +ui/modules/issue-56411-aux.rs +ui/modules/issue-56411.rs +ui/moves/issue-22536-copy-mustnt-zero.rs +ui/moves/issue-34721.rs +ui/moves/issue-46099-move-in-macro.rs +ui/moves/issue-72649-uninit-in-loop.rs +ui/moves/issue-75904-move-closure-loop.rs +ui/moves/issue-99470-move-out-of-some.rs +ui/never_type/issue-10176.rs +ui/never_type/issue-13352.rs +ui/never_type/issue-2149.rs +ui/never_type/issue-44402.rs +ui/never_type/issue-51506.rs +ui/never_type/issue-52443.rs +ui/never_type/issue-5500-1.rs +ui/never_type/issue-96335.rs +ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs +ui/nll/issue-112604-closure-output-normalize.rs +ui/nll/issue-16223.rs +ui/nll/issue-21114-ebfull.rs +ui/nll/issue-21114-kixunil.rs +ui/nll/issue-21232-partial-init-and-erroneous-use.rs +ui/nll/issue-21232-partial-init-and-use.rs +ui/nll/issue-22323-temp-destruction.rs +ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs +ui/nll/issue-27282-move-match-input-into-guard.rs +ui/nll/issue-27282-move-ref-mut-into-guard.rs +ui/nll/issue-27282-mutate-before-diverging-arm-1.rs +ui/nll/issue-27282-mutate-before-diverging-arm-2.rs +ui/nll/issue-27282-mutate-before-diverging-arm-3.rs +ui/nll/issue-27282-mutation-in-guard.rs +ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs +ui/nll/issue-27583.rs +ui/nll/issue-27868.rs +ui/nll/issue-30104.rs +ui/nll/issue-30438-a.rs +ui/nll/issue-30438-b.rs +ui/nll/issue-30438-c.rs +ui/nll/issue-31567.rs +ui/nll/issue-32382-index-assoc-type-with-lifetime.rs +ui/nll/issue-40510-1.rs +ui/nll/issue-40510-2.rs +ui/nll/issue-40510-3.rs +ui/nll/issue-40510-4.rs +ui/nll/issue-42574-diagnostic-in-nested-closure.rs +ui/nll/issue-43058.rs +ui/nll/issue-45157.rs +ui/nll/issue-45696-long-live-borrows-in-boxes.rs +ui/nll/issue-45696-no-variant-box-recur.rs +ui/nll/issue-45696-scribble-on-boxed-borrow.rs +ui/nll/issue-46023.rs +ui/nll/issue-46036.rs +ui/nll/issue-46589.rs +ui/nll/issue-47022.rs +ui/nll/issue-47153-generic-const.rs +ui/nll/issue-47388.rs +ui/nll/issue-47470.rs +ui/nll/issue-47589.rs +ui/nll/issue-48070.rs +ui/nll/issue-48179.rs +ui/nll/issue-48238.rs +ui/nll/issue-48623-closure.rs +ui/nll/issue-48623-coroutine.rs +ui/nll/issue-48697.rs +ui/nll/issue-48803.rs +ui/nll/issue-50343.rs +ui/nll/issue-50461-used-mut-from-moves.rs +ui/nll/issue-50716-1.rs +ui/nll/issue-50716.rs +ui/nll/issue-51191.rs +ui/nll/issue-51244.rs +ui/nll/issue-51268.rs +ui/nll/issue-51345-2.rs +ui/nll/issue-51351.rs +ui/nll/issue-51512.rs +ui/nll/issue-51770.rs +ui/nll/issue-52057.rs +ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs +ui/nll/issue-52078.rs +ui/nll/issue-52086.rs +ui/nll/issue-52113.rs +ui/nll/issue-52213.rs +ui/nll/issue-52533-1.rs +ui/nll/issue-52534-1.rs +ui/nll/issue-52534-2.rs +ui/nll/issue-52534.rs +ui/nll/issue-52663-span-decl-captured-variable.rs +ui/nll/issue-52663-trait-object.rs +ui/nll/issue-52669.rs +ui/nll/issue-52742.rs +ui/nll/issue-52992.rs +ui/nll/issue-53040.rs +ui/nll/issue-53119.rs +ui/nll/issue-53123-raw-pointer-cast.rs +ui/nll/issue-53570.rs +ui/nll/issue-53773.rs +ui/nll/issue-53807.rs +ui/nll/issue-54189.rs +ui/nll/issue-54302-cases.rs +ui/nll/issue-54302.rs +ui/nll/issue-54382-use-span-of-tail-of-block.rs +ui/nll/issue-54556-niconii.rs +ui/nll/issue-54556-stephaneyfx.rs +ui/nll/issue-54556-temps-in-tail-diagnostic.rs +ui/nll/issue-54556-used-vs-unused-tails.rs +ui/nll/issue-54556-wrap-it-up.rs +ui/nll/issue-54779-anon-static-lifetime.rs +ui/nll/issue-54943-3.rs +ui/nll/issue-54943.rs +ui/nll/issue-55288.rs +ui/nll/issue-55344.rs +ui/nll/issue-55394.rs +ui/nll/issue-55401.rs +ui/nll/issue-55511.rs +ui/nll/issue-55651.rs +ui/nll/issue-55825-const-fn.rs +ui/nll/issue-55850.rs +ui/nll/issue-57100.rs +ui/nll/issue-57265-return-type-wf-check.rs +ui/nll/issue-57280-1-flipped.rs +ui/nll/issue-57280-1.rs +ui/nll/issue-57280.rs +ui/nll/issue-57642-higher-ranked-subtype.rs +ui/nll/issue-57843.rs +ui/nll/issue-57960.rs +ui/nll/issue-57989.rs +ui/nll/issue-58053.rs +ui/nll/issue-58299.rs +ui/nll/issue-61311-normalize.rs +ui/nll/issue-61320-normalize.rs +ui/nll/issue-61424.rs +ui/nll/issue-62007-assign-const-index.rs +ui/nll/issue-62007-assign-differing-fields.rs +ui/nll/issue-63154-normalize.rs +ui/nll/issue-67007-escaping-data.rs +ui/nll/issue-68550.rs +ui/nll/issue-69114-static-mut-ty.rs +ui/nll/issue-69114-static-ty.rs +ui/nll/issue-73159-rpit-static.rs +ui/nll/issue-75777.rs +ui/nll/issue-78561.rs +ui/nll/issue-95272.rs +ui/nll/issue-97997.rs +ui/nll/issue-98170.rs +ui/nll/issue-98589-closures-relate-named-regions.rs +ui/nll/issue-98693.rs +ui/nll/polonius/issue-46589.rs +ui/nll/relate_tys/issue-48071.rs +ui/nll/ty-outlives/issue-53789-1.rs +ui/nll/ty-outlives/issue-53789-2.rs +ui/nll/ty-outlives/issue-55756.rs +ui/nll/user-annotations/issue-54124.rs +ui/nll/user-annotations/issue-54570-bootstrapping.rs +ui/nll/user-annotations/issue-55219.rs +ui/nll/user-annotations/issue-55241.rs +ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs +ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs +ui/numbers-arithmetic/issue-105626.rs +ui/numbers-arithmetic/issue-8460.rs +ui/object-safety/issue-102762.rs +ui/object-safety/issue-102933.rs +ui/object-safety/issue-106247.rs +ui/object-safety/issue-19538.rs +ui/on-unimplemented/issue-104140.rs +ui/or-patterns/issue-64879-trailing-before-guard.rs +ui/or-patterns/issue-67514-irrefutable-param.rs +ui/or-patterns/issue-68785-irrefutable-param-with-at.rs +ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs +ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs +ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs +ui/overloaded/issue-14958.rs +ui/packed/issue-118537-field-offset-ice.rs +ui/packed/issue-118537-field-offset.rs +ui/packed/issue-27060-2.rs +ui/packed/issue-27060.rs +ui/packed/issue-46152.rs +ui/panics/issue-47429-short-backtraces.rs +ui/parser/issue-116781.rs +ui/parser/issues/auxiliary/issue-21146-inc.rs +ui/parser/issues/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs +ui/parser/issues/auxiliary/issue-94340-inc.rs +ui/parser/issues/issue-100197-mut-let.rs +ui/parser/issues/issue-101477-enum.rs +ui/parser/issues/issue-101477-let.rs +ui/parser/issues/issue-101540.rs +ui/parser/issues/issue-102182-impl-trait-recover.rs +ui/parser/issues/issue-102806.rs +ui/parser/issues/issue-103143.rs +ui/parser/issues/issue-103381.rs +ui/parser/issues/issue-103425.rs +ui/parser/issues/issue-103451.rs +ui/parser/issues/issue-103748-ICE-wrong-braces.rs +ui/parser/issues/issue-10392-2.rs +ui/parser/issues/issue-10392.rs +ui/parser/issues/issue-104367.rs +ui/parser/issues/issue-104620.rs +ui/parser/issues/issue-104867-inc-dec-2.rs +ui/parser/issues/issue-104867-inc-dec.rs +ui/parser/issues/issue-105209.rs +ui/parser/issues/issue-105366.rs +ui/parser/issues/issue-105634.rs +ui/parser/issues/issue-10636-1.rs +ui/parser/issues/issue-10636-2.rs +ui/parser/issues/issue-107705.rs +ui/parser/issues/issue-108109-fn-missing-params.rs +ui/parser/issues/issue-108109-fn-trait-missing-paren.rs +ui/parser/issues/issue-108242-semicolon-recovery.rs +ui/parser/issues/issue-108495-dec.rs +ui/parser/issues/issue-110014.rs +ui/parser/issues/issue-111148.rs +ui/parser/issues/issue-111416.rs +ui/parser/issues/issue-111692.rs +ui/parser/issues/issue-112188.rs +ui/parser/issues/issue-112458.rs +ui/parser/issues/issue-113110-non-item-at-module-root.rs +ui/parser/issues/issue-113203.rs +ui/parser/issues/issue-113342.rs +ui/parser/issues/issue-114219.rs +ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs +ui/parser/issues/issue-118530-ice.rs +ui/parser/issues/issue-118531-ice.rs +ui/parser/issues/issue-13483.rs +ui/parser/issues/issue-14303-fncall.rs +ui/parser/issues/issue-14303.rs +ui/parser/issues/issue-15914.rs +ui/parser/issues/issue-15980.rs +ui/parser/issues/issue-1655.rs +ui/parser/issues/issue-17718-const-mut.rs +ui/parser/issues/issue-17718-parse-const.rs +ui/parser/issues/issue-17904-2.rs +ui/parser/issues/issue-17904.rs +ui/parser/issues/issue-1802-1.rs +ui/parser/issues/issue-1802-2.rs +ui/parser/issues/issue-19096.rs +ui/parser/issues/issue-19398.rs +ui/parser/issues/issue-20616-1.rs +ui/parser/issues/issue-20616-2.rs +ui/parser/issues/issue-20616-3.rs +ui/parser/issues/issue-20616-4.rs +ui/parser/issues/issue-20616-5.rs +ui/parser/issues/issue-20616-6.rs +ui/parser/issues/issue-20616-7.rs +ui/parser/issues/issue-20616-8.rs +ui/parser/issues/issue-20616-9.rs +ui/parser/issues/issue-20711-2.rs +ui/parser/issues/issue-20711.rs +ui/parser/issues/issue-21146.rs +ui/parser/issues/issue-21153.rs +ui/parser/issues/issue-21475.rs +ui/parser/issues/issue-22647.rs +ui/parser/issues/issue-22712.rs +ui/parser/issues/issue-2354-1.rs +ui/parser/issues/issue-2354.rs +ui/parser/issues/issue-23620-invalid-escapes.rs +ui/parser/issues/issue-24197.rs +ui/parser/issues/issue-24375.rs +ui/parser/issues/issue-24780.rs +ui/parser/issues/issue-27255.rs +ui/parser/issues/issue-30318.rs +ui/parser/issues/issue-3036.rs +ui/parser/issues/issue-31804.rs +ui/parser/issues/issue-32214.rs +ui/parser/issues/issue-32446.rs +ui/parser/issues/issue-32501.rs +ui/parser/issues/issue-32505.rs +ui/parser/issues/issue-33262.rs +ui/parser/issues/issue-33413.rs +ui/parser/issues/issue-33418.rs +ui/parser/issues/issue-33455.rs +ui/parser/issues/issue-34222-1.rs +ui/parser/issues/issue-34255-1.rs +ui/parser/issues/issue-35813-postfix-after-cast.rs +ui/parser/issues/issue-39616.rs +ui/parser/issues/issue-41155.rs +ui/parser/issues/issue-43196.rs +ui/parser/issues/issue-43692.rs +ui/parser/issues/issue-44021.rs +ui/parser/issues/issue-44406.rs +ui/parser/issues/issue-45296.rs +ui/parser/issues/issue-46186.rs +ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs +ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items.rs +ui/parser/issues/issue-48508-aux.rs +ui/parser/issues/issue-48508.rs +ui/parser/issues/issue-48636.rs +ui/parser/issues/issue-49040.rs +ui/parser/issues/issue-49257.rs +ui/parser/issues/issue-51602.rs +ui/parser/issues/issue-52496.rs +ui/parser/issues/issue-54521-1.rs +ui/parser/issues/issue-54521-2.rs +ui/parser/issues/issue-54521-3.rs +ui/parser/issues/issue-5544-a.rs +ui/parser/issues/issue-5544-b.rs +ui/parser/issues/issue-56031.rs +ui/parser/issues/issue-57198.rs +ui/parser/issues/issue-57684.rs +ui/parser/issues/issue-57819.rs +ui/parser/issues/issue-5806.rs +ui/parser/issues/issue-58094-missing-right-square-bracket.rs +ui/parser/issues/issue-58856-1.rs +ui/parser/issues/issue-58856-2.rs +ui/parser/issues/issue-59418.rs +ui/parser/issues/issue-60075.rs +ui/parser/issues/issue-61858.rs +ui/parser/issues/issue-62524.rs +ui/parser/issues/issue-62546.rs +ui/parser/issues/issue-62554.rs +ui/parser/issues/issue-62660.rs +ui/parser/issues/issue-62881.rs +ui/parser/issues/issue-62894.rs +ui/parser/issues/issue-62895.rs +ui/parser/issues/issue-62913.rs +ui/parser/issues/issue-62973.rs +ui/parser/issues/issue-63115-range-pat-interpolated.rs +ui/parser/issues/issue-63116.rs +ui/parser/issues/issue-63135.rs +ui/parser/issues/issue-64732.rs +ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs +ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs +ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs +ui/parser/issues/issue-65257-invalid-var-decl-recovery.rs +ui/parser/issues/issue-65846-rollback-gating-failing-matcher.rs +ui/parser/issues/issue-6610.rs +ui/parser/issues/issue-66357-unexpected-unreachable.rs +ui/parser/issues/issue-66473.rs +ui/parser/issues/issue-67146-negative-outlives-bound-syntactic-fail.rs +ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs +ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.rs +ui/parser/issues/issue-68091-unicode-ident-after-if.rs +ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs +ui/parser/issues/issue-68629.rs +ui/parser/issues/issue-68730.rs +ui/parser/issues/issue-68788-in-trait-item-propagation.rs +ui/parser/issues/issue-68890-2.rs +ui/parser/issues/issue-68890.rs +ui/parser/issues/issue-68987-unmatch-issue-1.rs +ui/parser/issues/issue-68987-unmatch-issue-2.rs +ui/parser/issues/issue-68987-unmatch-issue-3.rs +ui/parser/issues/issue-68987-unmatch-issue.rs +ui/parser/issues/issue-69259.rs +ui/parser/issues/issue-70050-ntliteral-accepts-negated-lit.rs +ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.rs +ui/parser/issues/issue-70388-without-witness.rs +ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.rs +ui/parser/issues/issue-70552-ascription-in-parens-after-call.rs +ui/parser/issues/issue-70583-block-is-empty-1.rs +ui/parser/issues/issue-70583-block-is-empty-2.rs +ui/parser/issues/issue-7222.rs +ui/parser/issues/issue-72253.rs +ui/parser/issues/issue-72373.rs +ui/parser/issues/issue-73568-lifetime-after-mut.rs +ui/parser/issues/issue-75599.rs +ui/parser/issues/issue-76437-async.rs +ui/parser/issues/issue-76437-const-async-unsafe.rs +ui/parser/issues/issue-76437-const-async.rs +ui/parser/issues/issue-76437-const.rs +ui/parser/issues/issue-76437-pub-crate-unsafe.rs +ui/parser/issues/issue-76437-unsafe.rs +ui/parser/issues/issue-76597.rs +ui/parser/issues/issue-7970b.rs +ui/parser/issues/issue-81804.rs +ui/parser/issues/issue-81806.rs +ui/parser/issues/issue-81827.rs +ui/parser/issues/issue-83639.rs +ui/parser/issues/issue-84104.rs +ui/parser/issues/issue-84117.rs +ui/parser/issues/issue-84148-1.rs +ui/parser/issues/issue-84148-2.rs +ui/parser/issues/issue-8537.rs +ui/parser/issues/issue-86895.rs +ui/parser/issues/issue-87086-colon-path-sep.rs +ui/parser/issues/issue-87197-missing-semicolon.rs +ui/parser/issues/issue-87635.rs +ui/parser/issues/issue-87694-duplicated-pub.rs +ui/parser/issues/issue-87694-misplaced-pub.rs +ui/parser/issues/issue-87812-path.rs +ui/parser/issues/issue-87812.rs +ui/parser/issues/issue-88276-unary-plus.rs +ui/parser/issues/issue-88583-union-as-ident.rs +ui/parser/issues/issue-88770.rs +ui/parser/issues/issue-88818.rs +ui/parser/issues/issue-89388.rs +ui/parser/issues/issue-89396.rs +ui/parser/issues/issue-89574.rs +ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs +ui/parser/issues/issue-90728.rs +ui/parser/issues/issue-90993.rs +ui/parser/issues/issue-91421.rs +ui/parser/issues/issue-91461.rs +ui/parser/issues/issue-93282.rs +ui/parser/issues/issue-93867.rs +ui/parser/issues/issue-94340.rs +ui/parser/issues/issue-98601-delimiter-error-1.rs +ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs +ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.rs +ui/parser/issues/issue-99910-const-let-mutually-exclusive.rs +ui/parser/macro/issue-33569.rs +ui/parser/macro/issue-37113.rs +ui/parser/macro/issue-37234.rs +ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs +ui/parser/shebang/issue-71471-ignore-tidy.rs +ui/pattern/issue-10392.rs +ui/pattern/issue-106552.rs +ui/pattern/issue-106862.rs +ui/pattern/issue-110508.rs +ui/pattern/issue-115599.rs +ui/pattern/issue-11577.rs +ui/pattern/issue-117626.rs +ui/pattern/issue-12582.rs +ui/pattern/issue-14221.rs +ui/pattern/issue-15080.rs +ui/pattern/issue-17718-patterns.rs +ui/pattern/issue-22546.rs +ui/pattern/issue-27320.rs +ui/pattern/issue-28992-empty.rs +ui/pattern/issue-52240.rs +ui/pattern/issue-6449.rs +ui/pattern/issue-66270-pat-struct-parser-recovery.rs +ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs +ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs +ui/pattern/issue-68393-let-pat-assoc-constant.rs +ui/pattern/issue-72565.rs +ui/pattern/issue-72574-1.rs +ui/pattern/issue-72574-2.rs +ui/pattern/issue-74539.rs +ui/pattern/issue-74702.rs +ui/pattern/issue-74954.rs +ui/pattern/issue-80186-mut-binding-help-suggestion.rs +ui/pattern/issue-8351-1.rs +ui/pattern/issue-8351-2.rs +ui/pattern/issue-88074-pat-range-type-inference-err.rs +ui/pattern/issue-88074-pat-range-type-inference.rs +ui/pattern/issue-92074-macro-ice.rs +ui/pattern/issue-94866.rs +ui/pattern/issue-95878.rs +ui/pattern/move-ref-patterns/issue-53840.rs +ui/pattern/usefulness/integer-ranges/issue-117648-overlapping_range_endpoints-false-positive.rs +ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs +ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs +ui/pattern/usefulness/issue-119493-type-error-ice.rs +ui/pattern/usefulness/issue-119778-type-error-ice.rs +ui/pattern/usefulness/issue-12116.rs +ui/pattern/usefulness/issue-12369.rs +ui/pattern/usefulness/issue-13727.rs +ui/pattern/usefulness/issue-15129.rs +ui/pattern/usefulness/issue-2111.rs +ui/pattern/usefulness/issue-30240-b.rs +ui/pattern/usefulness/issue-30240-rpass.rs +ui/pattern/usefulness/issue-30240.rs +ui/pattern/usefulness/issue-3096-1.rs +ui/pattern/usefulness/issue-3096-2.rs +ui/pattern/usefulness/issue-31221.rs +ui/pattern/usefulness/issue-31561.rs +ui/pattern/usefulness/issue-35609.rs +ui/pattern/usefulness/issue-3601.rs +ui/pattern/usefulness/issue-39362.rs +ui/pattern/usefulness/issue-40221.rs +ui/pattern/usefulness/issue-4321.rs +ui/pattern/usefulness/issue-50900.rs +ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs +ui/pattern/usefulness/issue-56379.rs +ui/pattern/usefulness/issue-57472.rs +ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs +ui/pattern/usefulness/issue-66501.rs +ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs +ui/pattern/usefulness/issue-72377.rs +ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs +ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs +ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs +ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs +ui/pattern/usefulness/issue-82772-match-box-as-struct.rs +ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs +ui/pattern/usefulness/issue-88747.rs +ui/polymorphization/issue-74614.rs +ui/polymorphization/issue-74636.rs +ui/privacy/auxiliary/issue-117997.rs +ui/privacy/auxiliary/issue-119463-extern.rs +ui/privacy/auxiliary/issue-17718-const-privacy.rs +ui/privacy/auxiliary/issue-57264-1.rs +ui/privacy/auxiliary/issue-57264-2.rs +ui/privacy/auxiliary/issue-75907.rs +ui/privacy/auxiliary/issue-92755.rs +ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs +ui/privacy/issue-111220-tuple-struct-fields.rs +ui/privacy/issue-113860-1.rs +ui/privacy/issue-113860-2.rs +ui/privacy/issue-113860.rs +ui/privacy/issue-11593.rs +ui/privacy/issue-117997.rs +ui/privacy/issue-119463.rs +ui/privacy/issue-13641.rs +ui/privacy/issue-17718-const-privacy.rs +ui/privacy/issue-29161.rs +ui/privacy/issue-30079.rs +ui/privacy/issue-46209-private-enum-variant-reexport.rs +ui/privacy/issue-57264-1.rs +ui/privacy/issue-57264-2.rs +ui/privacy/issue-75062-fieldless-tuple-struct.rs +ui/privacy/issue-75906.rs +ui/privacy/issue-75907.rs +ui/privacy/issue-75907_b.rs +ui/privacy/issue-79593.rs +ui/privacy/issue-92755.rs +ui/proc-macro/auxiliary/issue-104884.rs +ui/proc-macro/auxiliary/issue-107113.rs +ui/proc-macro/auxiliary/issue-118809.rs +ui/proc-macro/auxiliary/issue-38586.rs +ui/proc-macro/auxiliary/issue-39889.rs +ui/proc-macro/auxiliary/issue-42708.rs +ui/proc-macro/auxiliary/issue-50061.rs +ui/proc-macro/auxiliary/issue-50493.rs +ui/proc-macro/auxiliary/issue-59191.rs +ui/proc-macro/auxiliary/issue-66286.rs +ui/proc-macro/auxiliary/issue-75801.rs +ui/proc-macro/auxiliary/issue-79242.rs +ui/proc-macro/auxiliary/issue-79825.rs +ui/proc-macro/auxiliary/issue-83510.rs +ui/proc-macro/auxiliary/issue-91800-macro.rs +ui/proc-macro/issue-104884-trait-impl-sugg-err.rs +ui/proc-macro/issue-107113-wrap.rs +ui/proc-macro/issue-118455-skip-err-builtin.rs +ui/proc-macro/issue-118809.rs +ui/proc-macro/issue-36935.rs +ui/proc-macro/issue-37788.rs +ui/proc-macro/issue-38586.rs +ui/proc-macro/issue-39889.rs +ui/proc-macro/issue-42708.rs +ui/proc-macro/issue-50061.rs +ui/proc-macro/issue-50493.rs +ui/proc-macro/issue-53481.rs +ui/proc-macro/issue-59191-replace-root-with-fn.rs +ui/proc-macro/issue-66286.rs +ui/proc-macro/issue-73933-procedural-masquerade.rs +ui/proc-macro/issue-75734-pp-paren.rs +ui/proc-macro/issue-75801.rs +ui/proc-macro/issue-75930-derive-cfg.rs +ui/proc-macro/issue-76182-leading-vert-pat.rs +ui/proc-macro/issue-76270-panic-in-libproc-macro.rs +ui/proc-macro/issue-78675-captured-inner-attrs.rs +ui/proc-macro/issue-79148.rs +ui/proc-macro/issue-79242-slow-retokenize-check.rs +ui/proc-macro/issue-79825.rs +ui/proc-macro/issue-80760-empty-stmt.rs +ui/proc-macro/issue-81007-item-attrs.rs +ui/proc-macro/issue-81543-item-parse-err.rs +ui/proc-macro/issue-81555.rs +ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs +ui/proc-macro/issue-83510.rs +ui/proc-macro/issue-86781-bad-inner-doc.rs +ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs +ui/proc-macro/issue-91800.rs +ui/process/issue-13304.rs +ui/process/issue-14456.rs +ui/process/issue-14940.rs +ui/process/issue-16272.rs +ui/process/issue-20091.rs +ui/process/issue-30490.rs +ui/ptr_ops/issue-80309-safe.rs +ui/ptr_ops/issue-80309.rs +ui/pub/issue-33174-restricted-type-in-public-interface.rs +ui/query-system/issue-83479.rs +ui/range/issue-54505-no-literals.rs +ui/range/issue-54505-no-std.rs +ui/range/issue-54505.rs +ui/range/issue-73553-misinterp-range-literal.rs +ui/reachable/auxiliary/issue-11225-1.rs +ui/reachable/auxiliary/issue-11225-2.rs +ui/reachable/auxiliary/issue-11225-3.rs +ui/reachable/issue-11225-1.rs +ui/reachable/issue-11225-2.rs +ui/reachable/issue-11225-3.rs +ui/reachable/issue-948.rs +ui/recursion/issue-23302-1.rs +ui/recursion/issue-23302-2.rs +ui/recursion/issue-23302-3.rs +ui/recursion/issue-26548-recursion-via-normalize.rs +ui/recursion/issue-38591-non-regular-dropck-recursion.rs +ui/recursion/issue-83150.rs +ui/recursion/issue-86784.rs +ui/recursion/issue-95134.rs +ui/recursion_limit/issue-105700.rs +ui/recursion_limit/issue-40003.rs +ui/regions/issue-101280.rs +ui/regions/issue-102374.rs +ui/regions/issue-102392.rs +ui/regions/issue-11612.rs +ui/regions/issue-12470.rs +ui/regions/issue-21520.rs +ui/regions/issue-24085.rs +ui/regions/issue-26448-1.rs +ui/regions/issue-26448-2.rs +ui/regions/issue-26448-3.rs +ui/regions/issue-28848.rs +ui/regions/issue-5243.rs +ui/regions/issue-56537-closure-uses-region-from-container.rs +ui/regions/issue-6157.rs +ui/regions/issue-72051-member-region-hang.rs +ui/regions/issue-78262.rs +ui/repr/issue-83505-repr-simd.rs +ui/resolve/auxiliary/issue-112831-aux.rs +ui/resolve/auxiliary/issue-19452-aux.rs +ui/resolve/auxiliary/issue-21221-3.rs +ui/resolve/auxiliary/issue-21221-4.rs +ui/resolve/auxiliary/issue-30535.rs +ui/resolve/auxiliary/issue-3907.rs +ui/resolve/auxiliary/issue-80079.rs +ui/resolve/issue-100365.rs +ui/resolve/issue-101749-2.rs +ui/resolve/issue-101749.rs +ui/resolve/issue-10200.rs +ui/resolve/issue-102946.rs +ui/resolve/issue-103202.rs +ui/resolve/issue-103474.rs +ui/resolve/issue-104700-inner_scope.rs +ui/resolve/issue-105069.rs +ui/resolve/issue-107563-ambiguous-glob-reexports.rs +ui/resolve/issue-108529.rs +ui/resolve/issue-109153.rs +ui/resolve/issue-109250.rs +ui/resolve/issue-111312.rs +ui/resolve/issue-111727.rs +ui/resolve/issue-112472-multi-generics-suggestion.rs +ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs +ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs +ui/resolve/issue-116164.rs +ui/resolve/issue-117920.rs +ui/resolve/issue-118295.rs +ui/resolve/issue-120559.rs +ui/resolve/issue-12796.rs +ui/resolve/issue-14254.rs +ui/resolve/issue-16058.rs +ui/resolve/issue-17518.rs +ui/resolve/issue-18252.rs +ui/resolve/issue-19452.rs +ui/resolve/issue-21221-1.rs +ui/resolve/issue-21221-2.rs +ui/resolve/issue-21221-3.rs +ui/resolve/issue-21221-4.rs +ui/resolve/issue-22692.rs +ui/resolve/issue-2330.rs +ui/resolve/issue-23305.rs +ui/resolve/issue-2356.rs +ui/resolve/issue-23716.rs +ui/resolve/issue-24968.rs +ui/resolve/issue-26545.rs +ui/resolve/issue-3021-c.rs +ui/resolve/issue-3021.rs +ui/resolve/issue-30535.rs +ui/resolve/issue-3099-a.rs +ui/resolve/issue-3099-b.rs +ui/resolve/issue-31845.rs +ui/resolve/issue-33876.rs +ui/resolve/issue-35675.rs +ui/resolve/issue-3907-2.rs +ui/resolve/issue-3907.rs +ui/resolve/issue-39226.rs +ui/resolve/issue-39559-2.rs +ui/resolve/issue-39559.rs +ui/resolve/issue-42944.rs +ui/resolve/issue-49074.rs +ui/resolve/issue-5035-2.rs +ui/resolve/issue-5035.rs +ui/resolve/issue-50599.rs +ui/resolve/issue-5099.rs +ui/resolve/issue-54379.rs +ui/resolve/issue-55673.rs +ui/resolve/issue-57523.rs +ui/resolve/issue-5927.rs +ui/resolve/issue-60057.rs +ui/resolve/issue-65025-extern-static-parent-generics.rs +ui/resolve/issue-65035-static-with-parent-generics.rs +ui/resolve/issue-6642.rs +ui/resolve/issue-6702.rs +ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +ui/resolve/issue-70736-async-fn-no-body-def-collector.rs +ui/resolve/issue-73427.rs +ui/resolve/issue-80079.rs +ui/resolve/issue-81508.rs +ui/resolve/issue-82156.rs +ui/resolve/issue-82865.rs +ui/resolve/issue-85348.rs +ui/resolve/issue-85671.rs +ui/resolve/issue-88472.rs +ui/resolve/issue-90113.rs +ui/return/issue-64620.rs +ui/return/issue-82612-return-mutable-reference.rs +ui/return/issue-86188-return-not-in-fn-body.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs +ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs +ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs +ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs +ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs +ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs +ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs +ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs +ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs +ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs +ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs +ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs +ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs +ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs +ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs +ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs +ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs +ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs +ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +ui/rust-2018/issue-51008-1.rs +ui/rust-2018/issue-51008.rs +ui/rust-2018/issue-52202-use-suggestions.rs +ui/rust-2018/issue-54006.rs +ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs +ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs +ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs +ui/rust-2018/uniform-paths/auxiliary/issue-56596.rs +ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs +ui/rust-2018/uniform-paths/issue-54253.rs +ui/rust-2018/uniform-paths/issue-55779.rs +ui/rust-2018/uniform-paths/issue-56596-2.rs +ui/rust-2018/uniform-paths/issue-56596.rs +ui/rust-2018/uniform-paths/issue-87932.rs +ui/sanitizer/issue-111184-cfi-coroutine-witness.rs +ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs +ui/sanitizer/issue-72154-address-lifetime-markers.rs +ui/self/issue-61882-2.rs +ui/self/issue-61882.rs +ui/simd/intrinsic/issue-85855.rs +ui/simd/issue-105439.rs +ui/simd/issue-17170.rs +ui/simd/issue-32947.rs +ui/simd/issue-39720.rs +ui/simd/issue-85915-simd-ptrs.rs +ui/simd/issue-89193.rs +ui/single-use-lifetime/issue-104440.rs +ui/single-use-lifetime/issue-107998.rs +ui/single-use-lifetime/issue-117965.rs +ui/span/issue-107353.rs +ui/span/issue-11925.rs +ui/span/issue-15480.rs +ui/span/issue-23338-locals-die-before-temps-of-body.rs +ui/span/issue-23729.rs +ui/span/issue-23827.rs +ui/span/issue-24356.rs +ui/span/issue-24690.rs +ui/span/issue-24805-dropck-child-has-items-via-parent.rs +ui/span/issue-24805-dropck-trait-has-items.rs +ui/span/issue-24895-copy-clone-dropck.rs +ui/span/issue-25199.rs +ui/span/issue-26656.rs +ui/span/issue-27522.rs +ui/span/issue-29106.rs +ui/span/issue-29595.rs +ui/span/issue-33884.rs +ui/span/issue-34264.rs +ui/span/issue-35987.rs +ui/span/issue-36537.rs +ui/span/issue-37767.rs +ui/span/issue-39018.rs +ui/span/issue-39698.rs +ui/span/issue-40157.rs +ui/span/issue-42234-unknown-receiver-type.rs +ui/span/issue-43927-non-ADT-derive.rs +ui/span/issue-71363.rs +ui/span/issue-81800.rs +ui/span/issue28498-reject-ex1.rs +ui/span/issue28498-reject-lifetime-param.rs +ui/span/issue28498-reject-passed-to-fn.rs +ui/span/issue28498-reject-trait-bound.rs +ui/specialization/issue-111232.rs +ui/specialization/issue-33017.rs +ui/specialization/issue-35376.rs +ui/specialization/issue-36804.rs +ui/specialization/issue-38091-2.rs +ui/specialization/issue-38091.rs +ui/specialization/issue-39448.rs +ui/specialization/issue-39618.rs +ui/specialization/issue-40582.rs +ui/specialization/issue-43037.rs +ui/specialization/issue-44861.rs +ui/specialization/issue-45814.rs +ui/specialization/issue-50452-fail.rs +ui/specialization/issue-50452.rs +ui/specialization/issue-51892.rs +ui/specialization/issue-52050.rs +ui/specialization/issue-59435.rs +ui/specialization/issue-63716-parse-async.rs +ui/specialization/issue-68830-spurious-diagnostics.rs +ui/specialization/issue-70442.rs +ui/specialization/min_specialization/issue-79224.rs +ui/stability-attribute/issue-106589.rs +ui/stability-attribute/issue-109177.rs +ui/stability-attribute/issue-28075.rs +ui/stability-attribute/issue-28388-3.rs +ui/stability-attribute/issue-99286-stable-intrinsics.rs +ui/static/auxiliary/issue_24843.rs +ui/static/issue-1660.rs +ui/static/issue-18118-2.rs +ui/static/issue-18118.rs +ui/static/issue-24446.rs +ui/static/issue-24843.rs +ui/static/issue-34194.rs +ui/static/issue-5216.rs +ui/statics/issue-14227.rs +ui/statics/issue-15261.rs +ui/statics/issue-17233.rs +ui/statics/issue-17718-static-sync.rs +ui/statics/issue-17718-static-unsafe-interior.rs +ui/statics/issue-44373-2.rs +ui/statics/issue-44373.rs +ui/statics/issue-91050-1.rs +ui/statics/issue-91050-2.rs +ui/std/issue-3563-3.rs +ui/std/issue-81357-unsound-file-methods.rs +ui/stdlib-unit-tests/issue-21058.rs +ui/structs-enums/enum-rec/issue-17431-6.rs +ui/structs-enums/enum-rec/issue-17431-7.rs +ui/structs-enums/issue-103869.rs +ui/structs-enums/issue-1701.rs +ui/structs-enums/issue-2718-a.rs +ui/structs-enums/issue-3008-1.rs +ui/structs-enums/issue-3008-2.rs +ui/structs-enums/issue-3008-3.rs +ui/structs-enums/issue-38002.rs +ui/structs-enums/issue-50731.rs +ui/structs-enums/struct-rec/issue-17431-1.rs +ui/structs-enums/struct-rec/issue-17431-2.rs +ui/structs-enums/struct-rec/issue-17431-3.rs +ui/structs-enums/struct-rec/issue-17431-4.rs +ui/structs-enums/struct-rec/issue-17431-5.rs +ui/structs-enums/struct-rec/issue-74224.rs +ui/structs-enums/struct-rec/issue-84611.rs +ui/structs/issue-80853.rs +ui/suggestions/auxiliary/issue-61963-1.rs +ui/suggestions/auxiliary/issue-61963.rs +ui/suggestions/auxiliary/issue-81839.rs +ui/suggestions/issue-101065.rs +ui/suggestions/issue-101421.rs +ui/suggestions/issue-101465.rs +ui/suggestions/issue-101623.rs +ui/suggestions/issue-101984.rs +ui/suggestions/issue-102354.rs +ui/suggestions/issue-102892.rs +ui/suggestions/issue-102972.rs +ui/suggestions/issue-103112.rs +ui/suggestions/issue-103646.rs +ui/suggestions/issue-104086-suggest-let.rs +ui/suggestions/issue-104287.rs +ui/suggestions/issue-104327.rs +ui/suggestions/issue-104328.rs +ui/suggestions/issue-104961.rs +ui/suggestions/issue-105226.rs +ui/suggestions/issue-105494.rs +ui/suggestions/issue-105645.rs +ui/suggestions/issue-105761-suggest-self-for-closure.rs +ui/suggestions/issue-106443-sugg-clone-for-arg.rs +ui/suggestions/issue-106443-sugg-clone-for-bound.rs +ui/suggestions/issue-107860.rs +ui/suggestions/issue-108470.rs +ui/suggestions/issue-109195.rs +ui/suggestions/issue-109291.rs +ui/suggestions/issue-109396.rs +ui/suggestions/issue-109436.rs +ui/suggestions/issue-109854.rs +ui/suggestions/issue-109991.rs +ui/suggestions/issue-112590-suggest-import.rs +ui/suggestions/issue-114701.rs +ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs +ui/suggestions/issue-116434-2015.rs +ui/suggestions/issue-116434-2021.rs +ui/suggestions/issue-117669.rs +ui/suggestions/issue-21673.rs +ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs +ui/suggestions/issue-52820.rs +ui/suggestions/issue-53692.rs +ui/suggestions/issue-57672.rs +ui/suggestions/issue-59819.rs +ui/suggestions/issue-61226.rs +ui/suggestions/issue-61963.rs +ui/suggestions/issue-62843.rs +ui/suggestions/issue-64252-self-type.rs +ui/suggestions/issue-66968-suggest-sorted-words.rs +ui/suggestions/issue-68049-1.rs +ui/suggestions/issue-68049-2.rs +ui/suggestions/issue-71394-no-from-impl.rs +ui/suggestions/issue-72766.rs +ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs +ui/suggestions/issue-81098.rs +ui/suggestions/issue-81839.rs +ui/suggestions/issue-82361.rs +ui/suggestions/issue-82566-1.rs +ui/suggestions/issue-82566-2.rs +ui/suggestions/issue-83892.rs +ui/suggestions/issue-83943.rs +ui/suggestions/issue-84592.rs +ui/suggestions/issue-84700.rs +ui/suggestions/issue-84973-2.rs +ui/suggestions/issue-84973-blacklist.rs +ui/suggestions/issue-84973-negative.rs +ui/suggestions/issue-84973.rs +ui/suggestions/issue-85347.rs +ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs +ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs +ui/suggestions/issue-86100-tuple-paren-comma.rs +ui/suggestions/issue-86667.rs +ui/suggestions/issue-88696.rs +ui/suggestions/issue-88730.rs +ui/suggestions/issue-89064.rs +ui/suggestions/issue-89333.rs +ui/suggestions/issue-89640.rs +ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs +ui/suggestions/issue-90974.rs +ui/suggestions/issue-94171.rs +ui/suggestions/issue-96223.rs +ui/suggestions/issue-96555.rs +ui/suggestions/issue-97677.rs +ui/suggestions/issue-97704.rs +ui/suggestions/issue-97760.rs +ui/suggestions/issue-98500.rs +ui/suggestions/issue-98562.rs +ui/suggestions/issue-99080.rs +ui/suggestions/issue-99240-2.rs +ui/suggestions/issue-99240.rs +ui/suggestions/issue-99597.rs +ui/suggestions/lifetimes/issue-105544.rs +ui/symbol-names/issue-53912.rs +ui/symbol-names/issue-60925.rs +ui/symbol-names/issue-75326.rs +ui/symbol-names/issue-76365.rs +ui/test-attrs/custom-test-frameworks/issue-107454.rs +ui/test-attrs/issue-109816.rs +ui/test-attrs/issue-12997-1.rs +ui/test-attrs/issue-12997-2.rs +ui/test-attrs/issue-16597-empty.rs +ui/test-attrs/issue-16597.rs +ui/test-attrs/issue-20823.rs +ui/test-attrs/issue-34932.rs +ui/test-attrs/issue-36768.rs +ui/test-attrs/issue-52557.rs +ui/test-attrs/issue-53675-a-test-called-panic.rs +ui/threads-sendsync/issue-24313.rs +ui/threads-sendsync/issue-29488.rs +ui/threads-sendsync/issue-43733-2.rs +ui/threads-sendsync/issue-43733.rs +ui/threads-sendsync/issue-4446.rs +ui/threads-sendsync/issue-4448.rs +ui/threads-sendsync/issue-8827.rs +ui/threads-sendsync/issue-9396.rs +ui/trait-bounds/issue-119530-sugg-from-fn.rs +ui/trait-bounds/issue-75961.rs +ui/trait-bounds/issue-82038.rs +ui/trait-bounds/issue-93008.rs +ui/trait-bounds/issue-94680.rs +ui/trait-bounds/issue-94999.rs +ui/trait-bounds/issue-95640.rs +ui/traits/alias/issue-107747-do-not-assemble-supertraits.rs +ui/traits/alias/issue-108072-unmet-trait-alias-bound.rs +ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs +ui/traits/alias/issue-60021-assoc-method-resolve.rs +ui/traits/alias/issue-60755.rs +ui/traits/alias/issue-72415-assoc-const-resolve.rs +ui/traits/alias/issue-75983.rs +ui/traits/alias/issue-83613.rs +ui/traits/associated_type_bound/issue-51446.rs +ui/traits/auxiliary/issue_89119_intercrate_caching.rs +ui/traits/issue-103563.rs +ui/traits/issue-104322.rs +ui/traits/issue-105231.rs +ui/traits/issue-106072.rs +ui/traits/issue-117794.rs +ui/traits/issue-15155.rs +ui/traits/issue-18400.rs +ui/traits/issue-18412.rs +ui/traits/issue-20692.rs +ui/traits/issue-21837.rs +ui/traits/issue-22019.rs +ui/traits/issue-22110.rs +ui/traits/issue-22384.rs +ui/traits/issue-22655.rs +ui/traits/issue-23003-overflow.rs +ui/traits/issue-23003.rs +ui/traits/issue-23825.rs +ui/traits/issue-24010.rs +ui/traits/issue-2611-3.rs +ui/traits/issue-26339.rs +ui/traits/issue-28576.rs +ui/traits/issue-32963.rs +ui/traits/issue-33096.rs +ui/traits/issue-33140-hack-boundaries.rs +ui/traits/issue-33140.rs +ui/traits/issue-33187.rs +ui/traits/issue-35869.rs +ui/traits/issue-3683.rs +ui/traits/issue-38033.rs +ui/traits/issue-38404.rs +ui/traits/issue-38604.rs +ui/traits/issue-3973.rs +ui/traits/issue-3979-generics.rs +ui/traits/issue-40085.rs +ui/traits/issue-4107.rs +ui/traits/issue-43132.rs +ui/traits/issue-43784-supertrait.rs +ui/traits/issue-5008-borrowed-traitobject-method-call.rs +ui/traits/issue-50480.rs +ui/traits/issue-52893.rs +ui/traits/issue-56202.rs +ui/traits/issue-56488.rs +ui/traits/issue-58344.rs +ui/traits/issue-59029-1.rs +ui/traits/issue-59029-2.rs +ui/traits/issue-6128.rs +ui/traits/issue-6334.rs +ui/traits/issue-65284-suggest-generic-trait-bound.rs +ui/traits/issue-65673.rs +ui/traits/issue-66768.rs +ui/traits/issue-68295.rs +ui/traits/issue-7013.rs +ui/traits/issue-70944.rs +ui/traits/issue-71036.rs +ui/traits/issue-71136.rs +ui/traits/issue-72410.rs +ui/traits/issue-72455.rs +ui/traits/issue-75627.rs +ui/traits/issue-77982.rs +ui/traits/issue-78372.rs +ui/traits/issue-78632.rs +ui/traits/issue-79458.rs +ui/traits/issue-8153.rs +ui/traits/issue-82830.rs +ui/traits/issue-83538-tainted-cache-after-cycle.rs +ui/traits/issue-84399-bad-fresh-caching.rs +ui/traits/issue-85360-eval-obligation-ice.rs +ui/traits/issue-85735.rs +ui/traits/issue-87558.rs +ui/traits/issue-89119.rs +ui/traits/issue-90195-2.rs +ui/traits/issue-90195.rs +ui/traits/issue-90662-projection-caching.rs +ui/traits/issue-91594.rs +ui/traits/issue-91949-hangs-on-recursion.rs +ui/traits/issue-92292.rs +ui/traits/issue-9394-inherited-calls.rs +ui/traits/issue-95311.rs +ui/traits/issue-95898.rs +ui/traits/issue-96664.rs +ui/traits/issue-96665.rs +ui/traits/issue-97576.rs +ui/traits/issue-97695-double-trivial-bound.rs +ui/traits/issue-99875.rs +ui/traits/next-solver/coherence/issue-102048.rs +ui/traits/next-solver/issue-118950-root-region.rs +ui/traits/object/issue-33140-traitobject-crate.rs +ui/traits/object/issue-44454-1.rs +ui/traits/object/issue-44454-2.rs +ui/traits/object/issue-44454-3.rs +ui/traits/suggest-dereferences/issue-39029.rs +ui/traits/suggest-dereferences/issue-62530.rs +ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs +ui/traits/trait-upcasting/issue-11515.rs +ui/traits/vtable/issue-91807.rs +ui/traits/vtable/issue-97381.rs +ui/transmutability/arrays/issue-103783-array-length.rs +ui/transmutability/issue-101739-1.rs +ui/transmutability/issue-101739-2.rs +ui/transmutability/issue-110467.rs +ui/transmutability/issue-110892.rs +ui/trivial-bounds/issue-73021-impossible-inline.rs +ui/try-block/issue-45124.rs +ui/try-trait/issue-32709.rs +ui/type-alias-enum-variants/issue-57866.rs +ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs +ui/type-alias-enum-variants/issue-63151-dead-code-lint-fields-in-patterns.rs +ui/type-alias-impl-trait/issue-101750.rs +ui/type-alias-impl-trait/issue-104817.rs +ui/type-alias-impl-trait/issue-109054.rs +ui/type-alias-impl-trait/issue-52843-closure-constrain.rs +ui/type-alias-impl-trait/issue-52843.rs +ui/type-alias-impl-trait/issue-53092-2.rs +ui/type-alias-impl-trait/issue-53092.rs +ui/type-alias-impl-trait/issue-53096.rs +ui/type-alias-impl-trait/issue-53598.rs +ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs +ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs +ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs +ui/type-alias-impl-trait/issue-57611-trait-alias.rs +ui/type-alias-impl-trait/issue-57700.rs +ui/type-alias-impl-trait/issue-57807-associated-type.rs +ui/type-alias-impl-trait/issue-57961.rs +ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs +ui/type-alias-impl-trait/issue-58662-simplified.rs +ui/type-alias-impl-trait/issue-58887.rs +ui/type-alias-impl-trait/issue-58951-2.rs +ui/type-alias-impl-trait/issue-58951.rs +ui/type-alias-impl-trait/issue-60371.rs +ui/type-alias-impl-trait/issue-60407.rs +ui/type-alias-impl-trait/issue-60564-working.rs +ui/type-alias-impl-trait/issue-60564.rs +ui/type-alias-impl-trait/issue-60662.rs +ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs +ui/type-alias-impl-trait/issue-63263-closure-return.rs +ui/type-alias-impl-trait/issue-63279.rs +ui/type-alias-impl-trait/issue-63355.rs +ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs +ui/type-alias-impl-trait/issue-65384.rs +ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs +ui/type-alias-impl-trait/issue-65918.rs +ui/type-alias-impl-trait/issue-66580-closure-coherence.rs +ui/type-alias-impl-trait/issue-67844-nested-opaque.rs +ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs +ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs +ui/type-alias-impl-trait/issue-69323.rs +ui/type-alias-impl-trait/issue-70121.rs +ui/type-alias-impl-trait/issue-72793.rs +ui/type-alias-impl-trait/issue-74244.rs +ui/type-alias-impl-trait/issue-74280.rs +ui/type-alias-impl-trait/issue-74761-2.rs +ui/type-alias-impl-trait/issue-74761.rs +ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +ui/type-alias-impl-trait/issue-77179.rs +ui/type-alias-impl-trait/issue-78450.rs +ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs +ui/type-alias-impl-trait/issue-84660-unsoundness.rs +ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs +ui/type-alias-impl-trait/issue-89686.rs +ui/type-alias-impl-trait/issue-89952.rs +ui/type-alias-impl-trait/issue-90400-1.rs +ui/type-alias-impl-trait/issue-90400-2.rs +ui/type-alias-impl-trait/issue-93411.rs +ui/type-alias-impl-trait/issue-94429.rs +ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs +ui/type-alias-impl-trait/issue-96572-unconstrained.rs +ui/type-alias-impl-trait/issue-98604.rs +ui/type-alias-impl-trait/issue-98608.rs +ui/type-alias/issue-14933.rs +ui/type-alias/issue-37515.rs +ui/type-alias/issue-62263-self-in-atb.rs +ui/type-alias/issue-62305-self-assoc-ty.rs +ui/type-alias/issue-62364-self-ty-arg.rs +ui/type-inference/issue-113283-alllocator-trait-eq.rs +ui/type-inference/issue-30225.rs +ui/type/ascription/issue-34255-1.rs +ui/type/ascription/issue-47666.rs +ui/type/ascription/issue-54516.rs +ui/type/ascription/issue-60933.rs +ui/type/issue-100584.rs +ui/type/issue-101866.rs +ui/type/issue-102598.rs +ui/type/issue-103271.rs +ui/type/issue-58355.rs +ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs +ui/type/issue-91268.rs +ui/type/issue-94187-verbose-type-name.rs +ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs +ui/type/type-check/issue-22897.rs +ui/type/type-check/issue-40294.rs +ui/type/type-check/issue-41314.rs +ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs +ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs +ui/typeck/auxiliary/issue-29181.rs +ui/typeck/auxiliary/issue-36708.rs +ui/typeck/auxiliary/issue-81943-lib.rs +ui/typeck/issue-100164.rs +ui/typeck/issue-100246.rs +ui/typeck/issue-100285.rs +ui/typeck/issue-103899.rs +ui/typeck/issue-10401.rs +ui/typeck/issue-104510-ice.rs +ui/typeck/issue-104513-ice.rs +ui/typeck/issue-104582.rs +ui/typeck/issue-105946.rs +ui/typeck/issue-106929.rs +ui/typeck/issue-107087.rs +ui/typeck/issue-107775.rs +ui/typeck/issue-10969.rs +ui/typeck/issue-110017-format-into-help-deletes-macro.rs +ui/typeck/issue-110052.rs +ui/typeck/issue-112007-leaked-writeln-macro-internals.rs +ui/typeck/issue-112252-ptr-arithmetics-help.rs +ui/typeck/issue-112385-while-assign-lhs-place-expr-ice.rs +ui/typeck/issue-114423-ice-regression-in-suggestion.rs +ui/typeck/issue-114529-illegal-break-with-value.rs +ui/typeck/issue-116473-ice-wrong-span-variant-args.rs +ui/typeck/issue-116864.rs +ui/typeck/issue-120856.rs +ui/typeck/issue-13853-2.rs +ui/typeck/issue-13853-5.rs +ui/typeck/issue-13853.rs +ui/typeck/issue-16338.rs +ui/typeck/issue-1871.rs +ui/typeck/issue-18937-1.rs +ui/typeck/issue-18937.rs +ui/typeck/issue-2063-resource.rs +ui/typeck/issue-2063.rs +ui/typeck/issue-22375.rs +ui/typeck/issue-29124.rs +ui/typeck/issue-29181.rs +ui/typeck/issue-31173.rs +ui/typeck/issue-33575.rs +ui/typeck/issue-36708.rs +ui/typeck/issue-43189.rs +ui/typeck/issue-46112.rs +ui/typeck/issue-50687-ice-on-borrow.rs +ui/typeck/issue-52082-type-param-shadows-existing-type.rs +ui/typeck/issue-53712.rs +ui/typeck/issue-55810-must-typeck-match-pats-before-guards.rs +ui/typeck/issue-57404.rs +ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs +ui/typeck/issue-61711-once-caused-rustc-inf-loop.rs +ui/typeck/issue-65611.rs +ui/typeck/issue-67971.rs +ui/typeck/issue-68590-reborrow-through-derefmut.rs +ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs +ui/typeck/issue-72225-call-fnmut-through-derefmut.rs +ui/typeck/issue-73592-borrow_mut-through-deref.rs +ui/typeck/issue-74086.rs +ui/typeck/issue-74933.rs +ui/typeck/issue-75883.rs +ui/typeck/issue-75889.rs +ui/typeck/issue-7813.rs +ui/typeck/issue-79040.rs +ui/typeck/issue-80207-unsized-return.rs +ui/typeck/issue-80779.rs +ui/typeck/issue-81293.rs +ui/typeck/issue-81885.rs +ui/typeck/issue-81943.rs +ui/typeck/issue-82772.rs +ui/typeck/issue-83621-placeholder-static-in-extern.rs +ui/typeck/issue-83693.rs +ui/typeck/issue-84160.rs +ui/typeck/issue-84768.rs +ui/typeck/issue-84831.rs +ui/typeck/issue-86721-return-expr-ice.rs +ui/typeck/issue-87771-ice-assign-assign-to-bool.rs +ui/typeck/issue-87872-missing-inaccessible-field-literal.rs +ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs +ui/typeck/issue-88609.rs +ui/typeck/issue-88643.rs +ui/typeck/issue-88803-call-expr-method.rs +ui/typeck/issue-88844.rs +ui/typeck/issue-89044-wrapped-expr-method.rs +ui/typeck/issue-89275.rs +ui/typeck/issue-89806.rs +ui/typeck/issue-89856.rs +ui/typeck/issue-89935.rs +ui/typeck/issue-90027-async-fn-return-suggestion.rs +ui/typeck/issue-90101.rs +ui/typeck/issue-90164.rs +ui/typeck/issue-90319.rs +ui/typeck/issue-90483-inaccessible-field-adjustment.rs +ui/typeck/issue-90804-incorrect-reference-suggestion.rs +ui/typeck/issue-91210-ptr-method.rs +ui/typeck/issue-91267.rs +ui/typeck/issue-91328.rs +ui/typeck/issue-91334.rs +ui/typeck/issue-91450-inner-ty-error.rs +ui/typeck/issue-91633.rs +ui/typeck/issue-92481.rs +ui/typeck/issue-93486.rs +ui/typeck/issue-96530.rs +ui/typeck/issue-96738.rs +ui/typeck/issue-98260.rs +ui/typeck/issue-98982.rs +ui/typeof/issue-100183.rs +ui/typeof/issue-29184.rs +ui/typeof/issue-42060.rs +ui/unboxed-closures/issue-18652.rs +ui/unboxed-closures/issue-18661.rs +ui/unboxed-closures/issue-30906.rs +ui/unboxed-closures/issue-53448.rs +ui/underscore-imports/issue-110164.rs +ui/uniform-paths/auxiliary/issue-53691.rs +ui/uniform-paths/issue-53691.rs +ui/uninhabited/issue-107505.rs +ui/union/issue-41073.rs +ui/union/issue-81199.rs +ui/union/issue-99375.rs +ui/unsafe/auxiliary/issue-106126.rs +ui/unsafe/issue-106126-good-path-bug.rs +ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs +ui/unsafe/issue-3080.rs +ui/unsafe/issue-45087-unreachable-unsafe.rs +ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs +ui/unsafe/issue-47412.rs +ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs +ui/unsafe/issue-87414-query-cycle.rs +ui/unsized-locals/issue-30276-feature-flagged.rs +ui/unsized-locals/issue-30276.rs +ui/unsized-locals/issue-50940-with-feature.rs +ui/unsized-locals/issue-50940.rs +ui/unsized-locals/issue-67981.rs +ui/unsized/issue-115203.rs +ui/unsized/issue-115809.rs +ui/unsized/issue-23649-1.rs +ui/unsized/issue-23649-2.rs +ui/unsized/issue-23649-3.rs +ui/unsized/issue-30355.rs +ui/unsized/issue-40231-1.rs +ui/unsized/issue-40231-2.rs +ui/unsized/issue-71659.rs +ui/unsized/issue-75707.rs +ui/unsized/issue-75899-but-gats.rs +ui/unsized/issue-75899.rs +ui/unsized/issue-91801.rs +ui/unsized/issue-91803.rs +ui/unsized/issue-97732.rs +ui/use/issue-18986.rs +ui/use/issue-60976-extern-use-primitive-type.rs +ui/wf/issue-103573.rs +ui/wf/issue-110157.rs +ui/wf/issue-48638.rs +ui/wf/issue-87495.rs +ui/wf/issue-95665.rs +ui/wf/issue-96810.rs +ui/where-clauses/issue-50825-1.rs +ui/where-clauses/issue-50825.rs diff --git a/src/tools/tidy/src/known_bug.rs b/src/tools/tidy/src/known_bug.rs new file mode 100644 index 00000000000..a62556f762b --- /dev/null +++ b/src/tools/tidy/src/known_bug.rs @@ -0,0 +1,17 @@ +//! Tidy check to ensure that tests inside 'tests/crashes' have a '@known-bug' directive. + +use crate::walk::*; +use std::path::Path; + +pub fn check(filepath: &Path, bad: &mut bool) { + walk(filepath, |path, _is_dir| filter_not_rust(path), &mut |entry, contents| { + let file = entry.path(); + if !contents.lines().any(|line| line.starts_with("//@ known-bug: ")) { + tidy_error!( + bad, + "{} crash/ice test does not have a \"//@ known-bug: \" directive", + file.display() + ); + } + }); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 57436e8d7fe..23f303276aa 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -67,6 +67,7 @@ pub mod features; pub mod fluent_alphabetical; mod fluent_used; pub(crate) mod iter_header; +pub mod known_bug; pub mod mir_opt_tests; pub mod pal; pub mod run_make_tests; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 93be4d61a9a..77691815830 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,6 +35,7 @@ fn main() { let library_path = root_path.join("library"); let compiler_path = root_path.join("compiler"); let librustdoc_path = src_path.join("librustdoc"); + let crashes_path = tests_path.join("crashes"); let args: Vec<String> = env::args().skip(1).collect(); let (cfg_args, pos_args) = match args.iter().position(|arg| arg == "--") { @@ -108,6 +109,7 @@ fn main() { check!(mir_opt_tests, &tests_path, bless); check!(rustdoc_gui_tests, &tests_path); check!(rustdoc_css_themes, &librustdoc_path); + check!(known_bug, &crashes_path); // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); diff --git a/src/tools/tidy/src/run_make_tests.rs b/src/tools/tidy/src/run_make_tests.rs index 98021cec130..2d9f8448a35 100644 --- a/src/tools/tidy/src/run_make_tests.rs +++ b/src/tools/tidy/src/run_make_tests.rs @@ -6,10 +6,26 @@ use std::io::Write; use std::path::{Path, PathBuf}; pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { + let mut is_sorted = true; + let allowed_makefiles = { - let allowed_makefiles = include_str!("allowed_run_make_makefiles.txt"); - let allowed_makefiles = allowed_makefiles.lines().collect::<Vec<_>>(); - let is_sorted = allowed_makefiles.windows(2).all(|w| w[0] < w[1]); + let mut total_lines = 0; + let mut prev_line = ""; + let allowed_makefiles: BTreeSet<&str> = include_str!("allowed_run_make_makefiles.txt") + .lines() + .map(|line| { + total_lines += 1; + + if prev_line > line { + is_sorted = false; + } + + prev_line = line; + + line + }) + .collect(); + if !is_sorted && !bless { tidy_error!( bad, @@ -18,9 +34,7 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { `x test tidy --bless`" ); } - let allowed_makefiles_unique = - allowed_makefiles.iter().map(ToString::to_string).collect::<BTreeSet<String>>(); - if allowed_makefiles_unique.len() != allowed_makefiles.len() { + if allowed_makefiles.len() != total_lines { tidy_error!( bad, "`src/tools/tidy/src/allowed_run_make_makefiles.txt` contains duplicate entries, \ @@ -28,7 +42,8 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { `x test tidy --bless`" ); } - allowed_makefiles_unique + + allowed_makefiles }; let mut remaining_makefiles = allowed_makefiles.clone(); @@ -48,7 +63,7 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { let makefile_path = entry.path().strip_prefix(&tests_path).unwrap(); let makefile_path = makefile_path.to_str().unwrap().replace('\\', "/"); - if !remaining_makefiles.remove(&makefile_path) { + if !remaining_makefiles.remove(makefile_path.as_str()) { tidy_error!( bad, "found run-make Makefile not permitted in \ @@ -64,7 +79,7 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { // Our data must remain up to date, so they must be removed from // `src/tools/tidy/src/allowed_run_make_makefiles.txt`. // This can be done automatically on --bless, or else a tidy error will be issued. - if bless && !remaining_makefiles.is_empty() { + if bless && (!remaining_makefiles.is_empty() || !is_sorted) { let tidy_src = src_path.join("tools").join("tidy").join("src"); let org_file_path = tidy_src.join("allowed_run_make_makefiles.txt"); let temp_file_path = tidy_src.join("blessed_allowed_run_make_makefiles.txt"); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 454811c5fbb..7136bc4d8f2 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,8 +17,8 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1733; -const ROOT_ENTRY_LIMIT: usize = 860; +const ISSUES_ENTRY_LIMIT: usize = 1720; +const ROOT_ENTRY_LIMIT: usize = 859; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files @@ -49,6 +49,9 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file "tests/ui/shell-argfiles/shell-argfiles-via-argfile.args", // passing args via a file + "tests/ui/std/windows-bat-args1.bat", // tests escaping arguments through batch files + "tests/ui/std/windows-bat-args2.bat", // tests escaping arguments through batch files + "tests/ui/std/windows-bat-args3.bat", // tests escaping arguments through batch files ]; fn check_entries(tests_path: &Path, bad: &mut bool) { @@ -100,15 +103,32 @@ fn check_entries(tests_path: &Path, bad: &mut bool) { } pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { + let issues_txt_header = r#"============================================================ + ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️ +============================================================ +"#; + let path = &root_path.join("tests"); check_entries(&path, bad); // the list of files in ui tests that are allowed to start with `issue-XXXX` // BTreeSet because we would like a stable ordering so --bless works - let issues_list = - include!("issues.txt").map(|path| path.replace("/", std::path::MAIN_SEPARATOR_STR)); - let issues: Vec<String> = Vec::from(issues_list.clone()); - let is_sorted = issues.windows(2).all(|w| w[0] < w[1]); + let mut prev_line = ""; + let mut is_sorted = true; + let allowed_issue_names: BTreeSet<_> = include_str!("issues.txt") + .strip_prefix(issues_txt_header) + .unwrap() + .lines() + .map(|line| { + if prev_line > line { + is_sorted = false; + } + + prev_line = line; + line + }) + .collect(); + if !is_sorted && !bless { tidy_error!( bad, @@ -116,9 +136,8 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { please only update it with command `x test tidy --bless`" ); } - let allowed_issue_names = BTreeSet::from(issues_list); - let mut remaining_issue_names: BTreeSet<String> = allowed_issue_names.clone(); + let mut remaining_issue_names: BTreeSet<&str> = allowed_issue_names.clone(); let (ui, ui_fulldeps) = (path.join("ui"), path.join("ui-fulldeps")); let paths = [ui.as_path(), ui_fulldeps.as_path()]; @@ -170,8 +189,14 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { if let Some(test_name) = ISSUE_NAME_REGEX.captures(testname) { // these paths are always relative to the passed `path` and always UTF8 - let stripped_path = file_path.strip_prefix(path).unwrap().to_str().unwrap(); - if !remaining_issue_names.remove(stripped_path) { + let stripped_path = file_path + .strip_prefix(path) + .unwrap() + .to_str() + .unwrap() + .replace(std::path::MAIN_SEPARATOR_STR, "/"); + + if !remaining_issue_names.remove(stripped_path.as_str()) { tidy_error!( bad, "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`", @@ -186,15 +211,7 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { // if there are any file names remaining, they were moved on the fs. // our data must remain up to date, so it must be removed from issues.txt // do this automatically on bless, otherwise issue a tidy error - if bless && !remaining_issue_names.is_empty() { - let issues_txt_header = r#" -/* -============================================================ - ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️ -============================================================ -*/ -[ -"#; + if bless && (!remaining_issue_names.is_empty() || !is_sorted) { let tidy_src = root_path.join("src/tools/tidy/src"); // instead of overwriting the file, recreate it and use an "atomic rename" // so we don't bork things on panic or a contributor using Ctrl+C @@ -202,13 +219,9 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { let mut blessed_issues_txt = fs::File::create(&blessed_issues_path).unwrap(); blessed_issues_txt.write(issues_txt_header.as_bytes()).unwrap(); // If we changed paths to use the OS separator, reassert Unix chauvinism for blessing. - for filename in allowed_issue_names - .difference(&remaining_issue_names) - .map(|s| s.replace(std::path::MAIN_SEPARATOR_STR, "/")) - { - write!(blessed_issues_txt, "\"{filename}\",\n").unwrap(); + for filename in allowed_issue_names.difference(&remaining_issue_names) { + writeln!(blessed_issues_txt, "{filename}").unwrap(); } - write!(blessed_issues_txt, "]\n").unwrap(); let old_issues_path = tidy_src.join("issues.txt"); fs::rename(blessed_issues_path, old_issues_path).unwrap(); } else { diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs index 1b2bd4b3d81..3e2a4773703 100644 --- a/tests/assembly/asm/aarch64-types.rs +++ b/tests/assembly/asm/aarch64-types.rs @@ -1,8 +1,11 @@ +//@ revisions: aarch64 arm64ec //@ assembly-output: emit-asm -//@ compile-flags: --target aarch64-unknown-linux-gnu -//@ needs-llvm-components: aarch64 +//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@ [aarch64] needs-llvm-components: aarch64 +//@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc +//@ [arm64ec] needs-llvm-components: aarch64 -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -77,7 +80,7 @@ extern "C" { static extern_static: u8; } -// CHECK-LABEL: sym_fn: +// CHECK-LABEL: {{("#)?}}sym_fn{{"?}} // CHECK: //APP // CHECK: bl extern_func // CHECK: //NO_APP @@ -86,7 +89,7 @@ pub unsafe fn sym_fn() { asm!("bl {}", sym extern_func); } -// CHECK-LABEL: sym_static: +// CHECK-LABEL: {{("#)?}}sym_static{{"?}} // CHECK: //APP // CHECK: adr x0, extern_static // CHECK: //NO_APP @@ -96,7 +99,7 @@ pub unsafe fn sym_static() { } // Regression test for #75761 -// CHECK-LABEL: issue_75761: +// CHECK-LABEL: {{("#)?}}issue_75761{{"?}} // CHECK: str {{.*}}x30 // CHECK: //APP // CHECK: //NO_APP @@ -144,421 +147,421 @@ macro_rules! check_reg { }; } -// CHECK-LABEL: reg_i8: +// CHECK-LABEL: {{("#)?}}reg_i8{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_i8 i8 reg "mov" ""); -// CHECK-LABEL: reg_i16: +// CHECK-LABEL: {{("#)?}}reg_i16{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_i16 i16 reg "mov" ""); -// CHECK-LABEL: reg_i32: +// CHECK-LABEL: {{("#)?}}reg_i32{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_i32 i32 reg "mov" ""); -// CHECK-LABEL: reg_f32: +// CHECK-LABEL: {{("#)?}}reg_f32{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_f32 f32 reg "mov" ""); -// CHECK-LABEL: reg_i64: +// CHECK-LABEL: {{("#)?}}reg_i64{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_i64 i64 reg "mov" ""); -// CHECK-LABEL: reg_f64: +// CHECK-LABEL: {{("#)?}}reg_f64{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_f64 f64 reg "mov" ""); -// CHECK-LABEL: reg_ptr: +// CHECK-LABEL: {{("#)?}}reg_ptr{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check!(reg_ptr ptr reg "mov" ""); -// CHECK-LABEL: vreg_i8: +// CHECK-LABEL: {{("#)?}}vreg_i8{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i8 i8 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i16: +// CHECK-LABEL: {{("#)?}}vreg_i16{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i16 i16 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i32: +// CHECK-LABEL: {{("#)?}}vreg_i32{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i32 i32 vreg "fmov" "s"); -// CHECK-LABEL: vreg_f32: +// CHECK-LABEL: {{("#)?}}vreg_f32{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_f32 f32 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i64: +// CHECK-LABEL: {{("#)?}}vreg_i64{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i64 i64 vreg "fmov" "s"); -// CHECK-LABEL: vreg_f64: +// CHECK-LABEL: {{("#)?}}vreg_f64{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_f64 f64 vreg "fmov" "s"); -// CHECK-LABEL: vreg_ptr: +// CHECK-LABEL: {{("#)?}}vreg_ptr{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_ptr ptr vreg "fmov" "s"); -// CHECK-LABEL: vreg_i8x8: +// CHECK-LABEL: {{("#)?}}vreg_i8x8{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i8x8 i8x8 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i16x4: +// CHECK-LABEL: {{("#)?}}vreg_i16x4{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i16x4 i16x4 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i32x2: +// CHECK-LABEL: {{("#)?}}vreg_i32x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i32x2 i32x2 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i64x1: +// CHECK-LABEL: {{("#)?}}vreg_i64x1{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i64x1 i64x1 vreg "fmov" "s"); -// CHECK-LABEL: vreg_f32x2: +// CHECK-LABEL: {{("#)?}}vreg_f32x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_f32x2 f32x2 vreg "fmov" "s"); -// CHECK-LABEL: vreg_f64x1: +// CHECK-LABEL: {{("#)?}}vreg_f64x1{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_f64x1 f64x1 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i8x16: +// CHECK-LABEL: {{("#)?}}vreg_i8x16{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i8x16 i8x16 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i16x8: +// CHECK-LABEL: {{("#)?}}vreg_i16x8{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i16x8 i16x8 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i32x4: +// CHECK-LABEL: {{("#)?}}vreg_i32x4{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i32x4 i32x4 vreg "fmov" "s"); -// CHECK-LABEL: vreg_i64x2: +// CHECK-LABEL: {{("#)?}}vreg_i64x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_i64x2 i64x2 vreg "fmov" "s"); -// CHECK-LABEL: vreg_f32x4: +// CHECK-LABEL: {{("#)?}}vreg_f32x4{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_f32x4 f32x4 vreg "fmov" "s"); -// CHECK-LABEL: vreg_f64x2: +// CHECK-LABEL: {{("#)?}}vreg_f64x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_f64x2 f64x2 vreg "fmov" "s"); -// CHECK-LABEL: vreg_low16_i8: +// CHECK-LABEL: {{("#)?}}vreg_low16_i8{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i8 i8 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i16: +// CHECK-LABEL: {{("#)?}}vreg_low16_i16{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i16 i16 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_f32: +// CHECK-LABEL: {{("#)?}}vreg_low16_f32{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_f32 f32 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i64: +// CHECK-LABEL: {{("#)?}}vreg_low16_i64{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i64 i64 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_f64: +// CHECK-LABEL: {{("#)?}}vreg_low16_f64{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_f64 f64 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_ptr: +// CHECK-LABEL: {{("#)?}}vreg_low16_ptr{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_ptr ptr vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i8x8: +// CHECK-LABEL: {{("#)?}}vreg_low16_i8x8{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i8x8 i8x8 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i16x4: +// CHECK-LABEL: {{("#)?}}vreg_low16_i16x4{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i16x4 i16x4 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i32x2: +// CHECK-LABEL: {{("#)?}}vreg_low16_i32x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i32x2 i32x2 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i64x1: +// CHECK-LABEL: {{("#)?}}vreg_low16_i64x1{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i64x1 i64x1 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_f32x2: +// CHECK-LABEL: {{("#)?}}vreg_low16_f32x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_f32x2 f32x2 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_f64x1: +// CHECK-LABEL: {{("#)?}}vreg_low16_f64x1{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_f64x1 f64x1 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i8x16: +// CHECK-LABEL: {{("#)?}}vreg_low16_i8x16{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i8x16 i8x16 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i16x8: +// CHECK-LABEL: {{("#)?}}vreg_low16_i16x8{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i16x8 i16x8 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i32x4: +// CHECK-LABEL: {{("#)?}}vreg_low16_i32x4{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i32x4 i32x4 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_i64x2: +// CHECK-LABEL: {{("#)?}}vreg_low16_i64x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_i64x2 i64x2 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_f32x4: +// CHECK-LABEL: {{("#)?}}vreg_low16_f32x4{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); -// CHECK-LABEL: vreg_low16_f64x2: +// CHECK-LABEL: {{("#)?}}vreg_low16_f64x2{{"?}} // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} // CHECK: //NO_APP check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); -// CHECK-LABEL: x0_i8: +// CHECK-LABEL: {{("#)?}}x0_i8{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_i8 i8 "x0" "mov"); -// CHECK-LABEL: x0_i16: +// CHECK-LABEL: {{("#)?}}x0_i16{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_i16 i16 "x0" "mov"); -// CHECK-LABEL: x0_i32: +// CHECK-LABEL: {{("#)?}}x0_i32{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_i32 i32 "x0" "mov"); -// CHECK-LABEL: x0_f32: +// CHECK-LABEL: {{("#)?}}x0_f32{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_f32 f32 "x0" "mov"); -// CHECK-LABEL: x0_i64: +// CHECK-LABEL: {{("#)?}}x0_i64{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_i64 i64 "x0" "mov"); -// CHECK-LABEL: x0_f64: +// CHECK-LABEL: {{("#)?}}x0_f64{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_f64 f64 "x0" "mov"); -// CHECK-LABEL: x0_ptr: +// CHECK-LABEL: {{("#)?}}x0_ptr{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} // CHECK: //NO_APP check_reg!(x0_ptr ptr "x0" "mov"); -// CHECK-LABEL: v0_i8: +// CHECK-LABEL: {{("#)?}}v0_i8{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i8 i8 "s0" "fmov"); -// CHECK-LABEL: v0_i16: +// CHECK-LABEL: {{("#)?}}v0_i16{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i16 i16 "s0" "fmov"); -// CHECK-LABEL: v0_i32: +// CHECK-LABEL: {{("#)?}}v0_i32{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i32 i32 "s0" "fmov"); -// CHECK-LABEL: v0_f32: +// CHECK-LABEL: {{("#)?}}v0_f32{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f32 f32 "s0" "fmov"); -// CHECK-LABEL: v0_i64: +// CHECK-LABEL: {{("#)?}}v0_i64{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i64 i64 "s0" "fmov"); -// CHECK-LABEL: v0_f64: +// CHECK-LABEL: {{("#)?}}v0_f64{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f64 f64 "s0" "fmov"); -// CHECK-LABEL: v0_ptr: +// CHECK-LABEL: {{("#)?}}v0_ptr{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_ptr ptr "s0" "fmov"); -// CHECK-LABEL: v0_i8x8: +// CHECK-LABEL: {{("#)?}}v0_i8x8{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i8x8 i8x8 "s0" "fmov"); -// CHECK-LABEL: v0_i16x4: +// CHECK-LABEL: {{("#)?}}v0_i16x4{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i16x4 i16x4 "s0" "fmov"); -// CHECK-LABEL: v0_i32x2: +// CHECK-LABEL: {{("#)?}}v0_i32x2{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i32x2 i32x2 "s0" "fmov"); -// CHECK-LABEL: v0_i64x1: +// CHECK-LABEL: {{("#)?}}v0_i64x1{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i64x1 i64x1 "s0" "fmov"); -// CHECK-LABEL: v0_f32x2: +// CHECK-LABEL: {{("#)?}}v0_f32x2{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f32x2 f32x2 "s0" "fmov"); -// CHECK-LABEL: v0_f64x1: +// CHECK-LABEL: {{("#)?}}v0_f64x1{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f64x1 f64x1 "s0" "fmov"); -// CHECK-LABEL: v0_i8x16: +// CHECK-LABEL: {{("#)?}}v0_i8x16{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i8x16 i8x16 "s0" "fmov"); -// CHECK-LABEL: v0_i16x8: +// CHECK-LABEL: {{("#)?}}v0_i16x8{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i16x8 i16x8 "s0" "fmov"); -// CHECK-LABEL: v0_i32x4: +// CHECK-LABEL: {{("#)?}}v0_i32x4{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i32x4 i32x4 "s0" "fmov"); -// CHECK-LABEL: v0_i64x2: +// CHECK-LABEL: {{("#)?}}v0_i64x2{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_i64x2 i64x2 "s0" "fmov"); -// CHECK-LABEL: v0_f32x4: +// CHECK-LABEL: {{("#)?}}v0_f32x4{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f32x4 f32x4 "s0" "fmov"); -// CHECK-LABEL: v0_f64x2: +// CHECK-LABEL: {{("#)?}}v0_f64x2{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 // CHECK: //NO_APP diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs index bb4bd5444db..1310e61c41d 100644 --- a/tests/codegen/array-codegen.rs +++ b/tests/codegen/array-codegen.rs @@ -5,52 +5,58 @@ // CHECK-LABEL: @array_load #[no_mangle] pub fn array_load(a: &[u8; 4]) -> [u8; 4] { - // CHECK: %_0 = alloca [4 x i8], align 1 - // CHECK: %[[TEMP1:.+]] = load <4 x i8>, ptr %a, align 1 - // CHECK: store <4 x i8> %[[TEMP1]], ptr %_0, align 1 - // CHECK: %[[TEMP2:.+]] = load i32, ptr %_0, align 1 - // CHECK: ret i32 %[[TEMP2]] + // CHECK-NOT: alloca + // CHECK: %[[ALLOCA:.+]] = alloca [4 x i8], align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[ALLOCA]], ptr align 1 %a, {{.+}} 4, i1 false) + // CHECK: %[[TEMP:.+]] = load i32, ptr %[[ALLOCA]], align 1 + // CHECK: ret i32 %[[TEMP]] *a } // CHECK-LABEL: @array_store #[no_mangle] pub fn array_store(a: [u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca i32, [[TEMPALIGN:align [0-9]+]] + // CHECK-NOT: alloca // CHECK: %a = alloca [4 x i8] - // CHECK: %[[TEMP:.+]] = load <4 x i8>, ptr %a, align 1 - // CHECK-NEXT: store <4 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK-NOT: alloca + // store i32 %0, ptr %[[TEMP]] + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %a, ptr [[TEMPALIGN]] %[[TEMP]], {{.+}} 4, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %a, {{.+}} 4, i1 false) *p = a; } // CHECK-LABEL: @array_copy #[no_mangle] pub fn array_copy(a: &[u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca // CHECK: %[[LOCAL:.+]] = alloca [4 x i8], align 1 - // CHECK: %[[TEMP1:.+]] = load <4 x i8>, ptr %a, align 1 - // CHECK: store <4 x i8> %[[TEMP1]], ptr %[[LOCAL]], align 1 - // CHECK: %[[TEMP2:.+]] = load <4 x i8>, ptr %[[LOCAL]], align 1 - // CHECK: store <4 x i8> %[[TEMP2]], ptr %p, align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 4, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 4, i1 false) *p = *a; } // CHECK-LABEL: @array_copy_1_element #[no_mangle] pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK-NOT: alloca // CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1 - // CHECK: %[[TEMP1:.+]] = load i8, ptr %a, align 1 - // CHECK: store i8 %[[TEMP1]], ptr %[[LOCAL]], align 1 - // CHECK: %[[TEMP2:.+]] = load i8, ptr %[[LOCAL]], align 1 - // CHECK: store i8 %[[TEMP2]], ptr %p, align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 1, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 1, i1 false) *p = *a; } // CHECK-LABEL: @array_copy_2_elements #[no_mangle] pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: alloca // CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1 - // CHECK: %[[TEMP1:.+]] = load <2 x i8>, ptr %a, align 1 - // CHECK: store <2 x i8> %[[TEMP1]], ptr %[[LOCAL]], align 1 - // CHECK: %[[TEMP2:.+]] = load <2 x i8>, ptr %[[LOCAL]], align 1 - // CHECK: store <2 x i8> %[[TEMP2]], ptr %p, align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 2, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 2, i1 false) *p = *a; } diff --git a/tests/codegen/array-optimized.rs b/tests/codegen/array-optimized.rs index 4cf16f1fb30..42fdbd39b7e 100644 --- a/tests/codegen/array-optimized.rs +++ b/tests/codegen/array-optimized.rs @@ -16,8 +16,8 @@ pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { #[no_mangle] pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = load <2 x i8>, ptr %a, align 1 - // CHECK: store <2 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK: %[[TEMP:.+]] = load i16, ptr %a, align 1 + // CHECK: store i16 %[[TEMP]], ptr %p, align 1 // CHECK: ret *p = *a; } @@ -26,8 +26,8 @@ pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { #[no_mangle] pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) { // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = load <4 x i8>, ptr %a, align 1 - // CHECK: store <4 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK: %[[TEMP:.+]] = load i32, ptr %a, align 1 + // CHECK: store i32 %[[TEMP]], ptr %p, align 1 // CHECK: ret *p = *a; } diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs index fab9f8632fc..86ec9d73afe 100644 --- a/tests/codegen/ascii-char.rs +++ b/tests/codegen/ascii-char.rs @@ -12,7 +12,7 @@ pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar { // CHECK-NOT: panic // CHECK: %[[R:.+]] = urem i32 %v, 10 - // CHECK-NEXT: %[[T:.+]] = trunc i32 %[[R]] to i8 + // CHECK-NEXT: %[[T:.+]] = trunc{{( nuw)?( nsw)?}} i32 %[[R]] to i8 // CHECK-NEXT: %[[D:.+]] = or{{( disjoint)?}} i8 %[[T]], 48 // CHECK-NEXT: ret i8 %[[D]] diff --git a/tests/codegen/atomicptr.rs b/tests/codegen/atomicptr.rs new file mode 100644 index 00000000000..cbbd5615512 --- /dev/null +++ b/tests/codegen/atomicptr.rs @@ -0,0 +1,38 @@ +// LLVM does not support some atomic RMW operations on pointers, so inside codegen we lower those +// to integer atomics, surrounded by casts to and from integer type. +// This test ensures that we do the round-trip correctly for AtomicPtr::fetch_byte_add, and also +// ensures that we do not have such a round-trip for AtomicPtr::swap, because LLVM supports pointer +// arguments to `atomicrmw xchg`. + +//@ compile-flags: -O -Cno-prepopulate-passes +#![crate_type = "lib"] + +#![feature(strict_provenance)] +#![feature(strict_provenance_atomic_ptr)] + +use std::sync::atomic::AtomicPtr; +use std::sync::atomic::Ordering::Relaxed; +use std::ptr::without_provenance_mut; + +// Portability hack so that we can say [[USIZE]] instead of i64/i32/i16 for usize. +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// CHECK-LABEL: @atomicptr_fetch_byte_add +#[no_mangle] +pub fn atomicptr_fetch_byte_add(a: &AtomicPtr<u8>, v: usize) -> *mut u8 { + // CHECK: %[[INTPTR:.*]] = ptrtoint ptr %{{.*}} to [[USIZE]] + // CHECK-NEXT: %[[RET:.*]] = atomicrmw add ptr %{{.*}}, [[USIZE]] %[[INTPTR]] + // CHECK-NEXT: inttoptr [[USIZE]] %[[RET]] to ptr + a.fetch_byte_add(v, Relaxed) +} + +// CHECK-LABEL: @atomicptr_swap +#[no_mangle] +pub fn atomicptr_swap(a: &AtomicPtr<u8>, ptr: *mut u8) -> *mut u8 { + // CHECK-NOT: ptrtoint + // CHECK: atomicrmw xchg ptr %{{.*}}, ptr %{{.*}} monotonic + // CHECK-NOT: inttoptr + a.swap(ptr, Relaxed) +} diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs new file mode 100644 index 00000000000..807873ea368 --- /dev/null +++ b/tests/codegen/cffi/c-variadic-naked.rs @@ -0,0 +1,19 @@ +//@ needs-asm-support +//@ only-x86_64 + +// tests that `va_start` is not injected into naked functions + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![feature(naked_functions)] +#![no_std] + +#[naked] +pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { + // CHECK-NOT: va_start + // CHECK-NOT: alloca + core::arch::asm! { + "ret", + options(noreturn), + } +} diff --git a/tests/codegen/enum/enum-early-otherwise-branch.rs b/tests/codegen/enum/enum-early-otherwise-branch.rs new file mode 100644 index 00000000000..6c7548912da --- /dev/null +++ b/tests/codegen/enum/enum-early-otherwise-branch.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 + +#![crate_type = "lib"] + +pub enum Enum { + A(u32), + B(u32), + C(u32), +} + +#[no_mangle] +pub fn foo(lhs: &Enum, rhs: &Enum) -> bool { + // CHECK-LABEL: define{{.*}}i1 @foo( + // CHECK-NOT: switch + // CHECK-NOT: br + // CHECK: [[SELECT:%.*]] = select + // CHECK-NEXT: ret i1 [[SELECT]] + // CHECK-NEXT: } + match (lhs, rhs) { + (Enum::A(lhs), Enum::A(rhs)) => lhs == rhs, + (Enum::B(lhs), Enum::B(rhs)) => lhs == rhs, + (Enum::C(lhs), Enum::C(rhs)) => lhs == rhs, + _ => false, + } +} diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs new file mode 100644 index 00000000000..97d545e0283 --- /dev/null +++ b/tests/codegen/float/f128.rs @@ -0,0 +1,129 @@ +// Verify that our intrinsics generate the correct LLVM calls for f128 + +#![crate_type = "lib"] +#![feature(f128)] +#![feature(core_intrinsics)] + +// CHECK-LABEL: i1 @f128_eq( +#[no_mangle] +pub fn f128_eq(a: f128, b: f128) -> bool { + // CHECK: fcmp oeq fp128 %{{.+}}, %{{.+}} + a == b +} + +// CHECK-LABEL: i1 @f128_ne( +#[no_mangle] +pub fn f128_ne(a: f128, b: f128) -> bool { + // CHECK: fcmp une fp128 %{{.+}}, %{{.+}} + a != b +} + +// CHECK-LABEL: i1 @f128_gt( +#[no_mangle] +pub fn f128_gt(a: f128, b: f128) -> bool { + // CHECK: fcmp ogt fp128 %{{.+}}, %{{.+}} + a > b +} + +// CHECK-LABEL: i1 @f128_ge( +#[no_mangle] +pub fn f128_ge(a: f128, b: f128) -> bool { + // CHECK: fcmp oge fp128 %{{.+}}, %{{.+}} + a >= b +} + +// CHECK-LABEL: i1 @f128_lt( +#[no_mangle] +pub fn f128_lt(a: f128, b: f128) -> bool { + // CHECK: fcmp olt fp128 %{{.+}}, %{{.+}} + a < b +} + +// CHECK-LABEL: i1 @f128_le( +#[no_mangle] +pub fn f128_le(a: f128, b: f128) -> bool { + // CHECK: fcmp ole fp128 %{{.+}}, %{{.+}} + a <= b +} + +// CHECK-LABEL: fp128 @f128_neg( +#[no_mangle] +pub fn f128_neg(a: f128) -> f128 { + // CHECK: fneg fp128 + -a +} + +// CHECK-LABEL: fp128 @f128_add( +#[no_mangle] +pub fn f128_add(a: f128, b: f128) -> f128 { + // CHECK: fadd fp128 %{{.+}}, %{{.+}} + a + b +} + +// CHECK-LABEL: fp128 @f128_sub( +#[no_mangle] +pub fn f128_sub(a: f128, b: f128) -> f128 { + // CHECK: fsub fp128 %{{.+}}, %{{.+}} + a - b +} + +// CHECK-LABEL: fp128 @f128_mul( +#[no_mangle] +pub fn f128_mul(a: f128, b: f128) -> f128 { + // CHECK: fmul fp128 %{{.+}}, %{{.+}} + a * b +} + +// CHECK-LABEL: fp128 @f128_div( +#[no_mangle] +pub fn f128_div(a: f128, b: f128) -> f128 { + // CHECK: fdiv fp128 %{{.+}}, %{{.+}} + a / b +} + +// CHECK-LABEL: fp128 @f128_rem( +#[no_mangle] +pub fn f128_rem(a: f128, b: f128) -> f128 { + // CHECK: frem fp128 %{{.+}}, %{{.+}} + a % b +} + +// CHECK-LABEL: void @f128_add_assign( +#[no_mangle] +pub fn f128_add_assign(a: &mut f128, b: f128) { + // CHECK: fadd fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a += b; +} + +// CHECK-LABEL: void @f128_sub_assign( +#[no_mangle] +pub fn f128_sub_assign(a: &mut f128, b: f128) { + // CHECK: fsub fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a -= b; +} + +// CHECK-LABEL: void @f128_mul_assign( +#[no_mangle] +pub fn f128_mul_assign(a: &mut f128, b: f128) { + // CHECK: fmul fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a *= b +} + +// CHECK-LABEL: void @f128_div_assign( +#[no_mangle] +pub fn f128_div_assign(a: &mut f128, b: f128) { + // CHECK: fdiv fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a /= b +} + +// CHECK-LABEL: void @f128_rem_assign( +#[no_mangle] +pub fn f128_rem_assign(a: &mut f128, b: f128) { + // CHECK: frem fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a %= b +} diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs new file mode 100644 index 00000000000..d1f75cc3b68 --- /dev/null +++ b/tests/codegen/float/f16.rs @@ -0,0 +1,129 @@ +// Verify that our intrinsics generate the correct LLVM calls for f16 + +#![crate_type = "lib"] +#![feature(f16)] +#![feature(core_intrinsics)] + +// CHECK-LABEL: i1 @f16_eq( +#[no_mangle] +pub fn f16_eq(a: f16, b: f16) -> bool { + // CHECK: fcmp oeq half %{{.+}}, %{{.+}} + a == b +} + +// CHECK-LABEL: i1 @f16_ne( +#[no_mangle] +pub fn f16_ne(a: f16, b: f16) -> bool { + // CHECK: fcmp une half %{{.+}}, %{{.+}} + a != b +} + +// CHECK-LABEL: i1 @f16_gt( +#[no_mangle] +pub fn f16_gt(a: f16, b: f16) -> bool { + // CHECK: fcmp ogt half %{{.+}}, %{{.+}} + a > b +} + +// CHECK-LABEL: i1 @f16_ge( +#[no_mangle] +pub fn f16_ge(a: f16, b: f16) -> bool { + // CHECK: fcmp oge half %{{.+}}, %{{.+}} + a >= b +} + +// CHECK-LABEL: i1 @f16_lt( +#[no_mangle] +pub fn f16_lt(a: f16, b: f16) -> bool { + // CHECK: fcmp olt half %{{.+}}, %{{.+}} + a < b +} + +// CHECK-LABEL: i1 @f16_le( +#[no_mangle] +pub fn f16_le(a: f16, b: f16) -> bool { + // CHECK: fcmp ole half %{{.+}}, %{{.+}} + a <= b +} + +// CHECK-LABEL: half @f16_neg( +#[no_mangle] +pub fn f16_neg(a: f16) -> f16 { + // CHECK: fneg half %{{.+}} + -a +} + +// CHECK-LABEL: half @f16_add( +#[no_mangle] +pub fn f16_add(a: f16, b: f16) -> f16 { + // CHECK: fadd half %{{.+}}, %{{.+}} + a + b +} + +// CHECK-LABEL: half @f16_sub( +#[no_mangle] +pub fn f16_sub(a: f16, b: f16) -> f16 { + // CHECK: fsub half %{{.+}}, %{{.+}} + a - b +} + +// CHECK-LABEL: half @f16_mul( +#[no_mangle] +pub fn f16_mul(a: f16, b: f16) -> f16 { + // CHECK: fmul half %{{.+}}, %{{.+}} + a * b +} + +// CHECK-LABEL: half @f16_div( +#[no_mangle] +pub fn f16_div(a: f16, b: f16) -> f16 { + // CHECK: fdiv half %{{.+}}, %{{.+}} + a / b +} + +// CHECK-LABEL: half @f16_rem( +#[no_mangle] +pub fn f16_rem(a: f16, b: f16) -> f16 { + // CHECK: frem half %{{.+}}, %{{.+}} + a % b +} + +// CHECK-LABEL: void @f16_add_assign( +#[no_mangle] +pub fn f16_add_assign(a: &mut f16, b: f16) { + // CHECK: fadd half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a += b; +} + +// CHECK-LABEL: void @f16_sub_assign( +#[no_mangle] +pub fn f16_sub_assign(a: &mut f16, b: f16) { + // CHECK: fsub half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a -= b; +} + +// CHECK-LABEL: void @f16_mul_assign( +#[no_mangle] +pub fn f16_mul_assign(a: &mut f16, b: f16) { + // CHECK: fmul half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a *= b +} + +// CHECK-LABEL: void @f16_div_assign( +#[no_mangle] +pub fn f16_div_assign(a: &mut f16, b: f16) { + // CHECK: fdiv half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a /= b +} + +// CHECK-LABEL: void @f16_rem_assign( +#[no_mangle] +pub fn f16_rem_assign(a: &mut f16, b: f16) { + // CHECK: frem half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a %= b +} diff --git a/tests/codegen/issues/issue-122805.rs b/tests/codegen/issues/issue-122805.rs new file mode 100644 index 00000000000..6d108ada6dd --- /dev/null +++ b/tests/codegen/issues/issue-122805.rs @@ -0,0 +1,55 @@ +//@ revisions: OPT2 OPT3WINX64 OPT3LINX64 +//@ [OPT2] compile-flags: -O +//@ [OPT3LINX64] compile-flags: -C opt-level=3 +//@ [OPT3WINX64] compile-flags: -C opt-level=3 +//@ [OPT3LINX64] only-linux +//@ [OPT3WINX64] only-windows +//@ [OPT3LINX64] only-x86_64 +//@ [OPT3WINX64] only-x86_64 +//@ min-llvm-version: 18.1.3 + +#![crate_type = "lib"] +#![no_std] + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +// OPT2: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 2 +// OPT2-NEXT: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 4 +// OPT2-NEXT: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 6 +// OPT2-NEXT: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 8 +// OPT2-NEXT: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 10 +// OPT2-NEXT: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 12 +// OPT2-NEXT: store i16 +// OPT2-NEXT: getelementptr inbounds i8, {{.+}} 14 +// OPT2-NEXT: store i16 +// OPT3LINX64: load <8 x i16> +// OPT3LINX64-NEXT: call <8 x i16> @llvm.bswap +// OPT3LINX64-NEXT: store <8 x i16> +// OPT3WINX64: load <8 x i16> +// OPT3WINX64-NEXT: call <8 x i16> @llvm.bswap +// OPT3WINX64-NEXT: store <8 x i16> +// CHECK-NEXT: ret void +#[no_mangle] +#[cfg(target_endian = "little")] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + let addr16 = [ + value[0].to_be(), + value[1].to_be(), + value[2].to_be(), + value[3].to_be(), + value[4].to_be(), + value[5].to_be(), + value[6].to_be(), + value[7].to_be(), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs index 09907edf8f2..5cecafb9f29 100644 --- a/tests/codegen/match-optimized.rs +++ b/tests/codegen/match-optimized.rs @@ -26,12 +26,12 @@ pub fn exhaustive_match(e: E) -> u8 { // CHECK-NEXT: store i8 1, ptr %_0, align 1 // CHECK-NEXT: br label %[[EXIT]] // CHECK: [[C]]: -// CHECK-NEXT: store i8 2, ptr %_0, align 1 +// CHECK-NEXT: store i8 3, ptr %_0, align 1 // CHECK-NEXT: br label %[[EXIT]] match e { E::A => 0, E::B => 1, - E::C => 2, + E::C => 3, } } diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs index b00fbad05d9..50b43f5854a 100644 --- a/tests/codegen/mem-replace-simple-type.rs +++ b/tests/codegen/mem-replace-simple-type.rs @@ -45,9 +45,7 @@ pub fn replace_short_array_3(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] { // CHECK-LABEL: @replace_short_array_4( pub fn replace_short_array_4(r: &mut [u32; 4], v: [u32; 4]) -> [u32; 4] { // CHECK-NOT: alloca - // CHECK: %[[R:.+]] = load <4 x i32>, ptr %r, align 4 - // CHECK: store <4 x i32> %[[R]], ptr %result - // CHECK: %[[V:.+]] = load <4 x i32>, ptr %v, align 4 - // CHECK: store <4 x i32> %[[V]], ptr %r + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %result, ptr align 4 %r, i64 16, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 16, i1 false) std::mem::replace(r, v) } diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 755dd155112..3c426825537 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -19,7 +19,7 @@ pub unsafe extern "C" fn naked_empty() { } // CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b) +// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %0, i64 %1) #[no_mangle] #[naked] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs new file mode 100644 index 00000000000..dfe83443348 --- /dev/null +++ b/tests/codegen/pattern_type_symbols.rs @@ -0,0 +1,23 @@ +//! Check that symbol names with pattern types in them are +//! different from the same symbol with the base type + +//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib + +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999); + +fn foo<T>() {} + +pub fn bar() { + // CHECK: call pattern_type_symbols::foo::<u32> + // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_ + foo::<u32>(); + // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])> + // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_ + foo::<NanoU32>(); +} diff --git a/tests/codegen/powerpc64le-struct-align-128.rs b/tests/codegen/powerpc64le-struct-align-128.rs new file mode 100644 index 00000000000..0096c6d3138 --- /dev/null +++ b/tests/codegen/powerpc64le-struct-align-128.rs @@ -0,0 +1,93 @@ +// Test that structs aligned to 128 bits are passed with the correct ABI on powerpc64le. +// This is similar to aarch64-struct-align-128.rs, but for ppc. + +//@ compile-flags: --target powerpc64le-unknown-linux-gnu +//@ needs-llvm-components: powerpc + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Align8 { + pub a: u64, + pub b: u64, +} + +#[repr(transparent)] +pub struct Transparent8 { + a: Align8 +} + +#[repr(C)] +pub struct Wrapped8 { + a: Align8, +} + +extern "C" { + // CHECK: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) + fn test_8(a: Align8, b: Transparent8, c: Wrapped8); +} + +#[repr(C)] +#[repr(align(16))] +pub struct Align16 { + pub a: u64, + pub b: u64, +} + +#[repr(transparent)] +pub struct Transparent16 { + a: Align16 +} + +#[repr(C)] +pub struct Wrapped16 { + pub a: Align16, +} + +extern "C" { + // It's important that this produces [1 x i128] rather than just i128! + // CHECK: declare void @test_16([1 x i128], [1 x i128], [1 x i128]) + fn test_16(a: Align16, b: Transparent16, c: Wrapped16); +} + +#[repr(C)] +#[repr(align(32))] +pub struct Align32 { + pub a: u64, + pub b: u64, + pub c: u64, +} + +#[repr(transparent)] +pub struct Transparent32 { + a: Align32 +} + +#[repr(C)] +pub struct Wrapped32 { + pub a: Align32, +} + +extern "C" { + // CHECK: declare void @test_32([2 x i128], [2 x i128], [2 x i128]) + fn test_32(a: Align32, b: Transparent32, c: Wrapped32); +} + +pub unsafe fn main( + a1: Align8, a2: Transparent8, a3: Wrapped8, + b1: Align16, b2: Transparent16, b3: Wrapped16, + c1: Align32, c2: Transparent32, c3: Wrapped32, +) { + test_8(a1, a2, a3); + test_16(b1, b2, b3); + test_32(c1, c2, c3); +} diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs new file mode 100644 index 00000000000..5d545af9c76 --- /dev/null +++ b/tests/codegen/riscv-target-abi.rs @@ -0,0 +1,20 @@ +//@ revisions:riscv64gc riscv32gc riscv32imac + +//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu +//@[riscv64gc] needs-llvm-components: riscv +// riscv64gc: !{i32 1, !"target-abi", !"lp64d"} + +//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl +//@[riscv32gc] needs-llvm-components: riscv +// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"} + +//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf +//@[riscv32imac] needs-llvm-components: riscv +// riscv32imac-NOT: !"target-abi" + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs index ab3d339989b..c5dadf70de9 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs @@ -34,12 +34,12 @@ pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnO // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} // CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_S3_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs index cc7178e41c7..6d9fe7040f7 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs @@ -132,7 +132,7 @@ pub fn foo27(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>, _: &dyn Trait // CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} -// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEEE"} +// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEEE"} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} // CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} @@ -148,14 +148,14 @@ pub fn foo27(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>, _: &dyn Trait // CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"} // CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"} // CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"} -// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu5paramEu6regionEEE"} -// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu5paramEu6regionEEE"} -// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu5paramEu6regionEES4_E"} -// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu5paramEu6regionEES4_S4_E"} -// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu5paramLu5usizeEEu6regionEEE"} -// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu5paramLu5usizeEEu6regionEES5_E"} -// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu5paramLu5usizeEEu6regionEES5_S5_E"} +// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_E"} +// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_S3_E"} +// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEEE"} +// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_E"} +// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_S3_E"} +// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EEE"} +// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_E"} +// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_S6_E"} +// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEEE"} +// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_E"} +// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_S5_E"} diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs index ecce9201071..3d284148db2 100644 --- a/tests/codegen/slice-indexing.rs +++ b/tests/codegen/slice-indexing.rs @@ -32,3 +32,31 @@ pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut // CHECK: sub nuw i64 x.get_unchecked_mut(r) } + +// CHECK-LABEL: @str_index_by_range( +#[no_mangle] +pub fn str_index_by_range(x: &str, r: Range<usize>) -> &str { + // CHECK: sub nuw i64 + &x[r] +} + +// CHECK-LABEL: @str_get_unchecked_by_range( +#[no_mangle] +pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range<usize>) -> &str { + // CHECK: sub nuw i64 + x.get_unchecked(r) +} + +// CHECK-LABEL: @str_index_mut_by_range( +#[no_mangle] +pub fn str_index_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str { + // CHECK: sub nuw i64 + &mut x[r] +} + +// CHECK-LABEL: @str_get_unchecked_mut_by_range( +#[no_mangle] +pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str { + // CHECK: sub nuw i64 + x.get_unchecked_mut(r) +} diff --git a/tests/codegen/step_by-overflow-checks.rs b/tests/codegen/step_by-overflow-checks.rs new file mode 100644 index 00000000000..43e8514a8b7 --- /dev/null +++ b/tests/codegen/step_by-overflow-checks.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +use std::iter::StepBy; +use std::slice::Iter; + +// The constructor for `StepBy` ensures we can never end up needing to do zero +// checks on denominators, so check that the code isn't emitting panic paths. + +// CHECK-LABEL: @step_by_len_std +#[no_mangle] +pub fn step_by_len_std(x: &StepBy<Iter<i32>>) -> usize { + // CHECK-NOT: div_by_zero + // CHECK: udiv + // CHECK-NOT: div_by_zero + x.len() +} + +// CHECK-LABEL: @step_by_len_naive +#[no_mangle] +pub fn step_by_len_naive(x: Iter<i32>, step_minus_one: usize) -> usize { + // CHECK: udiv + // CHECK: call{{.+}}div_by_zero + x.len() / (step_minus_one + 1) +} diff --git a/tests/codegen/ub-checks.rs b/tests/codegen/ub-checks.rs new file mode 100644 index 00000000000..de48d74e652 --- /dev/null +++ b/tests/codegen/ub-checks.rs @@ -0,0 +1,28 @@ +// With -Zub-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a runtime +// check that the index to slice::get_unchecked is in-bounds of the slice. That is tested for by +// tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs +// +// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled, +// but ub-checks are explicitly disabled. + +//@ revisions: DEBUG NOCHECKS +//@ [DEBUG] compile-flags: +//@ [NOCHECKS] compile-flags: -Zub-checks=no +//@ compile-flags: -O -Cdebug-assertions=yes + +#![crate_type = "lib"] + +use std::ops::Range; + +// CHECK-LABEL: @slice_get_unchecked( +#[no_mangle] +pub unsafe fn slice_get_unchecked(x: &[i32], i: usize) -> &i32 { + // CHECK: icmp ult + // NOCHECKS: tail call void @llvm.assume + // DEBUG: br i1 + // DEBUG: call core::panicking::panic_nounwind + // DEBUG: unreachable + // CHECK: getelementptr inbounds + // CHECK: ret ptr + x.get_unchecked(i) +} diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs index 7d020fbb4d2..86517c89627 100644 --- a/tests/codegen/unchecked_shifts.rs +++ b/tests/codegen/unchecked_shifts.rs @@ -22,7 +22,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16 // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16 + // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16 // CHECK-DAG: shl i16 %a, %[[TRUNC]] a.unchecked_shl(b) } @@ -54,7 +54,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16 // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16 + // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16 // CHECK-DAG: ashr i16 %a, %[[TRUNC]] a.unchecked_shr(b) } @@ -94,7 +94,7 @@ pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 { // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8 // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8 + // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8 // CHECK-DAG: shl i8 %a, %[[TRUNC]] std::intrinsics::unchecked_shl(a, b) } @@ -107,7 +107,7 @@ pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 { // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8 // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8 + // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8 // CHECK-DAG: ashr i8 %a, %[[TRUNC]] std::intrinsics::unchecked_shr(a, b) } diff --git a/tests/codegen/vecdeque_pop_push.rs b/tests/codegen/vecdeque_pop_push.rs new file mode 100644 index 00000000000..040d5a279dc --- /dev/null +++ b/tests/codegen/vecdeque_pop_push.rs @@ -0,0 +1,67 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +#[no_mangle] +// CHECK-LABEL: @noop_back( +pub fn noop_back(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @noop_front( +pub fn noop_front(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_front_to_back( +pub fn move_byte_front_to_back(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_back_to_front( +pub fn move_byte_back_to_front(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @push_back_byte( +pub fn push_back_byte(v: &mut VecDeque<u8>) { + // CHECK: call {{.*}}grow + v.push_back(3); +} + +#[no_mangle] +// CHECK-LABEL: @push_front_byte( +pub fn push_front_byte(v: &mut VecDeque<u8>) { + // CHECK: call {{.*}}grow + v.push_front(3); +} diff --git a/tests/crashes/100041.rs b/tests/crashes/100041.rs new file mode 100644 index 00000000000..4d113cbe9ed --- /dev/null +++ b/tests/crashes/100041.rs @@ -0,0 +1,17 @@ +//@ known-bug: #100041 + +pub trait WellUnformed { + type RequestNormalize; +} + +impl<T: ?Sized> WellUnformed for T { + type RequestNormalize = (); +} + +pub fn latent(_: &[<[[()]] as WellUnformed>::RequestNormalize; 0]) {} + +pub fn bang() { + latent(&[]); +} + +fn main() {} diff --git a/tests/crashes/101036.rs b/tests/crashes/101036.rs new file mode 100644 index 00000000000..72334985820 --- /dev/null +++ b/tests/crashes/101036.rs @@ -0,0 +1,14 @@ +//@ known-bug: #101036 +#![feature(generic_const_exprs)] + +const fn t<const N: usize>() -> u8 { + N as u8 +} + +#[repr(u8)] +enum T<const N: u8 = { T::<0>::A as u8 + T::<0>::B as u8 }> +where + [(); N as usize]: +{ + A = t::<N>() as u8, B +} diff --git a/tests/crashes/101557.rs b/tests/crashes/101557.rs new file mode 100644 index 00000000000..a0290361ed1 --- /dev/null +++ b/tests/crashes/101557.rs @@ -0,0 +1,42 @@ +//@ known-bug: #101557 +//@ compile-flags: -Copt-level=0 +#![feature(generic_const_exprs)] +use std::marker::PhantomData; + +trait Trait { + const CONST: usize; +} + +struct A<T: Trait> { + _marker: PhantomData<T>, +} + +impl<const N: usize> Trait for [i8; N] { + const CONST: usize = N; +} + +impl<const N: usize> From<usize> for A<[i8; N]> { + fn from(_: usize) -> Self { + todo!() + } +} + +impl<T: Trait> From<A<[i8; T::CONST]>> for A<T> { + fn from(_: A<[i8; T::CONST]>) -> Self { + todo!() + } +} + +fn f<T: Trait>() -> A<T> +where + [(); T::CONST]:, +{ + // Usage of `0` is arbitrary + let a = A::<[i8; T::CONST]>::from(0); + A::<T>::from(a) +} + +fn main() { + // Usage of `1` is arbitrary + f::<[i8; 1]>(); +} diff --git a/tests/crashes/101962.rs b/tests/crashes/101962.rs new file mode 100644 index 00000000000..b6a78ce053a --- /dev/null +++ b/tests/crashes/101962.rs @@ -0,0 +1,11 @@ +//@ known-bug: #101962 + +#![feature(core_intrinsics)] + +pub fn wrapping<T: Copy>(a: T, b: T) { + let _z = core::intrinsics::wrapping_mul(a, b); +} + +fn main() { + wrapping(1,2); +} diff --git a/tests/crashes/102047.rs b/tests/crashes/102047.rs new file mode 100644 index 00000000000..61976f51273 --- /dev/null +++ b/tests/crashes/102047.rs @@ -0,0 +1,45 @@ +//@ known-bug: #102047 + +struct Ty1; +struct Ty2; + +pub trait Trait<T> {} + +pub trait WithAssoc1<'a> { + type Assoc; +} +pub trait WithAssoc2<'a> { + type Assoc; +} + +impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) +where + T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, + U: for<'a> WithAssoc2<'a>, +{ +} + +impl WithAssoc1<'_> for Ty1 { + type Assoc = (); +} +impl WithAssoc2<'_> for Ty1 { + type Assoc = i32; +} +impl WithAssoc1<'_> for Ty2 { + type Assoc = (); +} +impl WithAssoc2<'_> for Ty2 { + type Assoc = u32; +} + +fn foo<T, U, V>() +where + T: for<'a> WithAssoc1<'a>, + U: for<'a> WithAssoc2<'a>, + (T, U): Trait<V>, +{ +} + +fn main() { + foo::<Ty1, Ty2, _>(); +} diff --git a/tests/crashes/102252.rs b/tests/crashes/102252.rs new file mode 100644 index 00000000000..200782f95c8 --- /dev/null +++ b/tests/crashes/102252.rs @@ -0,0 +1,14 @@ +//@ known-bug: #102252 + +#![feature(min_specialization, rustc_attrs)] + +#[rustc_specialization_trait] +pub trait Trait {} + +struct Struct +where + Self: Iterator<Item = <Self as Iterator>::Item>, {} + +impl Trait for Struct {} + +fn main() {} diff --git a/tests/crashes/103899.rs b/tests/crashes/103899.rs new file mode 100644 index 00000000000..39c2d72bd35 --- /dev/null +++ b/tests/crashes/103899.rs @@ -0,0 +1,27 @@ +//@ known-bug: #103899 + +trait BaseWithAssoc { + type Assoc; +} + +trait WrapperWithAssoc { + type BaseAssoc: BaseWithAssoc; +} + +struct Wrapper<B> { + inner: B, +} + +struct ProjectToBase<T: BaseWithAssoc> { + data_type_h: T::Assoc, +} + +struct DoubleProject<L: WrapperWithAssoc> { + buffer: Wrapper<ProjectToBase<L::BaseAssoc>>, +} + +fn trigger<L: WrapperWithAssoc<BaseAssoc = ()>>() -> DoubleProject<L> { + loop {} +} + +fn main() {} diff --git a/tests/crashes/105238-1.rs b/tests/crashes/105238-1.rs new file mode 100644 index 00000000000..dd44a0f1d77 --- /dev/null +++ b/tests/crashes/105238-1.rs @@ -0,0 +1,31 @@ +//@ known-bug: #105238 + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Ret { + type R; +} + +struct Cond<const PRED: bool, U, V>(std::marker::PhantomData<U>, std::marker::PhantomData<V>); + +impl<U, V> Ret for Cond<true, U, V> { + type R = U; +} + +impl<U, V> Ret for Cond<false, U, V> { + type R = V; +} + +struct RobinHashTable<const MAX_LENGTH: usize, CellIdx = Cond<{ MAX_LENGTH < 65535 }, u16, u32>> +where + CellIdx: Ret, +{ + _idx: CellIdx::R, +} + +fn main() { + use std::mem::size_of; + println!("{}", size_of::<RobinHashTable<1024>>()); + println!("{}", size_of::<RobinHashTable<65536>>()); +} diff --git a/tests/crashes/105238-2.rs b/tests/crashes/105238-2.rs new file mode 100644 index 00000000000..368595c6a2a --- /dev/null +++ b/tests/crashes/105238-2.rs @@ -0,0 +1,31 @@ +//@ known-bug: #105238 + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Ret { + type R; +} + +struct Cond<const PRED: bool, U, V>(std::marker::PhantomData<U>, std::marker::PhantomData<V>); + +impl<U, V> Ret for Cond<true, U, V> { + type R = U; +} + +impl<U, V> Ret for Cond<false, U, V> { + type R = V; +} + +struct RobinHashTable< + const MAX_LENGTH: usize, + CellIdx = <Cond<{ MAX_LENGTH < 65535 }, u16, u32> as Ret>::R, +> { + _idx: CellIdx, +} + +fn main() { + use std::mem::size_of; + println!("{}", size_of::<RobinHashTable<1024>>()); + println!("{}", size_of::<RobinHashTable<65536>>()); +} diff --git a/tests/crashes/105275.rs b/tests/crashes/105275.rs new file mode 100644 index 00000000000..a97f36d1987 --- /dev/null +++ b/tests/crashes/105275.rs @@ -0,0 +1,27 @@ +//@ known-bug: #105275 +//@ compile-flags: -Copt-level=0 + +pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> { + if n > 15 { + encode_num(n / 16, &mut writer)?; + } + Ok(()) +} + +pub trait ExampleWriter { + type Error; +} + +impl<'a, T: ExampleWriter> ExampleWriter for &'a mut T { + type Error = T::Error; +} + +struct Error; + +impl ExampleWriter for Error { + type Error = (); +} + +fn main() { + encode_num(69, &mut Error).unwrap(); +} diff --git a/tests/crashes/105937.rs b/tests/crashes/105937.rs new file mode 100644 index 00000000000..ffd1a493e46 --- /dev/null +++ b/tests/crashes/105937.rs @@ -0,0 +1,27 @@ +//@ known-bug: #105937 +//@ compile-flags: -Copt-level=0 + +pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> { + if n > 15 { + encode_num(n / 16, &mut writer)?; + } + Ok(()) +} + +pub trait ExampleWriter { + type Error; +} + +impl<'a, T: ExampleWriter> ExampleWriter for &'a mut T { + type Error = T::Error; +} + +struct Error; + +impl ExampleWriter for Error { + type Error = (); +} + +fn main() { + encode_num(69, &mut Error).unwrap(); +} diff --git a/tests/crashes/106473.rs b/tests/crashes/106473.rs new file mode 100644 index 00000000000..b0a129cac01 --- /dev/null +++ b/tests/crashes/106473.rs @@ -0,0 +1,12 @@ +//@ known-bug: #106473 +#![feature(generic_const_exprs)] + +const DEFAULT: u32 = 1; + +struct V<const U: usize = DEFAULT> +where + [(); U]:; + +trait Tr {} + +impl Tr for V {} diff --git a/tests/crashes/108814.rs b/tests/crashes/108814.rs new file mode 100644 index 00000000000..c8db848f2e1 --- /dev/null +++ b/tests/crashes/108814.rs @@ -0,0 +1,9 @@ +//@ known-bug: #108814 + +#![feature(non_lifetime_binders)] + +fn take(_: impl for<T> FnOnce(T) -> T) {} + +fn main() { + take(|x| x) +} diff --git a/tests/crashes/109681.rs b/tests/crashes/109681.rs new file mode 100644 index 00000000000..73ff1007094 --- /dev/null +++ b/tests/crashes/109681.rs @@ -0,0 +1,9 @@ +//@ known-bug: #109681 + +#![crate_type="lib"] +#![feature(linkage)] + +#[linkage = "common"] +pub static TEST3: bool = true; + +fn main() {} diff --git a/tests/crashes/110378.rs b/tests/crashes/110378.rs new file mode 100644 index 00000000000..93de62d4139 --- /dev/null +++ b/tests/crashes/110378.rs @@ -0,0 +1,15 @@ +//@ known-bug: #110378 +// ignore-tidy-linelength + +#![feature(generic_const_exprs)] + +fn foo<const L: usize>(_a: [u8; L], _b: [u8; L]) -> [u8; L + 1] { + [0_u8; L + 1] +} + +fn main() { + let baz = [[0_u8; 1]; 8]; + + let _: [u8; 4] = foo(foo(foo(baz[0], baz[1]), foo(baz[2], baz[3])), foo(foo(baz[4], baz[5]), foo(baz[6], baz[7]))); + //let _: [u8; 3] = foo(foo(baz[0], baz[1]), foo(baz[2], baz[3])); +} diff --git a/tests/crashes/110534.rs b/tests/crashes/110534.rs new file mode 100644 index 00000000000..240ff6c2704 --- /dev/null +++ b/tests/crashes/110534.rs @@ -0,0 +1,44 @@ +//@ known-bug: #110534 +//@ edition:2021 +use core::cell::Ref; + +struct System; + +trait IntoSystem { + fn into_system(self) -> System; +} + +impl IntoSystem for fn(Ref<'_, u32>) { + fn into_system(self) -> System { System } +} + +impl<A> IntoSystem for fn(A) +where + // n.b. No `Ref<'_, u32>` can satisfy this bound + A: 'static + for<'x> MaybeBorrowed<'x, Output = A>, +{ + fn into_system(self) -> System { System } +} + +//--------------------------------------------------- + +trait MaybeBorrowed<'a> { + type Output: 'a; +} + +// If you comment this out you'll see the compiler chose to look at the +// fn(A) implementation of IntoSystem above +impl<'a, 'b> MaybeBorrowed<'a> for Ref<'b, u32> { + type Output = Ref<'a, u32>; +} + +// --------------------------------------------- + +fn main() { + fn sys_ref(_age: Ref<u32>) {} + let _sys_c = (sys_ref as fn(_)).into_system(); + // properly fails + // let _sys_c = (sys_ref as fn(Ref<'static, u32>)).into_system(); + // properly succeeds + // let _sys_c = (sys_ref as fn(Ref<'_, u32>)).into_system(); +} diff --git a/tests/crashes/110627.rs b/tests/crashes/110627.rs new file mode 100644 index 00000000000..752682fa605 --- /dev/null +++ b/tests/crashes/110627.rs @@ -0,0 +1,8 @@ +//@ known-bug: #110627 +#![feature(non_lifetime_binders)] + +fn take(id: impl for<T> Fn(T) -> T) {} + +fn main() { + take(|x| x) +} diff --git a/tests/crashes/110630.rs b/tests/crashes/110630.rs new file mode 100644 index 00000000000..f17f6f0781f --- /dev/null +++ b/tests/crashes/110630.rs @@ -0,0 +1,28 @@ +//@ known-bug: #110630 + +#![feature(generic_const_exprs)] + +use std::ops::Mul; + +pub trait Indices<const N: usize> { + const NUM_ELEMS: usize = I::NUM_ELEMS * N; +} + +pub trait Concat<J> { + type Output; +} + +pub struct Tensor<I: Indices<N>, const N: usize> +where + [u8; I::NUM_ELEMS]: Sized, {} + +impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N> +where + I: Concat<T>, + <I as Concat<J>>::Output: Indices<N>, + [u8; I::NUM_ELEMS]: Sized, + [u8; J::NUM_ELEMS]: Sized, + [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized, +{ + type Output = Tensor<<I as Concat<J>>::Output, N>; +} diff --git a/tests/crashes/111419.rs b/tests/crashes/111419.rs new file mode 100644 index 00000000000..3a1a13df198 --- /dev/null +++ b/tests/crashes/111419.rs @@ -0,0 +1,14 @@ +//@ known-bug: #111419 +#![allow(incomplete_features)] +#![feature(generic_const_exprs, generic_arg_infer)] + +pub trait Example<const X: usize, const Y: usize, const Z: usize = { X + Y }> +where + [(); X + Y]:, +{} + +impl<const X: usize, const Y: usize> Example<X, Y> for Value {} + +pub struct Value; + +fn main() {} diff --git a/tests/crashes/111699.rs b/tests/crashes/111699.rs new file mode 100644 index 00000000000..5ba17c2aa1a --- /dev/null +++ b/tests/crashes/111699.rs @@ -0,0 +1,14 @@ +//@ known-bug: #111699 +//@ edition:2021 +//@ compile-flags: -Copt-level=0 +#![feature(core_intrinsics)] +use std::intrinsics::offset; + +fn main() { + let a = [1u8, 2, 3]; + let ptr: *const u8 = a.as_ptr(); + + unsafe { + assert_eq!(*offset(ptr, 0), 1); + } +} diff --git a/tests/crashes/111709-2.rs b/tests/crashes/111709-2.rs new file mode 100644 index 00000000000..6c4fb9f28c7 --- /dev/null +++ b/tests/crashes/111709-2.rs @@ -0,0 +1,15 @@ +//@ known-bug: #111709 +//@ edition: 2021 + +use core::arch::asm; + +extern "C" fn test<T>() {} + +fn uwu() { + unsafe { + asm!( + "/* {0} */", + sym test::<&mut ()> + ); + } +} diff --git a/tests/crashes/111709.rs b/tests/crashes/111709.rs new file mode 100644 index 00000000000..eef375b8924 --- /dev/null +++ b/tests/crashes/111709.rs @@ -0,0 +1,25 @@ +//@ known-bug: #111709 +//@ edition:2021 + +use core::arch::asm; + +struct TrapFrame; + +unsafe extern "C" fn _rust_abi_shim1<A, R>(arg: A, f: fn(A) -> R) -> R { + f(arg) +} + +unsafe extern "C" fn _start_trap() { + extern "Rust" { + fn interrupt(tf: &mut TrapFrame); + } + asm!( + " + la a1, {irq} + call {shim} + ", + shim = sym crate::_rust_abi_shim1::<&mut TrapFrame, ()>, + irq = sym interrupt, + options(noreturn) + ) +} diff --git a/tests/crashes/111742.rs b/tests/crashes/111742.rs new file mode 100644 index 00000000000..fda2a96836f --- /dev/null +++ b/tests/crashes/111742.rs @@ -0,0 +1,12 @@ +//@ known-bug: #111742 +// ignore-tidy-linelength + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +const CONST: u32 = 0; +struct Test<const N: u32, const M: u32 = { CONST/* Must be a const and not a Literal */ }> where [(); N as usize]: , ([u32; N as usize]); + +fn main() { + let _: Test<1>; +} diff --git a/tests/crashes/111883.rs b/tests/crashes/111883.rs new file mode 100644 index 00000000000..fa72b28c228 --- /dev/null +++ b/tests/crashes/111883.rs @@ -0,0 +1,40 @@ +//@ known-bug: #111883 +#![crate_type = "lib"] +#![feature(arbitrary_self_types, no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} +#[lang = "receiver"] +trait Receiver {} +#[lang = "dispatch_from_dyn"] +trait DispatchFromDyn<T> {} +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +#[lang = "unsize"] +trait Unsize<T: ?Sized> {} +#[lang = "coerce_unsized"] +pub trait CoerceUnsized<T: ?Sized> {} +impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} + +#[lang = "drop_in_place"] +fn drop_in_place_fn<T>(a: &dyn Trait2<T>) {} + +pub trait Trait1 { + fn foo(&self); +} + +pub struct Type1; + +impl Trait1 for Type1 { + fn foo(&self) {} +} + +pub trait Trait2<T> {} + +pub fn bar1() { + let a = Type1; + let b = &a as &dyn Trait1; + b.foo(); +} diff --git a/tests/crashes/112201.rs b/tests/crashes/112201.rs new file mode 100644 index 00000000000..5d363403b8a --- /dev/null +++ b/tests/crashes/112201.rs @@ -0,0 +1,19 @@ +//@ known-bug: #112201 + +pub fn compose( + f1: impl FnOnce(f64) -> f64 + Clone, + f2: impl FnOnce(f64) -> f64 + Clone, +) -> impl FnOnce(f64) -> f64 + Clone { + move |x| f1(f2(x)) +} + +fn repeat_helper( + f: impl FnOnce(f64) -> f64 + Clone, + res: impl FnOnce(f64) -> f64 + Clone, + times: usize, +) -> impl FnOnce(f64) -> f64 + Clone { + return res; + repeat_helper(f.clone(), compose(f, res), times - 1) +} + +fn main() {} diff --git a/tests/crashes/113272.rs b/tests/crashes/113272.rs new file mode 100644 index 00000000000..d161575c657 --- /dev/null +++ b/tests/crashes/113272.rs @@ -0,0 +1,16 @@ +//@ known-bug: #113272 +trait Trait { + type RefTarget; +} + +impl Trait for () where Missing: Trait {} + +struct Other { + data: <() as Trait>::RefTarget, +} + +fn main() { + unsafe { + std::mem::transmute::<Option<()>, Option<&Other>>(None); + } +} diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs new file mode 100644 index 00000000000..86677f416fe --- /dev/null +++ b/tests/crashes/113280.rs @@ -0,0 +1,16 @@ +//@ known-bug: #113280 +//@ only-x86_64 + +#![feature(dyn_star, pointer_like_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; +use std::marker::PointerLike; + +fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a { + f32::from_bits(0x1) as f64 +} + +fn main() { + println!("{:?}", make_dyn_star(Box::new(1i32))); +} diff --git a/tests/crashes/113379.rs b/tests/crashes/113379.rs new file mode 100644 index 00000000000..7163cbc3934 --- /dev/null +++ b/tests/crashes/113379.rs @@ -0,0 +1,7 @@ +//@ known-bug: #113379 + +async fn f999() -> Vec<usize> { + 'b: { + continue 'b; + } +} diff --git a/tests/crashes/113846.rs b/tests/crashes/113846.rs new file mode 100644 index 00000000000..0e5afb4da61 --- /dev/null +++ b/tests/crashes/113846.rs @@ -0,0 +1,32 @@ +//@ known-bug: #113846 +trait Www { + type W; +} + +trait Xxx: Www<W = Self::X> { + type X; +} + +trait Yyy: Xxx {} + +trait Zzz<'a>: Yyy + Xxx<X = Self::Z> { + type Z; +} + +trait Aaa { + type Y: Yyy; +} + +trait Bbb: Aaa<Y = Self::B> { + type B: for<'a> Zzz<'a>; +} + +impl<T> Bbb for T +where + T: Aaa, + T::Y: for<'a> Zzz<'a>, +{ + type B = T::Y; +} + +pub fn main() {} diff --git a/tests/crashes/114212-2.rs b/tests/crashes/114212-2.rs new file mode 100644 index 00000000000..a430c1b40d3 --- /dev/null +++ b/tests/crashes/114212-2.rs @@ -0,0 +1,16 @@ +//@ known-bug: #114212 +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +const SOME_CONST: usize = 1; + +struct UwU< + // have a const generic with a default that's from another const item + // (associated consts work, a const declared in a block here, inline_const, etc) + const N: usize = SOME_CONST, + // use the previous const in a type generic + A = [(); N], +> { + // here to suppress "unused generic" error if the code stops ICEing + _x: core::marker::PhantomData<A>, +} diff --git a/tests/crashes/114212.rs b/tests/crashes/114212.rs new file mode 100644 index 00000000000..8642dbe8e71 --- /dev/null +++ b/tests/crashes/114212.rs @@ -0,0 +1,34 @@ +//@ known-bug: #114212 + +#![feature(generic_const_exprs)] + +use core::marker::PhantomData; + +pub const DEFAULT_MAX_INPUT_LEN: usize = 256; + +pub trait FooTrait {} + +pub struct Foo<const MAX_INPUT_LEN: usize>; + +impl<const MAX_INPUT_LEN: usize> FooTrait for Foo<MAX_INPUT_LEN> {} + +pub struct Bar< + const MAX_INPUT_LEN: usize = DEFAULT_MAX_INPUT_LEN, + PB = Foo<MAX_INPUT_LEN>, +> +where + PB: FooTrait, +{ + _pb: PhantomData<PB>, +} + +impl<const MAX_INPUT_LEN: usize, PB> Bar<MAX_INPUT_LEN, PB> +where + PB: FooTrait, +{ + pub fn new() -> Self { + Self { + _pb: PhantomData, + } + } +} diff --git a/tests/crashes/114317.rs b/tests/crashes/114317.rs new file mode 100644 index 00000000000..09fd2beeba8 --- /dev/null +++ b/tests/crashes/114317.rs @@ -0,0 +1,6 @@ +//@ known-bug: #114317 +#![feature(generic_const_exprs)] + +struct A<const B: str = 1, C>; + +fn main() {} diff --git a/tests/crashes/114456-2.rs b/tests/crashes/114456-2.rs new file mode 100644 index 00000000000..eca27febb96 --- /dev/null +++ b/tests/crashes/114456-2.rs @@ -0,0 +1,20 @@ +//@ known-bug: #114456 +#![feature(adt_const_params)] + +const EMPTY_MATRIX: <Type as Trait>::Matrix = [0; 1]; + +pub struct Walk<const REMAINING: <Type as Trait>::Matrix> {} + +impl Walk<EMPTY_MATRIX> { + pub const fn new() -> Self { + Self {} + } +} + +pub enum Type {} +pub trait Trait { type Matrix; } +impl Trait for Type { type Matrix = [usize; 1]; } + +fn main() { + let _ = Walk::new(); +} diff --git a/tests/crashes/114456.rs b/tests/crashes/114456.rs new file mode 100644 index 00000000000..e347327e738 --- /dev/null +++ b/tests/crashes/114456.rs @@ -0,0 +1,17 @@ +//@ known-bug: #114456 +#![feature(adt_const_params, lazy_type_alias)] + +pub type Matrix = [usize; 1]; +const EMPTY_MATRIX: Matrix = [0; 1]; + +pub struct Walk<const REMAINING: Matrix> {} + +impl Walk<EMPTY_MATRIX> { + pub const fn new() -> Self { + Self {} + } +} + +fn main() { + let _ = Walk::new(); +} diff --git a/tests/crashes/114484.rs b/tests/crashes/114484.rs new file mode 100644 index 00000000000..9d90c153624 --- /dev/null +++ b/tests/crashes/114484.rs @@ -0,0 +1,67 @@ +//@ known-bug: #114484 +use std::marker::PhantomData; + +trait MyTrait { + fn virtualize(&self) -> &dyn MyTrait; +} + +struct VirtualWrapper<T, const L: u8>(T); + +impl<T, const L: u8> VirtualWrapper<T, L> { + pub fn wrap(value: &T) -> &Self { + unsafe { &*(value as *const T as *const Self) } + } +} + +impl<T: MyTrait + 'static, const L: u8> MyTrait for VirtualWrapper<T, L> { + fn virtualize(&self) -> &dyn MyTrait { + unsafe { virtualize_my_trait(L, self) } + // unsafe { virtualize_my_trait(L, &self.0) } // <-- this code fixes the problem + } +} + +const unsafe fn virtualize_my_trait<T>(level: u8, obj: &T) -> &dyn MyTrait +where + T: MyTrait + 'static, +{ + const fn gen_vtable_ptr<T, const L: u8>() -> *const () + where + T: MyTrait + 'static, + { + let [_, vtable] = unsafe { + std::mem::transmute::<*const dyn MyTrait, [*const (); 2]>(std::ptr::null::< + VirtualWrapper<T, L>, + >()) + }; + vtable + } + + struct Vtable<T>(PhantomData<T>); + + impl<T> Vtable<T> + where + T: MyTrait + 'static, + { + const LEVELS: [*const (); 2] = [gen_vtable_ptr::<T, 1>(), gen_vtable_ptr::<T, 2>()]; + } + + let vtable = Vtable::<T>::LEVELS[(level != 0) as usize]; + + let data = obj as *const T as *const (); + let ptr: *const dyn MyTrait = std::mem::transmute([data, vtable]); + + &*ptr +} + +struct SomeData<const N: usize>([u8; N]); + +impl<const N: usize> MyTrait for SomeData<N> { + fn virtualize(&self) -> &dyn MyTrait { + VirtualWrapper::<Self, 0>::wrap(self) + } +} + +fn main() { + let test = SomeData([0; 256]); + test.virtualize(); +} diff --git a/tests/crashes/114663.rs b/tests/crashes/114663.rs new file mode 100644 index 00000000000..406371f12e4 --- /dev/null +++ b/tests/crashes/114663.rs @@ -0,0 +1,17 @@ +//@ known-bug: #114663 +//@ edition:2021 + +#![feature(generic_const_exprs)] + +use core::fmt::Debug; + +struct Inline<T> +where + [u8; ::core::mem::size_of::<T>() + 1]:, +{ + _phantom: PhantomData<T>, +} + +fn main() { + let dst = Inline::<dyn Debug>::new(0); // BANG! +} diff --git a/tests/crashes/115435.rs b/tests/crashes/115435.rs new file mode 100644 index 00000000000..c6e749867e8 --- /dev/null +++ b/tests/crashes/115435.rs @@ -0,0 +1,25 @@ +//@ known-bug: #115435 +//@ edition:2021 +//@ compile-flags: -Copt-level=0 +trait MyTrait { + type Target: ?Sized; +} + +impl<A: ?Sized> MyTrait for A { + type Target = A; +} + +fn main() { + bug_run::<dyn MyTrait<Target = u8>>(); +} + +fn bug_run<T: ?Sized>() +where + <T as MyTrait>::Target: Sized, +{ + bug::<T>(); +} + +fn bug<T>() { + std::mem::size_of::<T>(); +} diff --git a/tests/crashes/115808.rs b/tests/crashes/115808.rs new file mode 100644 index 00000000000..79196ac9c65 --- /dev/null +++ b/tests/crashes/115808.rs @@ -0,0 +1,27 @@ +//@ known-bug: #115808 +#![feature(generic_const_exprs)] + +use std::ops::Mul; + +pub trait Indices<const N: usize> { + const NUM_ELEMS: usize; +} + +pub trait Concat<J> { + type Output; +} + +pub struct Tensor<I: Indices<N>, const N: usize> +where + [u8; I::NUM_ELEMS]: Sized, {} + +impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N> +where + I: Concat<FN>, + <I as Concat<J>>::Output: Indices<N>, + [u8; I::NUM_ELEMS]: Sized, + [u8; J::NUM_ELEMS]: Sized, + [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized, +{ + type Output = Tensor<<I as Concat<J>>::Output, N>; +} diff --git a/tests/crashes/116308.rs b/tests/crashes/116308.rs new file mode 100644 index 00000000000..cb96c80d79b --- /dev/null +++ b/tests/crashes/116308.rs @@ -0,0 +1,16 @@ +//@ known-bug: #116308 +#![feature(adt_const_params)] + +pub trait Identity { + type Identity; +} + +impl<T> Identity for T { + type Identity = Self; +} + +pub fn foo<const X: <i32 as Identity>::Identity>() {} + +fn main() { + foo::<12>(); +} diff --git a/tests/crashes/116519-2.rs b/tests/crashes/116519-2.rs new file mode 100644 index 00000000000..e1abbbcd4c1 --- /dev/null +++ b/tests/crashes/116519-2.rs @@ -0,0 +1,15 @@ +//@ known-bug: #116519 +#![feature(generic_const_exprs)] + +trait Ret { + type R; +} + +struct Cond<const PRED: bool, U, V>(std::marker::PhantomData<U>, ); + +struct RobinHashTable< + const MAX_LENGTH: usize, + CellIdx = <Cond<{ }, u16, u32> as Ret>::R, +> {} + +impl<CellIdx> HashMapBase<CellIdx> for RobinHashTable<MAX_LENGTH, CellIdx> {} diff --git a/tests/crashes/116519.rs b/tests/crashes/116519.rs new file mode 100644 index 00000000000..0824a72be19 --- /dev/null +++ b/tests/crashes/116519.rs @@ -0,0 +1,57 @@ +//@ known-bug: #116519 +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] +trait Ret { + type R; +} +struct Cond<const PRED: bool, U, V>(std::marker::PhantomData<U>, std::marker::PhantomData<V>); +impl<U, V> Ret for Cond<true, U, V> { + type R = U; +} +impl<U, V> Ret for Cond<false, U, V> { + type R = V; +} +struct RobinHashTable< + const MAX_LENGTH: usize, + CellIdx = <Cond<{ MAX_LENGTH < 65535 }, u16, u32> as Ret>::R, +> { + _idx: CellIdx, +} +impl<CellIdx> RobinHashTable<MAX_LENGTH, CellIdx> { + fn new() -> Self { + Self { + _idx: CellIdx { MAX_LENGTH }, + } + } +} +impl<CellIdx> HashMapBase<CellIdx> { + fn new() -> Self { + Self { + _idx: CellIdx { 0 }, + } + } +} +impl<CellIdx> HashMapBase<CellIdx> for RobinHashTable<MAX_LENGTH, CellIdx> { + fn hash<H: Hash + Hasher>(&self, + + ) -> H { + self._idx.hash() + } + fn eq(&self, other: &Self) -> bool { + self._idx.eq(other._idx) + } +} +impl<CellIdx> HashMapBase<CellIdx> for RobinHashTable<MAX_LENGTH, CellIdx> { + fn hash<H: Hash + Hasher>(&self, other: &Self) -> H { + self._idx.hash(other._idx) + } + fn eq(&self, other: &Self) -> bool { + self._idx.eq(other._idx) + } +} +#[test] +fn test_size_of_robin_hash_table() { + use std::mem::size_of; + println!("{}", size_of::<RobinHashTable<1024>>()); + println!("{}", size_of::<RobinHashTable<65536>>()); +} diff --git a/tests/crashes/116554.rs b/tests/crashes/116554.rs new file mode 100644 index 00000000000..b87a478e6f2 --- /dev/null +++ b/tests/crashes/116554.rs @@ -0,0 +1,31 @@ +//@ known-bug: #116554 +#![feature(generic_const_exprs)] + +const fn t<const N: usize>() -> u8 { + + N as u8 + +} + +#[repr(u8)] + +enum T<const N: u8 = { T::<0>::A as u8 + T::<0>::B as u8 }> + +where + + [(); N as usize]:, + + T: ?Sized, + +{ + + A, + +} + +fn main() { + A = t::<N>() as u8, + + B, + +} diff --git a/tests/crashes/116947.rs b/tests/crashes/116947.rs new file mode 100644 index 00000000000..34f0522369e --- /dev/null +++ b/tests/crashes/116947.rs @@ -0,0 +1,16 @@ +//@ known-bug: #116947 +#![feature(min_specialization)] + +trait MySpecTrait { + fn f(); +} + +impl<'a, T: ?Sized> MySpecTrait for T { + default fn f() {} +} + +impl<'a, T: ?Sized> MySpecTrait for &'a T { + fn f() {} +} + +fn main() {} diff --git a/tests/crashes/117392-2.rs b/tests/crashes/117392-2.rs new file mode 100644 index 00000000000..632ce8b9dee --- /dev/null +++ b/tests/crashes/117392-2.rs @@ -0,0 +1,27 @@ +//@ known-bug: #117392 +pub trait BorrowComposite { + type Ref<'a>: 'a; +} + +impl BorrowComposite for () { + type Ref<'a> = (); +} + +pub trait Component<Args> { + type Output; +} + +impl<Args> Component<Args> for () { + type Output = (); +} + +pub fn delay<Args: BorrowComposite, Make: for<'a> FnMut(Args::Ref<'a>) -> C, C: Component<Args>>( + make: Make, +) -> impl Component<Args> { +} + +pub fn crash() -> impl Component<()> { + delay(|()| delay(|()| ())) +} + +pub fn main() {} diff --git a/tests/crashes/117392.rs b/tests/crashes/117392.rs new file mode 100644 index 00000000000..95fdf63f893 --- /dev/null +++ b/tests/crashes/117392.rs @@ -0,0 +1,47 @@ +//@ known-bug: #117392 +pub trait BorrowComposite { + type Ref<'a> + where + Self: 'a; +} + +impl BorrowComposite for () { + type Ref<'a> = (); +} + +pub trait Component<Args: BorrowComposite> { + type Output; +} + +impl<Args: BorrowComposite> Component<Args> for () { + type Output = (); +} + +struct Delay<Make> { + _make: Make, +} + +impl< + Args: BorrowComposite, + Make: for<'a> FnMut(Args::Ref<'a>) -> C, + C: Component<Args>, + > Component<Args> for Delay<Make> +{ + type Output = C::Output; +} + +pub fn delay< + Args: BorrowComposite, + Make: for<'a> FnMut(Args::Ref<'a>) -> C, + C: Component<Args>, +>( + make: Make, +) -> impl Component<Args, Output = C::Output> { + Delay { _make: make } +} + +pub fn crash() -> impl Component<(), Output = ()> { + delay(|()| delay(|()| ())) +} + +pub fn main() {} diff --git a/tests/crashes/117496.rs b/tests/crashes/117496.rs new file mode 100644 index 00000000000..1e85646cf83 --- /dev/null +++ b/tests/crashes/117496.rs @@ -0,0 +1,22 @@ +//@ known-bug: #117496 +#![feature(adt_const_params)] +#![feature(generic_const_exprs)] + +use core::marker::ConstParamTy; + +#[derive(PartialEq, Copy, Clone, Eq, ConstParamTy)] +pub enum Foo {} +impl Foo { + pub const fn size(self) -> usize { + 1 + } +} + +pub struct Bar<const F: Foo, const SIZE: usize = { F.size() }>([u64; SIZE]) +where + [u64; SIZE]: Sized; + +pub struct Quux<const F: Foo> {} +impl<const F: Foo> Quux<{ F }> { + pub unsafe fn nothing(&self, bar: &mut Bar<{ F }>) {} +} diff --git a/tests/crashes/117629.rs b/tests/crashes/117629.rs new file mode 100644 index 00000000000..d8b5f328545 --- /dev/null +++ b/tests/crashes/117629.rs @@ -0,0 +1,11 @@ +//@ known-bug: #117629 +//@ edition:2021 + +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + async fn ft1() {} +} + +fn main() {} diff --git a/tests/crashes/117696-1.rs b/tests/crashes/117696-1.rs new file mode 100644 index 00000000000..dfca3917785 --- /dev/null +++ b/tests/crashes/117696-1.rs @@ -0,0 +1,29 @@ +//@ known-bug: #117696 +fn main() { + let mut it = (Empty); + rec(&mut it); +} + +struct Empty; + +impl Iterator for Empty { + type Item = (); + fn next<'a>(&'a mut self) -> core::option::Option<()> { + None + } +} + +fn identity<T>(x: T) -> T { + x +} + +fn rec<T>(mut it: T) +where + T: Iterator, +{ + if () == () { + T::count(it); + } else { + rec(identity(&mut it)) + } +} diff --git a/tests/crashes/117696-2.rs b/tests/crashes/117696-2.rs new file mode 100644 index 00000000000..9c2a68d3a91 --- /dev/null +++ b/tests/crashes/117696-2.rs @@ -0,0 +1,13 @@ +//@ known-bug: #117696 +//@ compile-flags: -Copt-level=0 +fn main() { + rec(&mut None::<()>.into_iter()); +} + +fn rec<T: Iterator>(mut it: T) { + if true { + it.next(); + } else { + rec(&mut it); + } +} diff --git a/tests/crashes/117795.rs b/tests/crashes/117795.rs new file mode 100644 index 00000000000..3f0dd2f9bf4 --- /dev/null +++ b/tests/crashes/117795.rs @@ -0,0 +1,8 @@ +//@ known-bug: #117795 +const fn f() -> usize { + 5 +} + +fn main() { + let _ = [0; FnMut::call_mut(&mut f, ())]; +} diff --git a/tests/crashes/117829-2.rs b/tests/crashes/117829-2.rs new file mode 100644 index 00000000000..ecfd3148569 --- /dev/null +++ b/tests/crashes/117829-2.rs @@ -0,0 +1,14 @@ +//@ known-bug: #117829 +#![feature(auto_traits)] + +trait B {} + +auto trait Z<T> +where + T: Z<u16>, + <T as Z<u16>>::W: B, +{ + type W; +} + +fn main() {} diff --git a/tests/crashes/117829.rs b/tests/crashes/117829.rs new file mode 100644 index 00000000000..7544b5ec0fc --- /dev/null +++ b/tests/crashes/117829.rs @@ -0,0 +1,9 @@ +//@ known-bug: #117829 +auto trait Z<'a, T: ?Sized> +where + T: Z<'a, u16>, + + for<'b> <T as Z<'b, u16>>::W: Clone, +{ + type W: ?Sized; +} diff --git a/tests/crashes/117942.rs b/tests/crashes/117942.rs new file mode 100644 index 00000000000..6fdfc689250 --- /dev/null +++ b/tests/crashes/117942.rs @@ -0,0 +1,7 @@ +//@ known-bug: #117942 +struct Foo { + _: union { + #[rustfmt::skip] + f: String + }, +} diff --git a/tests/crashes/118038.rs b/tests/crashes/118038.rs new file mode 100644 index 00000000000..a346e84c78f --- /dev/null +++ b/tests/crashes/118038.rs @@ -0,0 +1,12 @@ +//@ known-bug: #118038 +#![feature(non_lifetime_binders)] + +fn trivial<A>() +where + for<B> dyn Fn(A, *const A): Fn(A, *const B), +{ +} + +fn main() { + trivial::<u8>(); +} diff --git a/tests/crashes/118320.rs b/tests/crashes/118320.rs new file mode 100644 index 00000000000..093c58e1c05 --- /dev/null +++ b/tests/crashes/118320.rs @@ -0,0 +1,14 @@ +//@ known-bug: #118320 +//@ edition:2021 +#![feature(const_trait_impl, effects, const_closures)] + +#[const_trait] +trait Bar { + fn foo(&self); +} + +impl Bar for () {} + +const FOO: () = { + (const || (()).foo())(); +}; diff --git a/tests/crashes/118403.rs b/tests/crashes/118403.rs new file mode 100644 index 00000000000..21ab15f9ffd --- /dev/null +++ b/tests/crashes/118403.rs @@ -0,0 +1,8 @@ +//@ known-bug: #118403 +#![feature(generic_const_exprs)] +pub struct X<const N: usize> {} +impl<const Z: usize> X<Z> { + pub fn y<'a, U: 'a>(&'a self) -> impl Iterator<Item = impl Iterator<Item = [u8; Z]> + '_> { + (0..1).map(move |_| (0..1).map(move |_| loop {})) + } +} diff --git a/tests/crashes/118603.rs b/tests/crashes/118603.rs new file mode 100644 index 00000000000..cde2cf35305 --- /dev/null +++ b/tests/crashes/118603.rs @@ -0,0 +1,44 @@ +//@ known-bug: #118603 +//@ compile-flags: -Copt-level=0 +// ignore-tidy-linelength + +#![feature(generic_const_exprs)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +struct FlatTree; + +#[derive(Copy, Clone)] +struct TreeLeaf; + +#[derive(Copy, Clone)] +struct TreeNode<V, W>(V, W); + +const fn const_concat<const A: usize, const B: usize>(_: [FlatTree; A], _: [FlatTree; B]) -> [FlatTree; A + B] { + [FlatTree; A + B] +} + +struct Builder<const N: usize, I> { + ops: [FlatTree; N], + builder: I, +} + +fn create_node<const N: usize, const M: usize, A, B>(a: Builder<N, A>, b: Builder<M, B>) -> Builder<{ N + M + 1 }, TreeNode<A, B>> { + Builder { + ops: const_concat(const_concat::<N, M>(a.ops, b.ops), [FlatTree]), + builder: TreeNode(a.builder, b.builder), + } +} + +const LEAF: Builder<1, TreeLeaf> = Builder { + ops: [FlatTree], + builder: TreeLeaf, +}; + +static INTERNAL_SIMPLE_BOOLEAN_TEMPLATES: &[fn()] = &[{ + fn eval() { + create_node(LEAF, create_node(LEAF, LEAF)); + } + + eval +}]; + +pub fn main() {} diff --git a/tests/crashes/118952-2.rs b/tests/crashes/118952-2.rs new file mode 100644 index 00000000000..469b1e8e905 --- /dev/null +++ b/tests/crashes/118952-2.rs @@ -0,0 +1,10 @@ +//@ known-bug: #118952 +#![feature(generic_const_exprs)] + +pub struct TinyVec<T, const N: usize = { () }> +where + [(); () - std::mem::size_of() - std::mem::size_of::<isize>()]:, {} + +pub fn main() { + let t = TinyVec::<u8>::new(); +} diff --git a/tests/crashes/118952.rs b/tests/crashes/118952.rs new file mode 100644 index 00000000000..cd873703284 --- /dev/null +++ b/tests/crashes/118952.rs @@ -0,0 +1,25 @@ +//@ known-bug: #118952 +#![allow(non_camel_case_types)] +#![feature(generic_const_exprs)] +#![feature(specialization)] + +const DEFAULT_SMALL_VEC_INLINE_CAPACITY: usize = std::mem::size_of::<usize>() * 8; + +pub const fn tiny_vec_cap<T>() -> usize { + return (DEFAULT_SMALL_VEC_INLINE_CAPACITY - 1) / std::mem::size_of::<T>() +} + +pub struct TinyVec<T, const N: usize = {tiny_vec_cap::<T>()}> + where [ + (); + (N * std::mem::size_of::<T>()) + - std::mem::size_of::<std::ptr::NonNull<T>>() + - std::mem::size_of::<isize>() + ]: , +{ + data: isize //TinyVecData<T, N>, +} + +pub fn main() { + let t = TinyVec::<u8>::new(); +} diff --git a/tests/crashes/118987-2.rs b/tests/crashes/118987-2.rs new file mode 100644 index 00000000000..4382a7bcb63 --- /dev/null +++ b/tests/crashes/118987-2.rs @@ -0,0 +1,17 @@ +//@ known-bug: #118987 +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +trait Assoc { + type Output; +} + +default impl<T: Clone> Assoc for T { + type Output = bool; +} + +impl Assoc for u8 {} + +trait Foo {} + +impl Foo for <u8 as Assoc>::Output {} +impl Foo for <u16 as Assoc>::Output {} diff --git a/tests/crashes/118987.rs b/tests/crashes/118987.rs new file mode 100644 index 00000000000..4382a7bcb63 --- /dev/null +++ b/tests/crashes/118987.rs @@ -0,0 +1,17 @@ +//@ known-bug: #118987 +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +trait Assoc { + type Output; +} + +default impl<T: Clone> Assoc for T { + type Output = bool; +} + +impl Assoc for u8 {} + +trait Foo {} + +impl Foo for <u8 as Assoc>::Output {} +impl Foo for <u16 as Assoc>::Output {} diff --git a/tests/crashes/119272.rs b/tests/crashes/119272.rs new file mode 100644 index 00000000000..02e2cfd09e2 --- /dev/null +++ b/tests/crashes/119272.rs @@ -0,0 +1,27 @@ +//@ known-bug: #119272 +#![feature(type_alias_impl_trait)] +mod defining_scope { + use super::*; + pub type Alias<T> = impl Sized; + + pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> { + x + } +} + +struct Container<T: Trait<U>, U> { + x: <T as Trait<U>>::Assoc, +} + +trait Trait<T> { + type Assoc; +} + +impl<T> Trait<T> for T { + type Assoc = Box<u32>; +} +impl<T> Trait<T> for defining_scope::Alias<T> { + type Assoc = usize; +} + +fn main() {} diff --git a/tests/crashes/119299.rs b/tests/crashes/119299.rs new file mode 100644 index 00000000000..c8c10546d94 --- /dev/null +++ b/tests/crashes/119299.rs @@ -0,0 +1,25 @@ +//@ known-bug: #119299 +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq)] +struct ConstStrU(*const u8, usize); + +impl ConstParamTy for &'static ConstStrU {} + +impl ConstStrU { + const fn from_bytes(bytes: &'static [u8]) -> Self { + Self(bytes.as_ptr(), bytes.len()) + } +} + +const fn chars_s<const S: &'static ConstStrU>() -> [char; 3] { + ['a','b','c'] +} + +fn main() { + const A: &'static ConstStrU = &ConstStrU::from_bytes(b"abc"); + chars_s::<A>(); +} diff --git a/tests/crashes/119692.rs b/tests/crashes/119692.rs new file mode 100644 index 00000000000..2e230f98d81 --- /dev/null +++ b/tests/crashes/119692.rs @@ -0,0 +1,48 @@ +//@ known-bug: #119692 +//@ compile-flags: -Copt-level=0 +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![feature(generic_const_exprs)] + +use std::ops::Add; + +#[derive(PartialEq, Eq, Clone, Debug, core::marker::ConstParamTy)] +pub struct Dimension; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Default)] +pub struct Quantity<S, const D: Dimension>(pub(crate) S); + +impl<const D: Dimension, LHS, RHS> Add<Quantity<RHS, D>> for Quantity<LHS, D> +where + LHS: Add<RHS>, +{ + type Output = Quantity<<LHS as Add<RHS>>::Output, D>; + fn add(self, rhs: Quantity<RHS, D>) -> Self::Output { + Quantity(self.0 + rhs.0) + } +} + +impl<LHS, RHS> Add<RHS> for Quantity<LHS, { Dimension }> +where + LHS: Add<RHS>, +{ + type Output = Quantity<<LHS as Add<RHS>>::Output, { Dimension }>; + fn add(self, rhs: RHS) -> Self::Output { + Quantity(self.0 + rhs) + } +} + +impl Add<Quantity<f32, { Dimension }>> for f32 { + type Output = Quantity<f32, { Dimension }>; + fn add(self, rhs: Quantity<f32, { Dimension }>) -> Self::Output { + Quantity(self + rhs.0) + } +} + +pub fn add<const U: Dimension>(x: Quantity<f32, U>, y: Quantity<f32, U>) -> Quantity<f32, U> { + x + y +} + +fn main() { + add(Quantity::<f32, {Dimension}>(1.0), Quantity(2.0)); +} diff --git a/tests/crashes/119694.rs b/tests/crashes/119694.rs new file mode 100644 index 00000000000..f655ea1cd34 --- /dev/null +++ b/tests/crashes/119694.rs @@ -0,0 +1,18 @@ +//@ known-bug: #119694 +#![feature(dyn_star)] + +trait Trait { + fn foo(self); +} + +impl Trait for usize { + fn foo(self) {} +} + +fn bar(x: dyn* Trait) { + x.foo(); +} + +fn main() { + bar(0usize); +} diff --git a/tests/crashes/119701.rs b/tests/crashes/119701.rs new file mode 100644 index 00000000000..5f681bb8da8 --- /dev/null +++ b/tests/crashes/119701.rs @@ -0,0 +1,21 @@ +//@ known-bug: #119701 +#![feature(const_trait_impl, effects, generic_const_exprs)] + +fn main() { + let _ = process::<()>([()]); +} + +fn process<T: const Trait>() -> [(); T::make(2)] { + input +} + +#[const_trait] +trait Trait { + fn make(input: u8) -> usize; +} + +impl const Trait for () { + fn make(input: usize) -> usize { + input / 2 + } +} diff --git a/tests/crashes/119716-2.rs b/tests/crashes/119716-2.rs new file mode 100644 index 00000000000..9cdc4417f5b --- /dev/null +++ b/tests/crashes/119716-2.rs @@ -0,0 +1,4 @@ +//@ known-bug: #119716 +#![feature(non_lifetime_binders)] +trait Trait<T> {} +fn f<T>() -> impl for<T> Trait<impl Trait<T>> {} diff --git a/tests/crashes/119716.rs b/tests/crashes/119716.rs new file mode 100644 index 00000000000..d7cba0f51c4 --- /dev/null +++ b/tests/crashes/119716.rs @@ -0,0 +1,4 @@ +//@ known-bug: #119716 +#![feature(non_lifetime_binders)] +trait v0<v1> {} +fn kind :(v3main impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {} diff --git a/tests/crashes/119717.rs b/tests/crashes/119717.rs new file mode 100644 index 00000000000..22746548e02 --- /dev/null +++ b/tests/crashes/119717.rs @@ -0,0 +1,10 @@ +//@ known-bug: #119717 +#![feature(const_trait_impl, effects)] + +use std::ops::{FromResidual, Try}; + +impl const FromResidual for T { + fn from_residual(t: T) -> _ { + t + } +} diff --git a/tests/crashes/119729.rs b/tests/crashes/119729.rs new file mode 100644 index 00000000000..ed07c58e89f --- /dev/null +++ b/tests/crashes/119729.rs @@ -0,0 +1,12 @@ +//@ known-bug: #119729 +#![feature(generic_const_exprs)] + +trait Size<const N: usize> {} + +impl<T: Sized> Size<{ std::mem::size_of::<T>() }> for T {} + +struct A<T: Size<8> + ?Sized> { + x: std::marker::PhantomData<T>, +} + +fn foo(x: A<dyn Send>) {} diff --git a/tests/crashes/119783.rs b/tests/crashes/119783.rs new file mode 100644 index 00000000000..9a41abe6920 --- /dev/null +++ b/tests/crashes/119783.rs @@ -0,0 +1,8 @@ +//@ known-bug: #119783 +#![feature(associated_const_equality)] + +trait Trait { const F: fn(); } + +fn take(_: impl Trait<F = { || {} }>) {} + +fn main() {} diff --git a/tests/crashes/119786.rs b/tests/crashes/119786.rs new file mode 100644 index 00000000000..ca79664d8b7 --- /dev/null +++ b/tests/crashes/119786.rs @@ -0,0 +1,15 @@ +//@ known-bug: #119786 +//@ edition:2021 + +fn enum_upvar() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + let x = move || { + match foo { + None => (), + Some(yield) => (), + } + }; +} + +pub fn main() {} diff --git a/tests/crashes/119824.rs b/tests/crashes/119824.rs new file mode 100644 index 00000000000..d51cd5f49a3 --- /dev/null +++ b/tests/crashes/119824.rs @@ -0,0 +1,14 @@ +//@ known-bug: #119824 +#![feature(generic_const_exprs)] + +const fn t<const N: usize>() -> u8 { + N as u8 +} + +#[repr(u8)] +enum T<const N: u8 = { T::<0>::A as u8 + T::<0>::B as u8 }> +where + [(); N as usize]: +{ + A = t::<N>() as u8, B +} diff --git a/tests/crashes/119830.rs b/tests/crashes/119830.rs new file mode 100644 index 00000000000..71becc04e16 --- /dev/null +++ b/tests/crashes/119830.rs @@ -0,0 +1,11 @@ +//@ known-bug: #119830 +#![feature(effects)] +#![feature(min_specialization)] + +trait Specialize {} + +trait Foo {} + +impl<T> const Foo for T {} + +impl<T> const Foo for T where T: const Specialize {} diff --git a/tests/crashes/119924-6.rs b/tests/crashes/119924-6.rs new file mode 100644 index 00000000000..01c4f43e8fd --- /dev/null +++ b/tests/crashes/119924-6.rs @@ -0,0 +1,14 @@ +//@ known-bug: #119924 +#![feature(const_trait_impl, effects)] + +struct S; +#[const_trait] +trait Trait<const N: u32> {} + +const fn f<T: Trait<{ + struct I<U: ~const Trait<0>>(U); // should've gotten rejected during AST validation + //~^ ICE no host param id for call in const yet no errors reported + 0 +}>>() {} + +pub fn main() {} diff --git a/tests/crashes/120241-2.rs b/tests/crashes/120241-2.rs new file mode 100644 index 00000000000..9c4a3a50293 --- /dev/null +++ b/tests/crashes/120241-2.rs @@ -0,0 +1,10 @@ +//@ known-bug: #120241 +//@ edition:2021 +#![feature(object_safe_for_dispatch)] +#![feature(unsized_fn_params)] + +fn guard(_s: Copy) -> bool { + panic!() +} + +fn main() {} diff --git a/tests/crashes/120241.rs b/tests/crashes/120241.rs new file mode 100644 index 00000000000..f18347a006c --- /dev/null +++ b/tests/crashes/120241.rs @@ -0,0 +1,13 @@ +//@ known-bug: #120241 +//@ edition:2021 +#![feature(object_safe_for_dispatch)] + +trait B { + fn f(a: A) -> A; +} + +trait A { + fn g(b: B) -> B; +} + +fn main() {} diff --git a/tests/crashes/120482.rs b/tests/crashes/120482.rs new file mode 100644 index 00000000000..6cbc2009c5f --- /dev/null +++ b/tests/crashes/120482.rs @@ -0,0 +1,13 @@ +//@ known-bug: #120482 +//@ edition:2021 +#![feature(object_safe_for_dispatch)] + +trait B { + fn bar(&self, x: &Self); +} + +trait A { + fn g(new: B) -> B; +} + +fn main() {} diff --git a/tests/crashes/120503.rs b/tests/crashes/120503.rs new file mode 100644 index 00000000000..28f1e3dfd94 --- /dev/null +++ b/tests/crashes/120503.rs @@ -0,0 +1,10 @@ +//@ known-bug: #120503 +#![feature(effects)] + +trait MyTrait {} + +impl MyTrait for i32 { + async const fn bar(&self) { + main8().await; + } +} diff --git a/tests/crashes/120600-2.rs b/tests/crashes/120600-2.rs new file mode 100644 index 00000000000..aa1785eea84 --- /dev/null +++ b/tests/crashes/120600-2.rs @@ -0,0 +1,13 @@ +//@ known-bug: #120600 +#![feature(never_type, never_type_fallback)] + +enum E { Bar(!) } + +fn f(a: &E, b: &E) { + match (a, b) { + (E::Bar(a), E::Bar(b)) => { *a == *b; } + _ => {} + } +} + +pub fn main() {} diff --git a/tests/crashes/120600.rs b/tests/crashes/120600.rs new file mode 100644 index 00000000000..1be51a8da16 --- /dev/null +++ b/tests/crashes/120600.rs @@ -0,0 +1,11 @@ +//@ known-bug: #120600 +#![feature(never_type)] +#![feature(never_type_fallback)] + +#[derive(Ord, Eq, PartialOrd, PartialEq)] +enum E { + Foo, + Bar(!, i32, i32), +} + +fn main() {} diff --git a/tests/crashes/120793-2.rs b/tests/crashes/120793-2.rs new file mode 100644 index 00000000000..0ce5e4df224 --- /dev/null +++ b/tests/crashes/120793-2.rs @@ -0,0 +1,22 @@ +//@ known-bug: #120793 +// can't use build-fail, because this also fails check-fail, but +// the ICE from #120787 only reproduces on build-fail. +//@ compile-flags: --emit=mir + +#![feature(effects)] + +trait Dim { + fn dim() -> usize; +} + +enum Dim3 {} + +impl Dim for Dim3 { + fn dim(x: impl Sized) -> usize { + 3 + } +} + +fn main() { + [0; Dim3::dim()]; +} diff --git a/tests/crashes/120793.rs b/tests/crashes/120793.rs new file mode 100644 index 00000000000..7e9166a50e5 --- /dev/null +++ b/tests/crashes/120793.rs @@ -0,0 +1,21 @@ +//@ known-bug: #120793 +#![feature(effects)] + +trait Dim { + fn dim() -> usize; +} + +enum Dim3 {} + +impl Dim for Dim3 { + fn dim(mut x: impl Iterator<Item = &'_ ()>) -> usize { + 3 + } +} + +fn main() { + let array: [usize; Dim3::dim()] + //~^ ERROR E0015 + = [0; Dim3::dim()]; + //~^ ERROR E0015 +} diff --git a/tests/crashes/120873.rs b/tests/crashes/120873.rs new file mode 100644 index 00000000000..45bc0bd457b --- /dev/null +++ b/tests/crashes/120873.rs @@ -0,0 +1,8 @@ +//@ known-bug: #120873 +#[repr(packed)] + +struct Dealigned<T>(u8, T); + +#[derive(PartialEq)] +#[repr(C)] +struct Dealigned<T>(u8, T); diff --git a/tests/crashes/120911.rs b/tests/crashes/120911.rs new file mode 100644 index 00000000000..9bd2bf68142 --- /dev/null +++ b/tests/crashes/120911.rs @@ -0,0 +1,26 @@ +//@ known-bug: #120911 +trait Container { + type Item<'a>; +} +impl Container for () { + type Item<'a> = (); +} +struct Exchange<C, F> { + _marker: std::marker::PhantomData<(C, F)>, +} +fn exchange<C, F>(_: F) -> Exchange<C, F> +where + C: Container, + for<'a> F: FnMut(&C::Item<'a>), +{ + unimplemented!() +} +trait Parallelization<C> {} +impl<C, F> Parallelization<C> for Exchange<C, F> {} +fn unary_frontier<P: Parallelization<()>>(_: P) {} +fn main() { + let exchange = exchange(|_| ()); + let _ = || { + unary_frontier(exchange); + }; +} diff --git a/tests/crashes/121052.rs b/tests/crashes/121052.rs new file mode 100644 index 00000000000..5d16b06db23 --- /dev/null +++ b/tests/crashes/121052.rs @@ -0,0 +1,32 @@ +//@ known-bug: #121052 +#![feature(generic_const_exprs, with_negative_coherence)] + +use std::ops::Mul; + +pub trait Indices<const N: usize> { + const NUM_ELEMS: usize; +} + +impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul for Tensor<I, N> +where + I: Concat<J>, + <I as Concat<J>>::Output: Indices<N>, + [u8; I::NUM_ELEMS]: Sized, + [u8; J::NUM_ELEMS]: Sized, + [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized, +{ +} + +pub trait Concat<J> {} + +pub struct Tensor<I: Indices<N>, const N: usize> {} + +impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul for Tensor<I, N> +where + I: Concat<J>, + <I as Concat<J>>::Output: Indices<N>, + [u8; I::NUM_ELEMS]: Sized, + [u8; J::NUM_ELEMS]: Sized, + [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized, +{ +} diff --git a/tests/crashes/121097.rs b/tests/crashes/121097.rs new file mode 100644 index 00000000000..65c6028e03e --- /dev/null +++ b/tests/crashes/121097.rs @@ -0,0 +1,10 @@ +//@ known-bug: #121097 +#[repr(simd)] +enum Aligned { + Zero = 0, + One = 1, +} + +fn tou8(al: Aligned) -> u8 { + al as u8 +} diff --git a/tests/crashes/121126.rs b/tests/crashes/121126.rs new file mode 100644 index 00000000000..2ebe91f02de --- /dev/null +++ b/tests/crashes/121126.rs @@ -0,0 +1,4 @@ +//@ known-bug: #121126 +fn main() { + let _n = 1i64 >> [64][4_294_967_295]; +} diff --git a/tests/crashes/121134.rs b/tests/crashes/121134.rs new file mode 100644 index 00000000000..36397d4ec3c --- /dev/null +++ b/tests/crashes/121134.rs @@ -0,0 +1,20 @@ +//@ known-bug: #121134 +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper<O, F>(&mut self, do_something_wrapper: F) + where + FnOnce:, + F: for<'a> FnOnce(<F as Output<i32, _>>::Type), + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper::<i32, _>(|value| ()); +} diff --git a/tests/crashes/121161.rs b/tests/crashes/121161.rs new file mode 100644 index 00000000000..6da6426a86d --- /dev/null +++ b/tests/crashes/121161.rs @@ -0,0 +1,12 @@ +//@ known-bug: #121161 +#![allow(incomplete_features)] +#![feature(unnamed_fields)] + + +#[derive(Eq)] +#[repr(C)] +struct Bar { + _: union { + a: u8, + }, +} diff --git a/tests/crashes/121263-2.rs b/tests/crashes/121263-2.rs new file mode 100644 index 00000000000..2c6327a8808 --- /dev/null +++ b/tests/crashes/121263-2.rs @@ -0,0 +1,6 @@ +//@ known-bug: #121263 +#[repr(C)] +#[derive(Debug)] +struct L { + _: MyI32, +} diff --git a/tests/crashes/121263.rs b/tests/crashes/121263.rs new file mode 100644 index 00000000000..cd7583a7faf --- /dev/null +++ b/tests/crashes/121263.rs @@ -0,0 +1,9 @@ +//@ known-bug: #121263 +#[repr(C)] +#[repr(C)] +#[derive(Debug)] +struct L { + _: i32, + _: MyI32, + _: BadEnum, +} diff --git a/tests/crashes/121299.rs b/tests/crashes/121299.rs new file mode 100644 index 00000000000..be5e0c0df57 --- /dev/null +++ b/tests/crashes/121299.rs @@ -0,0 +1,6 @@ +//@ known-bug: #121299 +#[derive(Eq)] +struct D { + _: union { + }, +} diff --git a/tests/crashes/121411.rs b/tests/crashes/121411.rs new file mode 100644 index 00000000000..ef7b16579dd --- /dev/null +++ b/tests/crashes/121411.rs @@ -0,0 +1,13 @@ +//@ known-bug: #121411 +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Foo { + fn into_iter(&self) {} +} + +impl const Foo for () { + fn into_iter(a: u32, b: u32) {} +} + +const _: () = Foo::into_iter(&()); diff --git a/tests/crashes/121422.rs b/tests/crashes/121422.rs new file mode 100644 index 00000000000..5d7ef6e8ce9 --- /dev/null +++ b/tests/crashes/121422.rs @@ -0,0 +1,8 @@ +//@ known-bug: #121422 +#![feature(non_lifetime_binders)] + +trait Trait<T: ?Sized> {} + +fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { + 16 +} diff --git a/tests/crashes/121429.rs b/tests/crashes/121429.rs new file mode 100644 index 00000000000..09bd343e0ba --- /dev/null +++ b/tests/crashes/121429.rs @@ -0,0 +1,17 @@ +//@ known-bug: #121429 +#![feature(generic_const_exprs)] + +pub trait True {} + +impl<const N: usize = { const { 3 } }> PartialEq<FixedI8<FRAC_RHS>> for FixedI8<FRAC_LHS> where + If<{}>: True +{ +} +#![feature(generic_const_exprs)] + +pub trait True {} + +impl<const N: usize = { const { 3 } }> PartialEq<FixedI8<FRAC_RHS>> for FixedI8<FRAC_LHS> where + If<{}>: True +{ +} diff --git a/tests/crashes/121444.rs b/tests/crashes/121444.rs new file mode 100644 index 00000000000..a6373a58c42 --- /dev/null +++ b/tests/crashes/121444.rs @@ -0,0 +1,13 @@ +//@ known-bug: #121444 +//@ compile-flags: -Copt-level=0 +//@ edition:2021 +//@ only-x86_64 +//@ ignore-windows +#[repr(align(536870912))] +pub struct A(i64); + +pub extern "C" fn foo(x: A) {} + +fn main() { + foo(A(0)); +} diff --git a/tests/crashes/121536.rs b/tests/crashes/121536.rs new file mode 100644 index 00000000000..000e7cb15eb --- /dev/null +++ b/tests/crashes/121536.rs @@ -0,0 +1,20 @@ +//@ known-bug: #121536 +#![feature(effects)] + +#[derive(Debug, Clone, Copy)] +pub struct Vec3 { + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl std::ops::Add<Vec3> for Vec3 { + type Output = Vec3; + const fn add(self, b: Vec3) -> Self::Output { + Vec3 { + x: self.x + b.x, + y: self.y + b.y, + z: self.z + b.z, + } + } +} diff --git a/tests/crashes/121574-2.rs b/tests/crashes/121574-2.rs new file mode 100644 index 00000000000..a08f3f06397 --- /dev/null +++ b/tests/crashes/121574-2.rs @@ -0,0 +1,8 @@ +//@ known-bug: #121574 +#![feature(generic_const_exprs)] +pub struct DimName<const N: usize> {} +impl<const Z: usize> X<Z> { + pub fn y<'a, U: 'a>(&'a self) -> impl Iterator<Item = impl Iterator<Item = [u8; Z]> + '_> { + "0".as_bytes(move |_| (0..1).map(move |_| loop {})) + } +} diff --git a/tests/crashes/121574.rs b/tests/crashes/121574.rs new file mode 100644 index 00000000000..53eec829c5f --- /dev/null +++ b/tests/crashes/121574.rs @@ -0,0 +1,6 @@ +//@ known-bug: #121574 +#![feature(generic_const_exprs)] + +impl<const Z: usize> X<Z> { + pub fn y<'a, U: 'a>(&'a self) -> impl Iterator<Item = impl Iterator<Item = [u8; Z]> + '_> {} +} diff --git a/tests/crashes/121575.rs b/tests/crashes/121575.rs new file mode 100644 index 00000000000..f0ce26c6f95 --- /dev/null +++ b/tests/crashes/121575.rs @@ -0,0 +1,107 @@ +//@ known-bug: #121575 +// ignore-tidy-linelength +#![feature(generic_const_exprs)] + +use std::array; + +trait PrimRec<const N: usize, const O: usize> { + fn eval(&self, x: [usize; N]) -> [usize; O]; +} + +struct Zero; + +impl<const N: usize> PrimRec<N, 1> for Zero { + fn eval(&self, _: [usize; N]) -> [usize; 1] { + [0] + } +} + +struct Const(usize); + +impl<const N: usize> PrimRec<N, 1> for Const { + fn eval(&self, _: [usize; N]) -> [usize; 1] { + [self.0] + } +} + +struct S; + +impl PrimRec<1, 1> for S { + fn eval(&self, x: [usize; 1]) -> [usize; 1] { + [x[0] + 1] + } +} + +struct Proj<const I: usize>; + +impl<const N: usize, const I: usize> PrimRec<N, 1> for Proj<I> { + fn eval(&self, x: [usize; N]) -> [usize; 1] { + [x[I]] + } +} + +struct Merge<const N: usize, const O1: usize, const O2: usize, A: PrimRec<N, O1>, B: PrimRec<N, O2>>( + A, + B, +); + +fn concat<const M: usize, const N: usize>(a: [usize; M], b: [usize; N]) -> [usize; M + N] { + array::from_fn(|i| if i < M { a[i] } else { b[i - M] }) +} + +impl<const N: usize, const O1: usize, const O2: usize, A: PrimRec<N, O1>, B: PrimRec<N, O2>> + PrimRec<N, { O1 + O2 }> for Merge<N, O1, O2, A, B> +{ + fn eval(&self, x: [usize; N]) -> [usize; O1 + O2] { + concat(self.0.eval(x), self.1.eval(x)) + } +} + +struct Compose<const N: usize, const I: usize, const O: usize, A: PrimRec<N, I>, B: PrimRec<I, O>>( + A, + B, +); + +impl<const N: usize, const I: usize, const O: usize, A: PrimRec<N, I>, B: PrimRec<I, O>> + PrimRec<N, O> for Compose<N, I, O, A, B> +{ + fn eval(&self, x: [usize; N]) -> [usize; O] { + self.1.eval(self.0.eval(x)) + } +} + +struct Rec<const N: usize, const O: usize, Base: PrimRec<N, O>, F: PrimRec<{ O + (N + 1) }, O>>( + Base, + F, +); + +fn tail<const N: usize>(x: [usize; N + 1]) -> [usize; N] { + array::from_fn(|i| x[i + 1]) +} + +fn cons<const N: usize>(x: usize, xs: [usize; N]) -> [usize; N + 1] { + array::from_fn(|i| if i == 0 { x } else { xs[i - 1] }) +} + +impl<const N: usize, const O: usize, Base: PrimRec<N, O>, F: PrimRec<{ O + (N + 1) }, O>> + PrimRec<{ N + 1 }, O> for Rec<N, O, Base, F> +{ + fn eval(&self, x: [usize; N + 1]) -> [usize; O] { + match (x[0], tail(x)) { + (0, x) => self.0.eval(x), + (y, x) => { + let xy = cons(y - 1, x); + let input = concat(self.eval(xy), xy); + self.1.eval(input) + } + } + } +} + +fn main() { + let one = Compose(Zero, S); + dbg!(one.eval([])); + let add: Rec<1, 1, Proj<0>, Compose<3, 1, 1, Proj<0>, S>> = + Rec(Proj::<0>, Compose(Proj::<0>, S)); + dbg!(add.eval([3, 2])); +} diff --git a/tests/crashes/121585-1.rs b/tests/crashes/121585-1.rs new file mode 100644 index 00000000000..2a4638efcab --- /dev/null +++ b/tests/crashes/121585-1.rs @@ -0,0 +1,13 @@ +//@ known-bug: #121585 +#![feature(generic_const_exprs)] + +trait Trait {} + +struct HasCastInTraitImpl<const N: usize, const M: u128>; +impl<const O: f64> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + +pub fn use_trait_impl() { + fn assert_impl<T: Trait>() {} + + assert_impl::<HasCastInTraitImpl<13, 13>>(); +} diff --git a/tests/crashes/121585-2.rs b/tests/crashes/121585-2.rs new file mode 100644 index 00000000000..99cc8f79195 --- /dev/null +++ b/tests/crashes/121585-2.rs @@ -0,0 +1,30 @@ +//@ known-bug: #121585 +//@ check-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Trait {} +pub struct EvaluatableU128<const N: u128>; + +struct HasCastInTraitImpl<const N: usize, const M: u128>; +impl<const O: f64> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + +pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, { + fn assert_impl<T: Trait>() {} + + assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>(); + assert_impl::<HasCastInTraitImpl<N, { N as _ }>>(); + assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>(); + assert_impl::<HasCastInTraitImpl<13, 13>>(); +} +pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, { + fn assert_impl<T: Trait>() {} + + assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>(); + assert_impl::<HasCastInTraitImpl<N, { N as _ }>>(); + assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>()const NUM: u8 = xyz(); + assert_impl::<HasCastInTraitImpl<13, 13>>(); +} + + +fn main() {} diff --git a/tests/crashes/121613-2.rs b/tests/crashes/121613-2.rs new file mode 100644 index 00000000000..ddc4f37c96a --- /dev/null +++ b/tests/crashes/121613-2.rs @@ -0,0 +1,28 @@ +//@ known-bug: #121613 +fn main() { + // destructure through a qualified path + let <Foo as A>::Assoc { br } = StructStruct { br: 2 }; + //~^ ERROR usage of qualified paths in this context is experimental + let _ = <Foo as A>::Assoc { br: 2 }; + //~^ ERROR usage of qualified paths in this context is experimental + let <E>::V(..) = E::V(|a, b| a.cmp(b)); + //~^ ERROR usage of qualified paths in this context is experimental +} + +struct StructStruct { + br: i8, +} + +struct Foo; + +trait A { + type Assoc; +} + +impl A for Foo { + type Assoc = StructStruct; +} + +enum E { + V(u8) +} diff --git a/tests/crashes/121613.rs b/tests/crashes/121613.rs new file mode 100644 index 00000000000..ec9ba82a68c --- /dev/null +++ b/tests/crashes/121613.rs @@ -0,0 +1,24 @@ +//@ known-bug: #121613 +fn main() { + let _ = <Foo as A>::Assoc { br: 2 }; + + let <E>::V(..) = E::V(|a, b| a.cmp(b)); +} + +struct StructStruct { + br: i8, +} + +struct Foo; + +trait A { + type Assoc; +} + +impl A for Foo { + type Assoc = StructStruct; +} + +enum E { + V(u8), +} diff --git a/tests/crashes/121623.rs b/tests/crashes/121623.rs new file mode 100644 index 00000000000..3c01a7f452c --- /dev/null +++ b/tests/crashes/121623.rs @@ -0,0 +1,8 @@ +//@ known-bug: #121623 +fn main() { + match () { + _ => 'b: { + continue 'b; + } + } +} diff --git a/tests/crashes/121722.rs b/tests/crashes/121722.rs new file mode 100644 index 00000000000..d1b8c447bf7 --- /dev/null +++ b/tests/crashes/121722.rs @@ -0,0 +1,10 @@ +//@ known-bug: #121722 +#[repr(C)] +struct Foo { + _: u8, +} + +#[repr(C)] +struct D { + _: Foo, +} diff --git a/tests/crashes/121799.rs b/tests/crashes/121799.rs new file mode 100644 index 00000000000..6035c9d9b15 --- /dev/null +++ b/tests/crashes/121799.rs @@ -0,0 +1,11 @@ +//@ known-bug: #121799 +struct S { + _: str +} + +fn func(a: S) +{ + let _x = a.f; +} + +fn main() {} diff --git a/tests/crashes/121816.rs b/tests/crashes/121816.rs new file mode 100644 index 00000000000..a5569ea19d3 --- /dev/null +++ b/tests/crashes/121816.rs @@ -0,0 +1,12 @@ +//@ known-bug: #121816 +fn f<'a, T>(_: &'static &'a (), x: &'a T) -> &'static T { + x +} +trait W<'a> { + fn g<T>(self, x: &'a T) -> &'static T; +} +impl<'a> W<'a> for &'static () { + fn g<T>(self, x: &'a T) -> &'static T { + f(&self, x) + } +} diff --git a/tests/crashes/121858-2.rs b/tests/crashes/121858-2.rs new file mode 100644 index 00000000000..cb80c081cff --- /dev/null +++ b/tests/crashes/121858-2.rs @@ -0,0 +1,20 @@ +//@ known-bug: #121858 +#![allow(named_arguments_used_positionally)] +#![feature(generic_const_exprs)] +struct Inner<const N: usize, const M: usize>; +impl<const N: usize, const M: usize> Inner<N, M> where [(); N + M]: { + fn i() -> Self { + Self + } +} + +struct Outer<const A: i64, const B: usize>(Inner<A, { B * 2 }>) where [(); A + (B * 2)]:; +impl<const A: usize, const B: usize> Outer<A, B> where [(); A + (B * 2)]: { + fn o() -> Union { + Self(Inner::i()) + } +} + +fn main() { + Outer::<1, 1>::o(); +} diff --git a/tests/crashes/121858.rs b/tests/crashes/121858.rs new file mode 100644 index 00000000000..7d5bae37f84 --- /dev/null +++ b/tests/crashes/121858.rs @@ -0,0 +1,14 @@ +//@ known-bug: #121858 +#![feature(generic_const_exprs)] + +struct Outer<const A: i64, const B: usize>(); +impl<const A: usize, const B: usize> Outer<A, B> +where + [(); A + (B * 2)]:, +{ + fn o() -> Union {} +} + +fn main() { + Outer::<1, 1>::o(); +} diff --git a/tests/crashes/121957-1.rs b/tests/crashes/121957-1.rs new file mode 100644 index 00000000000..74b4649cc9d --- /dev/null +++ b/tests/crashes/121957-1.rs @@ -0,0 +1,20 @@ +//@ known-bug: #121957 +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Main { + fn compute<T: ~const Aux>() -> u32; +} + +impl const Main for () { + fn compute<'x, 'y, 'z: 'x>() -> u32 {} +} + +#[const_trait] +trait Aux {} + +impl const Aux for () {} + +fn main() { + const _: u32 = <()>::compute::<()>(); +} diff --git a/tests/crashes/121957-2.rs b/tests/crashes/121957-2.rs new file mode 100644 index 00000000000..74b4649cc9d --- /dev/null +++ b/tests/crashes/121957-2.rs @@ -0,0 +1,20 @@ +//@ known-bug: #121957 +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Main { + fn compute<T: ~const Aux>() -> u32; +} + +impl const Main for () { + fn compute<'x, 'y, 'z: 'x>() -> u32 {} +} + +#[const_trait] +trait Aux {} + +impl const Aux for () {} + +fn main() { + const _: u32 = <()>::compute::<()>(); +} diff --git a/tests/crashes/121963.rs b/tests/crashes/121963.rs new file mode 100644 index 00000000000..c2ee8716f53 --- /dev/null +++ b/tests/crashes/121963.rs @@ -0,0 +1,26 @@ +//@ known-bug: #121963 +#![feature(generic_const_exprs)] +use std::marker::PhantomData; + +trait Arch { + const CHANNEL_COUNT: usize = 2; +} + +struct Channel<const N: usize> { + r: [u8; N], +} + +struct Dram<A: Arch, S = Channel<{ A::CHANNEL_COUNT }>> { + a: PhantomData<A>, + s: PhantomData<S>, +} + +struct C<A: Arch> +where + Channel<{ A::CHANNEL_COUNT }, u8>: Sized, +{ + b: Dram<A>, + // b: Dram<A, Channel<{ A::CHANNEL_COUNT }>>, // When I specified generic here, it worked +} + +fn main() {} diff --git a/tests/crashes/122044.rs b/tests/crashes/122044.rs new file mode 100644 index 00000000000..4c1d0de5719 --- /dev/null +++ b/tests/crashes/122044.rs @@ -0,0 +1,38 @@ +//@ known-bug: #122044 +use std::hint::black_box; + +trait Func { + type Ret: Id; +} + +trait Id { + type Assoc; +} +impl Id for u32 {} +impl Id for u32 {} + +impl<F: FnOnce() -> R, R: Id> Func for F { + type Ret = R; +} + +fn bar() -> impl Copy + Id { + 0u32 +} + +struct Foo<T: Func> { + _func: T, + value: Option<<<T as Func>::Ret as Id>::Assoc>, +} + +fn main() { + let mut fn_def = black_box(Foo { + _func: bar, + value: None, + }); + let fn_ptr = black_box(Foo { + _func: bar as fn() -> _, + value: None, + }); + + fn_def.value = fn_ptr.value; +} diff --git a/tests/crashes/122529.rs b/tests/crashes/122529.rs new file mode 100644 index 00000000000..87d393a4532 --- /dev/null +++ b/tests/crashes/122529.rs @@ -0,0 +1,8 @@ +//@ known-bug: #122529 +pub trait Archive { + type Archived; +} + +impl<'a> Archive for <&'a [u8] as Archive>::Archived { + type Archived = (); +} diff --git a/tests/crashes/122548.rs b/tests/crashes/122548.rs new file mode 100644 index 00000000000..232ce5d4413 --- /dev/null +++ b/tests/crashes/122548.rs @@ -0,0 +1,17 @@ +//@ known-bug: #122548 +#![feature(const_mut_refs)] +#![feature(const_refs_to_static)] + +use std::cell::UnsafeCell; + +struct Meh { + x: &'static UnsafeCell<i32>, +} + +const MUH: Meh = Meh { + x: &mut *(&READONLY as *const _ as *mut _), +}; + +static READONLY: i32 = 0; + +pub fn main() {} diff --git a/tests/crashes/122552.rs b/tests/crashes/122552.rs new file mode 100644 index 00000000000..29566941e22 --- /dev/null +++ b/tests/crashes/122552.rs @@ -0,0 +1,10 @@ +//@ known-bug: #122552 +//@ edition:2021 + +trait X { + fn line_stream<'a, Repr>() -> Self::LineStreamFut<{ async {} }, Repr>; +} + +struct Y; + +pub fn main() {} diff --git a/tests/crashes/122587-1.rs b/tests/crashes/122587-1.rs new file mode 100644 index 00000000000..ea0e843a10c --- /dev/null +++ b/tests/crashes/122587-1.rs @@ -0,0 +1,5 @@ +//@ known-bug: #122587 +const b: f16 = 0.0f16; +pub fn main() { + let b = 0.0f16; +} diff --git a/tests/crashes/122638.rs b/tests/crashes/122638.rs new file mode 100644 index 00000000000..af0fc5bbd50 --- /dev/null +++ b/tests/crashes/122638.rs @@ -0,0 +1,12 @@ +//@ known-bug: #122638 +#![feature(min_specialization)] + +impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, { N }> { + fn next(&mut self) -> Option<Self::Item> {} +} + +struct ConstChunksExact<'a, T: '_, const assert: usize> {} + +impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {}> { + type Item = &'a [T; N]; +} diff --git a/tests/crashes/122681.rs b/tests/crashes/122681.rs new file mode 100644 index 00000000000..7dae276950e --- /dev/null +++ b/tests/crashes/122681.rs @@ -0,0 +1,10 @@ +//@ known-bug: #122681 +#[rustc_layout_scalar_valid_range_start(1)] +struct UnitStruct; + +#[derive(Default)] +enum SomeEnum { + #[default] + Unit, + Tuple(UnitStruct), +} diff --git a/tests/crashes/122704.rs b/tests/crashes/122704.rs new file mode 100644 index 00000000000..d6c07be8318 --- /dev/null +++ b/tests/crashes/122704.rs @@ -0,0 +1,14 @@ +//@ known-bug: #122704 +use std::any::Any; + +pub struct Foo { + bar: Box<dyn for<'a> Fn(&'a usize) -> Box<dyn Any + 'a>>, +} + +impl Foo { + pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + self.bar = Box::new(|baz| Box::new(f(baz))); + } +} + +fn main() {} diff --git a/tests/crashes/122710.rs b/tests/crashes/122710.rs new file mode 100644 index 00000000000..16911fd522f --- /dev/null +++ b/tests/crashes/122710.rs @@ -0,0 +1,24 @@ +//@ known-bug: #122710 +use std::marker::PhantomData; + +pub trait BarTrait<T> { + fn bar(self, _: T); +} + +impl<T, F: Fn(T)> BarTrait<T> for F { + fn bar(self, _: T) { } +} + +impl<T: for<'a> MyTrait<'a>> BarTrait<T> for () { + fn bar(self, _: T) { } +} + +pub trait MyTrait<'a> { } + +impl<'a> MyTrait<'a> for PhantomData<&'a ()> { } + +fn foo() { + ().bar(PhantomData); +} + +pub fn main() {} diff --git a/tests/crashes/122736.rs b/tests/crashes/122736.rs new file mode 100644 index 00000000000..83b60444c2f --- /dev/null +++ b/tests/crashes/122736.rs @@ -0,0 +1,15 @@ +//@ known-bug: #122736 +fn main_ref() { + let array = [(); { + let mut x = &0; + let mut n = 0; + while n < 5 { + x = &0; + } + 0 + }]; + + let mut ptrs: Vec<*const [u8]> = vec![&array[0..0], &array[0..1], &array, &array[1..]]; +} + +fn main() {} diff --git a/tests/crashes/122823.rs b/tests/crashes/122823.rs new file mode 100644 index 00000000000..ec22b331ad9 --- /dev/null +++ b/tests/crashes/122823.rs @@ -0,0 +1,69 @@ +//@ known-bug: #122823 +//@ compile-flags: -Copt-level=0 +// ignore-tidy-linelength + +use std::vec::Vec; +use std::iter::Peekable; + +pub fn main() { + let packet = decode(vec![1,0,1,0]); +} + +pub fn decode(bitstream: Vec<u64>) -> Packet { + let mut bitstream_itr = bitstream.into_iter().peekable(); + return match decode_packet(&mut bitstream_itr) { + Some(p) => p, + None => panic!("expected outer packet"), + } +} + +pub fn decode_packets<I: Iterator<Item = u64>>(itr: &mut Peekable<I>) -> Vec<Packet> { + let mut res = Vec::new(); + loop { + match decode_packet(itr) { + Some(p) => { res.push(p); }, + None => break + } + } + + return res; +} + +pub fn decode_packet<I: Iterator<Item = u64>>(itr: &mut Peekable<I>) -> Option<Packet> { + // get version digits + let version = extend_number(0, itr, 3)?; + let type_id = extend_number(0, itr, 3)?; + return operator_packet(version, type_id, itr); +} + +pub fn operator_packet<I: Iterator<Item = u64>>(version: u64, type_id: u64, itr: &mut Peekable<I>) -> Option<Packet> { + let p = OperatorPacket { + version: version, + type_id: type_id, + packets: decode_packets(&mut itr.take(0).peekable()), + }; + + return Some(Packet::Operator(p)); +} + +pub fn extend_number<I: Iterator<Item = u64>>(num: u64, itr: &mut Peekable<I>, take: u64) -> Option<u64> { + let mut value = num; + for _ in 0..take { + value *= 2; + value += itr.next()?; + } + + return Some(value); +} + +#[derive(Debug)] +pub enum Packet { + Operator(OperatorPacket), +} + +#[derive(Debug)] +pub struct OperatorPacket { + version: u64, + type_id: u64, + packets: Vec<Packet> +} diff --git a/tests/crashes/122903-1.rs b/tests/crashes/122903-1.rs new file mode 100644 index 00000000000..9323c435851 --- /dev/null +++ b/tests/crashes/122903-1.rs @@ -0,0 +1,8 @@ +//@ known-bug: #122903 +impl Struct { + async fn box_box_ref_Struct( + self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>>, + ) -> &u32 { + f + } +} diff --git a/tests/crashes/122903-2.rs b/tests/crashes/122903-2.rs new file mode 100644 index 00000000000..0d5d93014c1 --- /dev/null +++ b/tests/crashes/122903-2.rs @@ -0,0 +1,9 @@ +//@ known-bug: #122903 + +impl Struct { + async fn box_box_ref_Struct( + self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>> + ) -> &u32 { + f + } +} diff --git a/tests/crashes/122904-2.rs b/tests/crashes/122904-2.rs new file mode 100644 index 00000000000..85ed91c2fa4 --- /dev/null +++ b/tests/crashes/122904-2.rs @@ -0,0 +1,15 @@ +//@ known-bug: #122904 +trait T {} + +type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S {} + +fn with_positive(fun: impl Fn(Alias<'_>)) { + with_positive(|&n| ()); +} + +fn main(Alias<'_>) { + with_positive(|&a| ()); +} diff --git a/tests/crashes/122904.rs b/tests/crashes/122904.rs new file mode 100644 index 00000000000..8b8bb35d56c --- /dev/null +++ b/tests/crashes/122904.rs @@ -0,0 +1,11 @@ +//@ known-bug: #122904 +trait T {} + +type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S {} + +fn with_positive(fun: impl Fn(Alias<'_>)) { + with_positive(|&n| ()); +} diff --git a/tests/crashes/122908.rs b/tests/crashes/122908.rs new file mode 100644 index 00000000000..c9da1bc1879 --- /dev/null +++ b/tests/crashes/122908.rs @@ -0,0 +1,4 @@ +//@ known-bug: #122908 +trait Trait<const module_path: Trait = bar> { + async fn handle<F>(slf: &F) {} +} diff --git a/tests/crashes/122909.rs b/tests/crashes/122909.rs new file mode 100644 index 00000000000..90bba772b91 --- /dev/null +++ b/tests/crashes/122909.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes +//@ known-bug: #122909 + + +use std::sync::{Arc, Context, Weak}; + +pub struct WeakOnce<T>(); +impl<T> WeakOnce<T> { + extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {} + + pub fn get(&self) -> Arc<T> { + self.try_get() + .unwrap_or_else(|| panic!("Singleton {} not available", std::any::type_name::<T>())) + } +} diff --git a/tests/crashes/122914.rs b/tests/crashes/122914.rs new file mode 100644 index 00000000000..63a84bc8099 --- /dev/null +++ b/tests/crashes/122914.rs @@ -0,0 +1,11 @@ +//@ known-bug: #122914 +use std::future::Future; +use std::pin::Pin; + +impl<'a, F> Poll { + fn project<'_>(self: Pin<&'pin mut Future>) -> Projection<'pin, 'a, F> { + me.local_set.with(|| { + let _ = self.poll(cx); + }) + } +} diff --git a/tests/crashes/122989.rs b/tests/crashes/122989.rs new file mode 100644 index 00000000000..70ad7d3b65c --- /dev/null +++ b/tests/crashes/122989.rs @@ -0,0 +1,8 @@ +//@ known-bug: #122989 +trait Traitor<const N: N<2> = 1, const N: N<2> = N> { + fn N(&N) -> N<2> { + M + } +} + +trait N<const N: Traitor<2> = 12> {} diff --git a/tests/crashes/123077-2.rs b/tests/crashes/123077-2.rs new file mode 100644 index 00000000000..e086e330337 --- /dev/null +++ b/tests/crashes/123077-2.rs @@ -0,0 +1,12 @@ +//@ known-bug: #123077 +//@ only-x86_64 +use std::arch::x86_64::{__m128, _mm_blend_ps}; + +pub fn sse41_blend_noinline( ) -> __m128 { + let f = { |x, y| unsafe { + _mm_blend_ps(x, y, { |x, y| unsafe }) + }}; + f(x, y) +} + +pub fn main() {} diff --git a/tests/crashes/123134.rs b/tests/crashes/123134.rs new file mode 100644 index 00000000000..61c043db763 --- /dev/null +++ b/tests/crashes/123134.rs @@ -0,0 +1,39 @@ +//@ known-bug: #123134 +trait Api: Sized { + type Device: ?Sized; +} + +struct OpenDevice<A: Api> +where + A::Device: Sized, +{ + device: A::Device, + queue: (), +} + +trait Adapter { + type A: Api; + + fn open() -> OpenDevice<Self::A> + where + <Self::A as Api>::Device: Sized; +} + +struct ApiS; + +impl Api for ApiS { + type Device = [u8]; +} + +impl<T> Adapter for T { + type A = ApiS; + + fn open() -> OpenDevice<Self::A> + where + <Self::A as Api>::Device: Sized, + { + unreachable!() + } +} + +pub fn main() {} diff --git a/tests/crashes/123140.rs b/tests/crashes/123140.rs new file mode 100644 index 00000000000..89e55baad98 --- /dev/null +++ b/tests/crashes/123140.rs @@ -0,0 +1,6 @@ +//@ known-bug: #123140 +trait Project { + const SELF: Self; +} + +fn take1(_: Project<SELF = { loop {} }>) {} diff --git a/tests/crashes/123141-2.rs b/tests/crashes/123141-2.rs new file mode 100644 index 00000000000..74f961c2a33 --- /dev/null +++ b/tests/crashes/123141-2.rs @@ -0,0 +1,23 @@ +//@ known-bug: #123141 + +trait ConstChunksExactTrait<T> { + fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}>; +} + +impl <T> ConstChunksExactTrait<T> for [T] {} + +struct ConstChunksExact<'a, T: 'a, const N: usize> {} + +impl <'a, T: , const N: usize> Iterator for ConstChunksExact<'a, T, {rem}> { + type Item = &'a [T; N]; +} + +fn main() { + let slice = &[1i32, 2, 3, 4, 5, 6, 7, 7, 9, 1i32]; + + let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8 ,9]].iter(); + + for a in slice.const_chunks_exact::<3>() { + assert_eq!(a, iter.next().unwrap()); + } +} diff --git a/tests/crashes/123141.rs b/tests/crashes/123141.rs new file mode 100644 index 00000000000..99dfee7670e --- /dev/null +++ b/tests/crashes/123141.rs @@ -0,0 +1,22 @@ +//@ known-bug: #123141 +trait ConstChunksExactTrait<T> { + fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, { N }>; +} + +impl<T> ConstChunksExactTrait<T> for [T] {} + +struct ConstChunksExact<'a, T: 'a, const N: usize> {} + +impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, { rem }> { + type Item = &'a [T; N]; +} + +fn main() { + let slice = &[1i32, 2, 3, 4, 5, 6, 7, 7, 9, 1i32]; + + let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8, 9]].iter(); + + for a in slice.const_chunks_exact::<3>() { + assert_eq!(a, iter.next().unwrap()); + } +} diff --git a/tests/crashes/123153.rs b/tests/crashes/123153.rs new file mode 100644 index 00000000000..d2c32ecd73e --- /dev/null +++ b/tests/crashes/123153.rs @@ -0,0 +1,17 @@ +//@ known-bug: #123153 +pub struct wl_interface { + pub version: str, +} + +pub struct Interface { + pub other_interfaces: &'static [&'static Interface], + pub c_ptr: Option<&'static wl_interface>, +} + +pub static mut wl_callback_interface: wl_interface = wl_interface { version: 0 }; + +pub static WL_CALLBACK_INTERFACE: Interface = + Interface { other_interfaces: &[], c_ptr: Some(unsafe { &wl_callback_interface }) }; + + +fn main() {} diff --git a/tests/crashes/123154.rs b/tests/crashes/123154.rs new file mode 100644 index 00000000000..510ae8adf35 --- /dev/null +++ b/tests/crashes/123154.rs @@ -0,0 +1,12 @@ +//@ known-bug: #123154 +struct AA { + pub data: [&usize] +} + +impl AA { + const fn new() -> Self { } +} + +static AA = AA::new(); + +fn main() { } diff --git a/tests/crashes/123157.rs b/tests/crashes/123157.rs new file mode 100644 index 00000000000..d6cc55ba052 --- /dev/null +++ b/tests/crashes/123157.rs @@ -0,0 +1,16 @@ +//@ known-bug: #123157 +//@ edition:2021 +#![feature(type_alias_impl_trait)] + +#[derive(Copy, Clone)] +struct Foo((u32, u32)); + +fn main() { + type T = impl Copy; + let foo: T = Foo((1u32, 2u32)); + let x = move || { + let x = move || { + let Foo((a, b)) = foo; + }; + }; +} diff --git a/tests/crashes/23707.rs b/tests/crashes/23707.rs new file mode 100644 index 00000000000..4105933c60f --- /dev/null +++ b/tests/crashes/23707.rs @@ -0,0 +1,109 @@ +//@ known-bug: #23707 +//@ compile-flags: -Copt-level=0 --edition=2021 +//@ only-x86_64 +#![recursion_limit="2048"] + +use std::marker::PhantomData; +use std::fmt; +use std::fmt::Debug; + +pub struct Z( () ); +pub struct S<T> (PhantomData<T>); + + +pub trait Nat { + fn sing() -> Self; + fn get(&self) -> usize; +} + +impl Nat for Z { + fn sing() -> Z { Z( () ) } + #[inline(always)] + fn get(&self) -> usize { + 0 + } +} + +impl<T : Nat> Nat for S<T> { + fn sing() -> S<T> { S::<T>( PhantomData::<T> ) } + #[inline(always)] + fn get(&self) -> usize { + let prd : T = Nat::sing(); + 1 + prd.get() + } +} + +pub type N0 = Z; +pub type N1 = S<N0>; +pub type N2 = S<N1>; +pub type N3 = S<N2>; +pub type N4 = S<N3>; +pub type N5 = S<N4>; + + +pub struct Node<D : Nat>(usize,PhantomData<D>); + +impl<D:Nat> Node<D> { + pub fn push(&self, c : usize) -> Node<S<D>> { + let Node(i,_) = *self; + Node(10*i+c, PhantomData::<S<D>>) + } +} + +impl<D:Nat> Node<S<D>> { + pub fn pop(&self) -> (Node<D>,usize) { + let Node(i,_) = *self; + (Node(i/10, PhantomData::<D>), i-10*(i/10)) + } +} + +impl<D:Nat> Debug for Node<D> { + fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result { + let s : D = Nat::sing(); + write!(f, "Node<{}>: i= {}", + s.get(), self.0) + } +} +pub trait Step { + fn step(&self, usize) -> Self; +} + +impl Step for Node<N0> { + #[inline(always)] + fn step(&self, n : usize) -> Node<N0> { + println!("base case"); + Node(n,PhantomData::<N0>) + } +} + +impl<D:Nat> Step for Node<S<D>> + where Node<D> : Step { + #[inline(always)] + fn step(&self, n : usize) -> Node<S<D>> { + println!("rec"); + let (par,c) = self.pop(); + let cnew = c+n; + par.step(c).push(cnew) + } + +} + +fn tst<D:Nat>(ref p : &Node<D>, c : usize) -> usize + where Node<D> : Step { + let Node(i,_) = p.step(c); + i +} + + + +fn main() { + let nd : Node<N3> = Node(555,PhantomData::<N3>); + + // overflow...core::marker::Size + let Node(g,_) = tst(nd,1); + + // ok + //let Node(g,_) = nd.step(1); + + println!("{:?}", g); +} diff --git a/tests/crashes/34127.rs b/tests/crashes/34127.rs new file mode 100644 index 00000000000..88a2cf30ec5 --- /dev/null +++ b/tests/crashes/34127.rs @@ -0,0 +1,7 @@ +//@ compile-flags: -g -Copt-level=0 +//@ known-bug: #34127 +//@ only-x86_64 + +pub fn main() { +let _a = [(); 1 << 63]; +} diff --git a/tests/crashes/54888.rs b/tests/crashes/54888.rs new file mode 100644 index 00000000000..2c87d7ee9e4 --- /dev/null +++ b/tests/crashes/54888.rs @@ -0,0 +1,21 @@ +//@ known-bug: #54888 + +#![feature(unsize, coerce_unsized)] + +use std::{ + ops::CoerceUnsized, + marker::Unsize, +}; + +#[repr(C)] +struct Ptr<T: ?Sized>(Box<T>); + +impl<T: ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> +where + T: Unsize<U>, +{} + + +fn main() { + let foo = Ptr(Box::new(5)) as Ptr<dyn std::any::Any>; +} diff --git a/tests/crashes/57276.rs b/tests/crashes/57276.rs new file mode 100644 index 00000000000..f70be4fba6d --- /dev/null +++ b/tests/crashes/57276.rs @@ -0,0 +1,11 @@ +//@ known-bug: #57276 + +#![feature(arbitrary_self_types, dispatch_from_dyn)] + +use std::ops::{Deref, DispatchFromDyn}; + +trait Trait<T: Deref<Target = Self> + DispatchFromDyn<T>> { + fn foo(self: T) -> dyn Trait<T>; +} + +fn main() {} diff --git a/tests/crashes/74299.rs b/tests/crashes/74299.rs new file mode 100644 index 00000000000..0e2ddce1c5b --- /dev/null +++ b/tests/crashes/74299.rs @@ -0,0 +1,24 @@ +//@ known-bug: #74299 +#![feature(specialization)] + +trait X { + type U; + fn f(&self) -> Self::U { + loop {} + } +} + +impl<T> X for T { + default type U = (); +} + +trait Y { + fn g(&self) {} +} + +impl Y for <() as X>::U {} +impl Y for <i32 as X>::U {} + +fn main() { + ().f().g(); +} diff --git a/tests/crashes/74451.rs b/tests/crashes/74451.rs new file mode 100644 index 00000000000..8f936994678 --- /dev/null +++ b/tests/crashes/74451.rs @@ -0,0 +1,42 @@ +//@ known-bug: #74451 +//@ compile-flags: -Copt-level=0 + +#![feature(specialization)] +#![feature(unsize, coerce_unsized)] +#![allow(incomplete_features)] +#![crate_type = "lib"] + +use std::ops::CoerceUnsized; + +pub struct SmartassPtr<A: Smartass+?Sized>(A::Data); + +pub trait Smartass { + type Data; + type Data2: CoerceUnsized<*const [u8]>; +} + +pub trait MaybeObjectSafe {} + +impl MaybeObjectSafe for () {} + +impl<T> Smartass for T { + type Data = <Self as Smartass>::Data2; + default type Data2 = *const [u8; 0]; +} + +impl Smartass for () { + type Data2 = *const [u8; 1]; +} + +impl Smartass for dyn MaybeObjectSafe { + type Data = *const [u8]; + type Data2 = *const [u8; 0]; +} + +impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for SmartassPtr<U> + where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data> +{} + +pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> { + s // This shouldn't coerce +} diff --git a/tests/crashes/79409.rs b/tests/crashes/79409.rs new file mode 100644 index 00000000000..98b5f606336 --- /dev/null +++ b/tests/crashes/79409.rs @@ -0,0 +1,16 @@ +//@ known-bug: #79409 + +#![feature(extern_types)] +#![feature(unsized_locals)] + +extern { + type Device; +} + +unsafe fn make_device() -> Box<Device> { + Box::from_raw(0 as *mut _) +} + +fn main() { + let d: Device = unsafe { *make_device() }; +} diff --git a/tests/crashes/79590.rs b/tests/crashes/79590.rs new file mode 100644 index 00000000000..b73864cce23 --- /dev/null +++ b/tests/crashes/79590.rs @@ -0,0 +1,19 @@ +//@ known-bug: #79590 + +trait Database: Restriction<Inner = u32> {} + +trait Restriction { + type Inner; +} + +struct Test {} + +impl Database for Test {} +impl Restriction for Test { + type Inner = u32; +} + +fn main() { + let t = Test {}; + let x: &dyn Database<Inner = _> = &t; +} diff --git a/tests/crashes/87577.rs b/tests/crashes/87577.rs new file mode 100644 index 00000000000..c632b72c147 --- /dev/null +++ b/tests/crashes/87577.rs @@ -0,0 +1,4 @@ +//@ known-bug: #87577 + +#[derive(Debug)] +struct S<#[cfg(feature = "alloc")] N: A<T>> {} diff --git a/tests/crashes/88296.rs b/tests/crashes/88296.rs new file mode 100644 index 00000000000..999834f5bde --- /dev/null +++ b/tests/crashes/88296.rs @@ -0,0 +1,27 @@ +//@ known-bug: #88296 + +#![feature(specialization)] + +trait Foo { + type Bar; +} + +impl<T> Foo for T { + default type Bar = u32; +} + +impl Foo for i32 { + type Bar = i32; +} + +extern "C" { + #[allow(unused)] + // OK as Foo::Bar is explicitly defined for i32 + static OK: <i32 as Foo>::Bar; + + #[allow(unused)] + // ICE in the improper_ctypes lint + // as Foo::Bar is only default implemented for () + static ICE: <() as Foo>::Bar; +} +pub fn main() {} diff --git a/tests/crashes/90110.rs b/tests/crashes/90110.rs new file mode 100644 index 00000000000..a27a1f42b7a --- /dev/null +++ b/tests/crashes/90110.rs @@ -0,0 +1,57 @@ +//@ known-bug: #90110 + +use std::fs::File; +use std::io::{BufReader, BufRead}; +use std::str::Split; +use std::path::Path; + +pub trait Parser<D> +where dyn Parser<D>: Sized +{ + fn new(split_header: Split<&str>) -> Self where Self: Sized; + fn parse_line(&self, split_line: &Split<&str>) -> D; +} + + +pub struct CsvReader<D> { + parser: Box<dyn Parser<D>>, + + reader: BufReader<File>, + buf: String, // Buffer we will read into. Avoids re-allocation on each line. + path: String, // Record this so we can return more informative error messages. + line: usize, // Same motivation for this. +} + +impl<D> CsvReader<D> +where dyn Parser<D>: Sized +{ + fn new<F>(path: &str, make_parser: F) -> CsvReader<D> + where F: Fn(Split<char>) -> dyn Parser<D> { + let file = match File::open(Path::new(path)) { + Err(err) => panic!("Couldn't read {}: {}", path, err), + Ok(file) => file, + }; + + let mut reader = BufReader::new(file); + + let mut buf = String::new(); + + let parser = Box::new(match reader.read_line(&mut buf) { + Err(err) => panic!("Failed to read the header line from {}: {}", path, err), + Ok(_) => { + let split_header = buf.split(','); + make_parser(split_header) + }, + }); + + CsvReader { + parser: parser, + reader, + buf, + path: path.to_string(), + line: 2, + } + } +} + +pub fn main() {} diff --git a/tests/crashes/91985.rs b/tests/crashes/91985.rs new file mode 100644 index 00000000000..338550430e1 --- /dev/null +++ b/tests/crashes/91985.rs @@ -0,0 +1,42 @@ +//@ known-bug: #91985 + +#![feature(generic_associated_types)] + +pub trait Trait1 { + type Associated: Ord; +} + +pub trait Trait2 { + type Associated: Clone; +} + +pub trait GatTrait { + type Gat<T: Clone>; +} + +pub struct GatStruct; + +impl GatTrait for GatStruct { + type Gat<T: Clone> = Box<T>; +} + +pub struct OuterStruct<T1: Trait1, T2: Trait2> { + inner: InnerStruct<T2, GatStruct>, + t1: T1, +} + +pub struct InnerStruct<T: Trait2, G: GatTrait> { + pub gat: G::Gat<T::Associated>, +} + +impl<T1, T2> OuterStruct<T1, T2> +where + T1: Trait1, + T2: Trait2<Associated = T1::Associated>, +{ + pub fn new() -> Self { + todo!() + } +} + +pub fn main() {} diff --git a/tests/crashes/92004.rs b/tests/crashes/92004.rs new file mode 100644 index 00000000000..bc2ca2a7ba3 --- /dev/null +++ b/tests/crashes/92004.rs @@ -0,0 +1,70 @@ +//@ known-bug: #102310 +//@ compile-flags: -Copt-level=0 +//@ edition:2021 +// ignore-tidy-linelength + +use std::vec::Vec; +use std::iter::Peekable; + +pub fn main() { + let packet = decode(vec![1,0,1,0]); +} + +pub fn decode(bitstream: Vec<u64>) -> Packet { + let mut bitstream_itr = bitstream.into_iter().peekable(); + return match decode_packet(&mut bitstream_itr) { + Some(p) => p, + None => panic!("expected outer packet"), + } +} + +pub fn decode_packets<I: Iterator<Item = u64>>(itr: &mut Peekable<I>) -> Vec<Packet> { + let mut res = Vec::new(); + loop { + match decode_packet(itr) { + Some(p) => { res.push(p); }, + None => break + } + } + + return res; +} + +pub fn decode_packet<I: Iterator<Item = u64>>(itr: &mut Peekable<I>) -> Option<Packet> { + // get version digits + let version = extend_number(0, itr, 3)?; + let type_id = extend_number(0, itr, 3)?; + return operator_packet(version, type_id, itr); +} + +pub fn operator_packet<I: Iterator<Item = u64>>(version: u64, type_id: u64, itr: &mut Peekable<I>) -> Option<Packet> { + let p = OperatorPacket { + version: version, + type_id: type_id, + packets: decode_packets(&mut itr.take(0).peekable()), + }; + + return Some(Packet::Operator(p)); +} + +pub fn extend_number<I: Iterator<Item = u64>>(num: u64, itr: &mut Peekable<I>, take: u64) -> Option<u64> { + let mut value = num; + for _ in 0..take { + value *= 2; + value += itr.next()?; + } + + return Some(value); +} + +#[derive(Debug)] +pub enum Packet { + Operator(OperatorPacket), +} + +#[derive(Debug)] +pub struct OperatorPacket { + version: u64, + type_id: u64, + packets: Vec<Packet> +} diff --git a/tests/crashes/93182.rs b/tests/crashes/93182.rs new file mode 100644 index 00000000000..f2e77c03533 --- /dev/null +++ b/tests/crashes/93182.rs @@ -0,0 +1,29 @@ +//@ known-bug: #93182 +#![feature(generic_const_exprs)] + +// this causes an ICE!!! +pub const CONST: usize = 64; +pub trait Tr<const S: usize = CONST>: Foo<A<S>> {} + +// no ICE +// pub trait Digest<const S: usize = 64>: FromH<[u8; S]> {} + +struct St (); + +struct A<const S: usize> ([u8; S]); + +pub trait Foo<T> { + fn foo(_: T); +} + +impl<const S: usize> Foo<A<S>> for St { + fn foo(_: A<S>) { + todo!() + } +} + +pub trait FooBar { + type Tr: Tr; +} + +pub fn main() {} diff --git a/tests/crashes/93237.rs b/tests/crashes/93237.rs new file mode 100644 index 00000000000..c903e79a2e3 --- /dev/null +++ b/tests/crashes/93237.rs @@ -0,0 +1,18 @@ +//@ known-bug: #93237 +trait Trait { + type Assoc; +} +impl Trait for () { + type Assoc = (); +} + +macro_rules! m { + ([#$($t:tt)*] [$($open:tt)*] [$($close:tt)*]) => { + m!{[$($t)*][$($open)*$($open)*][$($close)*$($close)*]} + }; + ([] [$($open:tt)*] [$($close:tt)*]) => { + fn _f() -> $($open)*()$($close)* {} + }; +} + +m! {[###########][impl Trait<Assoc =][>]} diff --git a/tests/crashes/94846.rs b/tests/crashes/94846.rs new file mode 100644 index 00000000000..9a3b26621d9 --- /dev/null +++ b/tests/crashes/94846.rs @@ -0,0 +1,6 @@ +//@ known-bug: #94846 +#![feature(generic_const_exprs)] + +struct S<const C:() = {}>() where S<{}>:; + +pub fn main() {} diff --git a/tests/crashes/95134.rs b/tests/crashes/95134.rs new file mode 100644 index 00000000000..bcd88b1076f --- /dev/null +++ b/tests/crashes/95134.rs @@ -0,0 +1,27 @@ +//@ known-bug: #95134 +//@ compile-flags: -Copt-level=0 + +pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> { + if n > 15 { + encode_num(n / 16, &mut writer)?; + } + Ok(()) +} + +pub trait ExampleWriter { + type Error; +} + +impl<'a, T: ExampleWriter> ExampleWriter for &'a mut T { + type Error = T::Error; +} + +struct EmptyWriter; + +impl ExampleWriter for EmptyWriter { + type Error = (); +} + +fn main() { + encode_num(69, &mut EmptyWriter).unwrap(); +} diff --git a/tests/crashes/96304.rs b/tests/crashes/96304.rs new file mode 100644 index 00000000000..637012f4585 --- /dev/null +++ b/tests/crashes/96304.rs @@ -0,0 +1,6 @@ +//@ known-bug: #96304 + +#![feature(asm_sym)] +core::arch::global_asm!("/* {} */", sym<&'static ()>::clone); + +pub fn main() {} diff --git a/tests/crashes/97501.rs b/tests/crashes/97501.rs new file mode 100644 index 00000000000..51a83d8be16 --- /dev/null +++ b/tests/crashes/97501.rs @@ -0,0 +1,22 @@ +//@ known-bug: #97501 + +#![feature(core_intrinsics)] +use std::intrinsics::wrapping_add; + +#[derive(Clone, Copy)] +struct WrapInt8 { + value: u8 +} + +impl std::ops::Add for WrapInt8 { + type Output = WrapInt8; + fn add(self, other: WrapInt8) -> WrapInt8 { + wrapping_add(self, other) + } +} + +fn main() { + let p = WrapInt8 { value: 123 }; + let q = WrapInt8 { value: 234 }; + println!("{}", (p + q).value); +} diff --git a/tests/crashes/98322.rs b/tests/crashes/98322.rs new file mode 100644 index 00000000000..57b34916029 --- /dev/null +++ b/tests/crashes/98322.rs @@ -0,0 +1,37 @@ +//@ known-bug: #98322 + +#![feature(generic_const_exprs)] + +// Main function seems irrelevant +fn main() {} + +// Constant must be provided via an associated constant in a trait +pub trait ConstTrait { + const ASSOC_CONST: usize; +} + +// For some reason I find it's necessary to have an implementation of this trait that recurses +pub trait OtherTrait +{ + fn comm(self); +} + +// There must be a blanket impl here +impl<T> OtherTrait for T where + T: ConstTrait, + [();T::ASSOC_CONST]: Sized, +{ + fn comm(self) { + todo!() + } +} + +// The struct must be recursive +pub struct RecursiveStruct(Box<RecursiveStruct>); + +// This implementation must exist, and it must recurse into its child +impl OtherTrait for RecursiveStruct { + fn comm(self) { + (self.0).comm(); + } +} diff --git a/tests/crashes/README.md b/tests/crashes/README.md new file mode 100644 index 00000000000..dee11e2a3dd --- /dev/null +++ b/tests/crashes/README.md @@ -0,0 +1,16 @@ +This is serves as a collection of crashes so that accidental ICE fixes are tracked. +This was formally done at https://github.com/rust-lang/glacier but doing it inside +the rustc testsuite is more convenient. + +It is imperative that a test in the suite causes an internal compiler error/panic +or makes rustc crash in some other way. +A test will "pass" if rustc exits with something other than 1 or 0. + +When adding crashes from https://github.com/rust-lang/rust/issues, the +issue number should be noted in the file name (12345.rs should suffice) +and perhaps also inside the file via `//@ known-bug #4321` + +If you happen to fix one of the crashes, please move it to a fitting +subdirectory in `tests/ui` and give it a meaningful name. +Also please add a doc comment at the top of the file explaining why +this test exists. :) diff --git a/tests/incremental/spike-neg1.rs b/tests/incremental/spike-neg1.rs index c5fe31862b4..356c61759f9 100644 --- a/tests/incremental/spike-neg1.rs +++ b/tests/incremental/spike-neg1.rs @@ -7,6 +7,7 @@ //@ revisions:rpass1 rpass2 //@ should-fail +//@ compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/tests/incremental/spike-neg2.rs b/tests/incremental/spike-neg2.rs index 140aa4684a7..9f69d7a757a 100644 --- a/tests/incremental/spike-neg2.rs +++ b/tests/incremental/spike-neg2.rs @@ -7,6 +7,7 @@ //@ revisions:rpass1 rpass2 //@ should-fail +//@ compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index 76938c14e1e..cb72ad3d253 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,36 +1,36 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10] -| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10] -| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10] -| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] -| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10] +| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send +| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10] +| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send +| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10] +| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send +| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] | fn address_of_reborrow() -> () { let mut _0: (); diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 5df6633880e..5c0d1e9b93f 100644 --- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> -| 1: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> +| 0: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> +| 1: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 19a777cb03b..0f7917dbb5c 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> -| 1: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> +| 0: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> +| 1: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index e07c2b6fa9d..1855bb0787d 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -1,10 +1,10 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test -| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test +| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test +| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 7a374c5675a..4af3ed3e1d1 100644 --- a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -12,8 +12,6 @@ let mut _7: isize; let _8: u32; let _9: u32; -+ let mut _10: isize; -+ let mut _11: bool; scope 1 { debug a => _8; debug b => _9; @@ -29,28 +27,20 @@ StorageDead(_5); StorageDead(_4); _7 = discriminant((_3.0: std::option::Option<u32>)); -- switchInt(move _7) -> [1: bb2, otherwise: bb1]; -+ StorageLive(_10); -+ _10 = discriminant((_3.1: std::option::Option<u32>)); -+ StorageLive(_11); -+ _11 = Ne(_7, move _10); -+ StorageDead(_10); -+ switchInt(move _11) -> [0: bb4, otherwise: bb1]; + switchInt(move _7) -> [1: bb2, 0: bb1, otherwise: bb5]; } bb1: { -+ StorageDead(_11); _0 = const 1_u32; -- goto -> bb4; -+ goto -> bb3; + goto -> bb4; } bb2: { -- _6 = discriminant((_3.1: std::option::Option<u32>)); -- switchInt(move _6) -> [1: bb3, otherwise: bb1]; -- } -- -- bb3: { + _6 = discriminant((_3.1: std::option::Option<u32>)); + switchInt(move _6) -> [1: bb3, 0: bb1, otherwise: bb5]; + } + + bb3: { StorageLive(_8); _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); StorageLive(_9); @@ -58,19 +48,16 @@ _0 = const 0_u32; StorageDead(_9); StorageDead(_8); -- goto -> bb4; -+ goto -> bb3; + goto -> bb4; } -- bb4: { -+ bb3: { + bb4: { StorageDead(_3); return; -+ } -+ -+ bb4: { -+ StorageDead(_11); -+ switchInt(_7) -> [1: bb2, otherwise: bb1]; + } + + bb5: { + unreachable; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 1348bdd739a..7776ff0fde7 100644 --- a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -13,8 +13,6 @@ let mut _8: isize; let _9: u32; let _10: u32; -+ let mut _11: isize; -+ let mut _12: bool; scope 1 { debug a => _9; debug b => _10; @@ -30,33 +28,25 @@ StorageDead(_5); StorageDead(_4); _8 = discriminant((_3.0: std::option::Option<u32>)); -- switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1]; -+ StorageLive(_11); -+ _11 = discriminant((_3.1: std::option::Option<u32>)); -+ StorageLive(_12); -+ _12 = Ne(_8, move _11); -+ StorageDead(_11); -+ switchInt(move _12) -> [0: bb5, otherwise: bb1]; + switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb7]; } bb1: { -+ StorageDead(_12); _0 = const 1_u32; -- goto -> bb6; -+ goto -> bb4; + goto -> bb6; } bb2: { -- _6 = discriminant((_3.1: std::option::Option<u32>)); -- switchInt(move _6) -> [1: bb4, otherwise: bb1]; -- } -- -- bb3: { -- _7 = discriminant((_3.1: std::option::Option<u32>)); -- switchInt(move _7) -> [0: bb5, otherwise: bb1]; -- } -- -- bb4: { + _6 = discriminant((_3.1: std::option::Option<u32>)); + switchInt(move _6) -> [1: bb4, 0: bb1, otherwise: bb7]; + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option<u32>)); + switchInt(move _7) -> [0: bb5, 1: bb1, otherwise: bb7]; + } + + bb4: { StorageLive(_9); _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32); StorageLive(_10); @@ -64,26 +54,21 @@ _0 = const 0_u32; StorageDead(_10); StorageDead(_9); -- goto -> bb6; -+ goto -> bb4; + goto -> bb6; } -- bb5: { -+ bb3: { - _0 = const 0_u32; -- goto -> bb6; -+ goto -> bb4; + bb5: { + _0 = const 2_u32; + goto -> bb6; } -- bb6: { -+ bb4: { + bb6: { StorageDead(_3); return; -+ } -+ -+ bb5: { -+ StorageDead(_12); -+ switchInt(_8) -> [0: bb3, 1: bb2, otherwise: bb1]; + } + + bb7: { + unreachable; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index e058c409cb5..b41e952d80f 100644 --- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -1,76 +1,107 @@ - // MIR for `opt3` before EarlyOtherwiseBranch + // MIR for `opt3` after EarlyOtherwiseBranch - fn opt3(_1: Option<u32>, _2: Option<bool>) -> u32 { + fn opt3(_1: Option2<u32>, _2: Option2<bool>) -> u32 { debug x => _1; debug y => _2; let mut _0: u32; - let mut _3: (std::option::Option<u32>, std::option::Option<bool>); - let mut _4: std::option::Option<u32>; - let mut _5: std::option::Option<bool>; + let mut _3: (Option2<u32>, Option2<bool>); + let mut _4: Option2<u32>; + let mut _5: Option2<bool>; let mut _6: isize; let mut _7: isize; - let _8: u32; - let _9: bool; -+ let mut _10: isize; -+ let mut _11: bool; + let mut _8: isize; + let mut _9: isize; + let _10: u32; + let _11: bool; ++ let mut _12: isize; ++ let mut _13: bool; scope 1 { - debug a => _8; - debug b => _9; + debug a => _10; + debug b => _11; } bb0: { StorageLive(_3); StorageLive(_4); - _4 = _1; + _4 = move _1; StorageLive(_5); - _5 = _2; + _5 = move _2; _3 = (move _4, move _5); StorageDead(_5); StorageDead(_4); - _7 = discriminant((_3.0: std::option::Option<u32>)); -- switchInt(move _7) -> [1: bb2, otherwise: bb1]; -+ StorageLive(_10); -+ _10 = discriminant((_3.1: std::option::Option<bool>)); -+ StorageLive(_11); -+ _11 = Ne(_7, move _10); -+ StorageDead(_10); -+ switchInt(move _11) -> [0: bb4, otherwise: bb1]; + _9 = discriminant((_3.0: Option2<u32>)); +- switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; ++ StorageLive(_12); ++ _12 = discriminant((_3.1: Option2<bool>)); ++ StorageLive(_13); ++ _13 = Ne(_9, move _12); ++ StorageDead(_12); ++ switchInt(move _13) -> [0: bb7, otherwise: bb1]; } bb1: { -+ StorageDead(_11); ++ StorageDead(_13); _0 = const 1_u32; -- goto -> bb4; -+ goto -> bb3; +- goto -> bb8; ++ goto -> bb5; } bb2: { -- _6 = discriminant((_3.1: std::option::Option<bool>)); -- switchInt(move _6) -> [1: bb3, otherwise: bb1]; +- _6 = discriminant((_3.1: Option2<bool>)); +- switchInt(move _6) -> [0: bb5, otherwise: bb1]; - } - - bb3: { - StorageLive(_8); - _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); - StorageLive(_9); - _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool); +- _7 = discriminant((_3.1: Option2<bool>)); +- switchInt(move _7) -> [1: bb6, otherwise: bb1]; +- } +- +- bb4: { +- _8 = discriminant((_3.1: Option2<bool>)); +- switchInt(move _8) -> [2: bb7, otherwise: bb1]; +- } +- +- bb5: { + StorageLive(_10); + _10 = (((_3.0: Option2<u32>) as Some).0: u32); + StorageLive(_11); + _11 = (((_3.1: Option2<bool>) as Some).0: bool); _0 = const 0_u32; - StorageDead(_9); - StorageDead(_8); -- goto -> bb4; -+ goto -> bb3; + StorageDead(_11); + StorageDead(_10); +- goto -> bb8; ++ goto -> bb5; } -- bb4: { +- bb6: { + bb3: { + _0 = const 2_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb7: { ++ bb4: { + _0 = const 3_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb8: { ++ bb5: { StorageDead(_3); return; + } + +- bb9: { ++ bb6: { + unreachable; + } + -+ bb4: { -+ StorageDead(_11); -+ switchInt(_7) -> [1: bb2, otherwise: bb1]; ++ bb7: { ++ StorageDead(_13); ++ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..18dea56f430 --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff @@ -0,0 +1,107 @@ +- // MIR for `opt4` before EarlyOtherwiseBranch ++ // MIR for `opt4` after EarlyOtherwiseBranch + + fn opt4(_1: Option2<u32>, _2: Option2<u32>) -> u32 { + debug x => _1; + debug y => _2; + let mut _0: u32; + let mut _3: (Option2<u32>, Option2<u32>); + let mut _4: Option2<u32>; + let mut _5: Option2<u32>; + let mut _6: isize; + let mut _7: isize; + let mut _8: isize; + let mut _9: isize; + let _10: u32; + let _11: u32; ++ let mut _12: isize; ++ let mut _13: bool; + scope 1 { + debug a => _10; + debug b => _11; + } + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = move _1; + StorageLive(_5); + _5 = move _2; + _3 = (move _4, move _5); + StorageDead(_5); + StorageDead(_4); + _9 = discriminant((_3.0: Option2<u32>)); +- switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; ++ StorageLive(_12); ++ _12 = discriminant((_3.1: Option2<u32>)); ++ StorageLive(_13); ++ _13 = Ne(_9, move _12); ++ StorageDead(_12); ++ switchInt(move _13) -> [0: bb7, otherwise: bb1]; + } + + bb1: { ++ StorageDead(_13); + _0 = const 1_u32; +- goto -> bb8; ++ goto -> bb5; + } + + bb2: { +- _6 = discriminant((_3.1: Option2<u32>)); +- switchInt(move _6) -> [0: bb5, otherwise: bb1]; +- } +- +- bb3: { +- _7 = discriminant((_3.1: Option2<u32>)); +- switchInt(move _7) -> [1: bb6, otherwise: bb1]; +- } +- +- bb4: { +- _8 = discriminant((_3.1: Option2<u32>)); +- switchInt(move _8) -> [2: bb7, otherwise: bb1]; +- } +- +- bb5: { + StorageLive(_10); + _10 = (((_3.0: Option2<u32>) as Some).0: u32); + StorageLive(_11); + _11 = (((_3.1: Option2<u32>) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_11); + StorageDead(_10); +- goto -> bb8; ++ goto -> bb5; + } + +- bb6: { ++ bb3: { + _0 = const 2_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb7: { ++ bb4: { + _0 = const 3_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb8: { ++ bb5: { + StorageDead(_3); + return; + } + +- bb9: { ++ bb6: { + unreachable; ++ } ++ ++ bb7: { ++ StorageDead(_13); ++ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6]; + } + } + diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index c984c271ccd..bfeb1f7bbc6 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -1,27 +1,79 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching + +enum Option2<T> { + Some(T), + None, + Other, +} + +// We can't optimize it because y may be an invalid value. // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff fn opt1(x: Option<u32>, y: Option<u32>) -> u32 { + // CHECK-LABEL: fn opt1( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y) { (Some(a), Some(b)) => 0, _ => 1, } } +// FIXME: `switchInt` will have three targets after `UnreachableEnumBranching`, +// otherwise is unreachable. We can consume the UB fact to transform back to if else pattern. // EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff fn opt2(x: Option<u32>, y: Option<u32>) -> u32 { + // CHECK-LABEL: fn opt2( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y) { (Some(a), Some(b)) => 0, - (None, None) => 0, + (None, None) => 2, _ => 1, } } // optimize despite different types // EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff -fn opt3(x: Option<u32>, y: Option<bool>) -> u32 { +fn opt3(x: Option2<u32>, y: Option2<bool>) -> u32 { + // CHECK-LABEL: fn opt3( + // CHECK: let mut [[CMP_LOCAL:_.*]]: bool; + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}}); + // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]); + // CHECK: switchInt(move [[CMP_LOCAL]]) -> [ + // CHECK-NEXT: } match (x, y) { - (Some(a), Some(b)) => 0, + (Option2::Some(a), Option2::Some(b)) => 0, + (Option2::None, Option2::None) => 2, + (Option2::Other, Option2::Other) => 3, + _ => 1, + } +} + +// EMIT_MIR early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff +fn opt4(x: Option2<u32>, y: Option2<u32>) -> u32 { + // CHECK-LABEL: fn opt4( + // CHECK: let mut [[CMP_LOCAL:_.*]]: bool; + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}}); + // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]); + // CHECK: switchInt(move [[CMP_LOCAL]]) -> [ + // CHECK-NEXT: } + match (x, y) { + (Option2::Some(a), Option2::Some(b)) => 0, + (Option2::None, Option2::None) => 2, + (Option2::Other, Option2::Other) => 3, _ => 1, } } @@ -29,5 +81,6 @@ fn opt3(x: Option<u32>, y: Option<bool>) -> u32 { fn main() { opt1(None, Some(0)); opt2(None, Some(0)); - opt3(None, Some(false)); + opt3(Option2::None, Option2::Some(false)); + opt4(Option2::None, Option2::Some(0)); } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index f98d68e6ffc..4c3c717b522 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -13,17 +13,15 @@ let mut _8: isize; let mut _9: isize; let mut _10: isize; - let _11: u32; - let _12: u32; + let mut _11: isize; + let mut _12: isize; let _13: u32; -+ let mut _14: isize; -+ let mut _15: bool; -+ let mut _16: isize; -+ let mut _17: bool; + let _14: u32; + let _15: u32; scope 1 { - debug a => _11; - debug b => _12; - debug c => _13; + debug a => _13; + debug b => _14; + debug c => _15; } bb0: { @@ -38,60 +36,61 @@ StorageDead(_7); StorageDead(_6); StorageDead(_5); - _10 = discriminant((_4.0: std::option::Option<u32>)); -- switchInt(move _10) -> [1: bb2, otherwise: bb1]; -+ StorageLive(_14); -+ _14 = discriminant((_4.1: std::option::Option<u32>)); -+ StorageLive(_15); -+ _15 = Ne(_10, move _14); -+ StorageDead(_14); -+ switchInt(move _15) -> [0: bb5, otherwise: bb1]; + _12 = discriminant((_4.0: std::option::Option<u32>)); + switchInt(move _12) -> [0: bb4, 1: bb2, otherwise: bb9]; } bb1: { -+ StorageDead(_17); -+ StorageDead(_15); _0 = const 1_u32; -- goto -> bb5; -+ goto -> bb4; + goto -> bb8; } bb2: { -- _9 = discriminant((_4.1: std::option::Option<u32>)); -- switchInt(move _9) -> [1: bb3, otherwise: bb1]; -- } -- -- bb3: { + _9 = discriminant((_4.1: std::option::Option<u32>)); + switchInt(move _9) -> [1: bb3, 0: bb1, otherwise: bb9]; + } + + bb3: { _8 = discriminant((_4.2: std::option::Option<u32>)); -- switchInt(move _8) -> [1: bb4, otherwise: bb1]; -+ switchInt(move _8) -> [1: bb3, otherwise: bb1]; + switchInt(move _8) -> [1: bb6, 0: bb1, otherwise: bb9]; + } + + bb4: { + _11 = discriminant((_4.1: std::option::Option<u32>)); + switchInt(move _11) -> [0: bb5, 1: bb1, otherwise: bb9]; + } + + bb5: { + _10 = discriminant((_4.2: std::option::Option<u32>)); + switchInt(move _10) -> [0: bb7, 1: bb1, otherwise: bb9]; } -- bb4: { -+ bb3: { - StorageLive(_11); - _11 = (((_4.0: std::option::Option<u32>) as Some).0: u32); - StorageLive(_12); - _12 = (((_4.1: std::option::Option<u32>) as Some).0: u32); + bb6: { StorageLive(_13); - _13 = (((_4.2: std::option::Option<u32>) as Some).0: u32); + _13 = (((_4.0: std::option::Option<u32>) as Some).0: u32); + StorageLive(_14); + _14 = (((_4.1: std::option::Option<u32>) as Some).0: u32); + StorageLive(_15); + _15 = (((_4.2: std::option::Option<u32>) as Some).0: u32); _0 = const 0_u32; + StorageDead(_15); + StorageDead(_14); StorageDead(_13); - StorageDead(_12); - StorageDead(_11); -- goto -> bb5; -+ goto -> bb4; + goto -> bb8; + } + + bb7: { + _0 = const 2_u32; + goto -> bb8; } -- bb5: { -+ bb4: { + bb8: { StorageDead(_4); return; -+ } -+ -+ bb5: { -+ StorageDead(_15); -+ switchInt(_10) -> [1: bb2, otherwise: bb1]; + } + + bb9: { + unreachable; } } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..0ea7a10baaa --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,141 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: Option2<u32>, _2: Option2<u32>, _3: Option2<u32>) -> u32 { + debug x => _1; + debug y => _2; + debug z => _3; + let mut _0: u32; + let mut _4: (Option2<u32>, Option2<u32>, Option2<u32>); + let mut _5: Option2<u32>; + let mut _6: Option2<u32>; + let mut _7: Option2<u32>; + let mut _8: isize; + let mut _9: isize; + let mut _10: isize; + let mut _11: isize; + let mut _12: isize; + let mut _13: isize; + let mut _14: isize; + let _15: u32; + let _16: u32; + let _17: u32; ++ let mut _18: isize; ++ let mut _19: bool; + scope 1 { + debug a => _15; + debug b => _16; + debug c => _17; + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = move _1; + StorageLive(_6); + _6 = move _2; + StorageLive(_7); + _7 = move _3; + _4 = (move _5, move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); + _14 = discriminant((_4.0: Option2<u32>)); +- switchInt(move _14) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb12]; ++ StorageLive(_18); ++ _18 = discriminant((_4.1: Option2<u32>)); ++ StorageLive(_19); ++ _19 = Ne(_14, move _18); ++ StorageDead(_18); ++ switchInt(move _19) -> [0: bb10, otherwise: bb1]; + } + + bb1: { ++ StorageDead(_19); + _0 = const 1_u32; +- goto -> bb11; ++ goto -> bb8; + } + + bb2: { +- _9 = discriminant((_4.1: Option2<u32>)); +- switchInt(move _9) -> [0: bb3, otherwise: bb1]; +- } +- +- bb3: { + _8 = discriminant((_4.2: Option2<u32>)); +- switchInt(move _8) -> [0: bb8, otherwise: bb1]; ++ switchInt(move _8) -> [0: bb5, otherwise: bb1]; + } + +- bb4: { +- _11 = discriminant((_4.1: Option2<u32>)); +- switchInt(move _11) -> [1: bb5, otherwise: bb1]; +- } +- +- bb5: { ++ bb3: { + _10 = discriminant((_4.2: Option2<u32>)); +- switchInt(move _10) -> [1: bb9, otherwise: bb1]; ++ switchInt(move _10) -> [1: bb6, otherwise: bb1]; + } + +- bb6: { +- _13 = discriminant((_4.1: Option2<u32>)); +- switchInt(move _13) -> [2: bb7, otherwise: bb1]; +- } +- +- bb7: { ++ bb4: { + _12 = discriminant((_4.2: Option2<u32>)); +- switchInt(move _12) -> [2: bb10, otherwise: bb1]; ++ switchInt(move _12) -> [2: bb7, otherwise: bb1]; + } + +- bb8: { ++ bb5: { + StorageLive(_15); + _15 = (((_4.0: Option2<u32>) as Some).0: u32); + StorageLive(_16); + _16 = (((_4.1: Option2<u32>) as Some).0: u32); + StorageLive(_17); + _17 = (((_4.2: Option2<u32>) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); +- goto -> bb11; ++ goto -> bb8; + } + +- bb9: { ++ bb6: { + _0 = const 2_u32; +- goto -> bb11; ++ goto -> bb8; + } + +- bb10: { ++ bb7: { + _0 = const 3_u32; +- goto -> bb11; ++ goto -> bb8; + } + +- bb11: { ++ bb8: { + StorageDead(_4); + return; + } + +- bb12: { ++ bb9: { + unreachable; ++ } ++ ++ bb10: { ++ StorageDead(_19); ++ switchInt(_14) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; + } + } + diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs b/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs index 32081347558..2d215621bbd 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs @@ -1,14 +1,49 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching +enum Option2<T> { + Some(T), + None, + Other, +} + +// FIXME: `switchInt` will have three targets after `UnreachableEnumBranching`, +// otherwise is unreachable. We can consume the UB fact to transform back to if else pattern. // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 { + // CHECK-LABEL: fn opt1( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y, z) { (Some(a), Some(b), Some(c)) => 0, + (None, None, None) => 2, + _ => 1, + } +} + +// EMIT_MIR early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff +fn opt2(x: Option2<u32>, y: Option2<u32>, z: Option2<u32>) -> u32 { + // CHECK-LABEL: fn opt2( + // CHECK: let mut [[CMP_LOCAL:_.*]]: bool; + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}}); + // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]); + // CHECK: switchInt(move [[CMP_LOCAL]]) -> [ + // CHECK-NEXT: } + match (x, y, z) { + (Option2::Some(a), Option2::Some(b), Option2::Some(c)) => 0, + (Option2::None, Option2::None, Option2::None) => 2, + (Option2::Other, Option2::Other, Option2::Other) => 3, _ => 1, } } fn main() { opt1(None, Some(0), None); + opt2(Option2::None, Option2::Some(0), Option2::None); } diff --git a/tests/mir-opt/early_otherwise_branch_68867.rs b/tests/mir-opt/early_otherwise_branch_68867.rs index 805d21533c5..59bc19ceecc 100644 --- a/tests/mir-opt/early_otherwise_branch_68867.rs +++ b/tests/mir-opt/early_otherwise_branch_68867.rs @@ -1,5 +1,5 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching // FIXME: This test was broken by the derefer change. @@ -19,6 +19,13 @@ pub extern "C" fn try_sum( x: &ViewportPercentageLength, other: &ViewportPercentageLength, ) -> Result<ViewportPercentageLength, ()> { + // CHECK-LABEL: fn try_sum( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } use self::ViewportPercentageLength::*; Ok(match (x, other) { (&Vw(one), &Vw(other)) => Vw(one + other), diff --git a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index a5b5659a31a..de12fe8f120 100644 --- a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -78,7 +78,7 @@ StorageDead(_5); _34 = deref_copy (_4.0: &ViewportPercentageLength); _11 = discriminant((*_34)); - switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb1]; + switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb12]; } bb1: { @@ -213,5 +213,9 @@ bb11: { return; } + + bb12: { + unreachable; + } } diff --git a/tests/mir-opt/early_otherwise_branch_noopt.rs b/tests/mir-opt/early_otherwise_branch_noopt.rs index 648089e2df1..6b48393e6b9 100644 --- a/tests/mir-opt/early_otherwise_branch_noopt.rs +++ b/tests/mir-opt/early_otherwise_branch_noopt.rs @@ -1,11 +1,18 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching // must not optimize as it does not follow the pattern of // left and right hand side being the same variant // EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff fn noopt1(x: Option<u32>, y: Option<u32>) -> u32 { + // CHECK-LABEL: fn noopt1( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y) { (Some(a), Some(b)) => 0, (Some(a), None) => 1, diff --git a/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff index b24ff6ec74b..8eab59823f4 100644 --- a/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff @@ -14,7 +14,7 @@ bb0: { _3 = discriminant(_1); - switchInt(move _3) -> [1: bb2, otherwise: bb1]; + switchInt(move _3) -> [1: bb2, 0: bb1, otherwise: bb6]; } bb1: { @@ -24,7 +24,7 @@ bb2: { _4 = discriminant((*_2)); - switchInt(move _4) -> [1: bb4, otherwise: bb3]; + switchInt(move _4) -> [1: bb4, 0: bb3, otherwise: bb6]; } bb3: { @@ -43,5 +43,9 @@ bb5: { return; } + + bb6: { + unreachable; + } } diff --git a/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff index c3ea975ce03..6a4c947b882 100644 --- a/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff @@ -12,13 +12,13 @@ bb0: { _3 = discriminant((*_1)); - switchInt(move _3) -> [1: bb1, otherwise: bb3]; + switchInt(move _3) -> [1: bb1, 0: bb3, otherwise: bb5]; } bb1: { _4 = deref_copy (((*_1) as Some).0: &E<'_>); _2 = discriminant((*_4)); - switchInt(move _2) -> [1: bb2, otherwise: bb3]; + switchInt(move _2) -> [1: bb2, 0: bb3, otherwise: bb5]; } bb2: { @@ -34,5 +34,9 @@ bb4: { return; } + + bb5: { + unreachable; + } } diff --git a/tests/mir-opt/early_otherwise_branch_soundness.rs b/tests/mir-opt/early_otherwise_branch_soundness.rs index b4f5821c420..74a2af884c0 100644 --- a/tests/mir-opt/early_otherwise_branch_soundness.rs +++ b/tests/mir-opt/early_otherwise_branch_soundness.rs @@ -1,5 +1,5 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching // Tests various cases that the `early_otherwise_branch` opt should *not* optimize @@ -11,12 +11,26 @@ enum E<'a> { // EMIT_MIR early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff fn no_downcast(e: &E) -> u32 { + // CHECK-LABEL: fn no_downcast( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } if let E::Some(E::Some(_)) = e { 1 } else { 2 } } // SAFETY: if `a` is `Some`, `b` must point to a valid, initialized value // EMIT_MIR early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 { + // CHECK-LABEL: fn no_deref_ptr( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match a { // `*b` being correct depends on `a == Some(_)` Some(_) => match *b { diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir index ae0dc9a0b6a..e8ad5cd8d16 100644 --- a/tests/mir-opt/issue_72181_1.main.built.after.mir +++ b/tests/mir-opt/issue_72181_1.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void -| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index c8039dc4735..0b0bac73e9f 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index c8039dc4735..0b0bac73e9f 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff new file mode 100644 index 00000000000..31ce51dc6de --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_i128_u128` before MatchBranchSimplification ++ // MIR for `match_i128_u128` after MatchBranchSimplification + + fn match_i128_u128(_1: EnumAi128) -> u128 { + debug i => _1; + let mut _0: u128; + let mut _2: i128; ++ let mut _3: i128; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [1: bb3, 2: bb4, 3: bb5, 340282366920938463463374607431768211455: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const core::num::<impl u128>::MAX; +- goto -> bb6; +- } +- +- bb3: { +- _0 = const 1_u128; +- goto -> bb6; +- } +- +- bb4: { +- _0 = const 2_u128; +- goto -> bb6; +- } +- +- bb5: { +- _0 = const 3_u128; +- goto -> bb6; +- } +- +- bb6: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u128 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff new file mode 100644 index 00000000000..e1b537b1b71 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_i16_i8` before MatchBranchSimplification ++ // MIR for `match_i16_i8` after MatchBranchSimplification + + fn match_i16_i8(_1: EnumAi16) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: i16; ++ let mut _3: i16; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [65535: bb3, 2: bb4, 65533: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const -3_i8; +- goto -> bb5; +- } +- +- bb3: { +- _0 = const -1_i8; +- goto -> bb5; +- } +- +- bb4: { +- _0 = const 2_i8; +- goto -> bb5; +- } +- +- bb5: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff new file mode 100644 index 00000000000..cabc5a44cd8 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_i8_i16` before MatchBranchSimplification ++ // MIR for `match_i8_i16` after MatchBranchSimplification + + fn match_i8_i16(_1: EnumAi8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: i8; ++ let mut _3: i8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const -3_i16; +- goto -> bb5; +- } +- +- bb3: { +- _0 = const -1_i16; +- goto -> bb5; +- } +- +- bb4: { +- _0 = const 2_i16; +- goto -> bb5; +- } +- +- bb5: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff new file mode 100644 index 00000000000..b0217792294 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff @@ -0,0 +1,37 @@ +- // MIR for `match_i8_i16_failed` before MatchBranchSimplification ++ // MIR for `match_i8_i16_failed` after MatchBranchSimplification + + fn match_i8_i16_failed(_1: EnumAi8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: i8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 3_i16; + goto -> bb5; + } + + bb3: { + _0 = const -1_i16; + goto -> bb5; + } + + bb4: { + _0 = const 2_i16; + goto -> bb5; + } + + bb5: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff new file mode 100644 index 00000000000..9ee01a87a91 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff @@ -0,0 +1,37 @@ +- // MIR for `match_u8_i16` before MatchBranchSimplification ++ // MIR for `match_u8_i16` after MatchBranchSimplification + + fn match_u8_i16(_1: EnumAu8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 2_i16; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 1_i16; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff new file mode 100644 index 00000000000..3333cd765a8 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff @@ -0,0 +1,26 @@ +- // MIR for `match_u8_i16_2` before MatchBranchSimplification ++ // MIR for `match_u8_i16_2` after MatchBranchSimplification + + fn match_u8_i16_2(_1: EnumAu8) -> i16 { + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(_2) -> [1: bb3, 2: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 2_i16; + goto -> bb3; + } + + bb2: { + unreachable; + } + + bb3: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff new file mode 100644 index 00000000000..6da19e46dab --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff @@ -0,0 +1,32 @@ +- // MIR for `match_u8_i16_failed` before MatchBranchSimplification ++ // MIR for `match_u8_i16_failed` after MatchBranchSimplification + + fn match_u8_i16_failed(_1: EnumAu8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 3_i16; + goto -> bb4; + } + + bb3: { + _0 = const 1_i16; + goto -> bb4; + } + + bb4: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff new file mode 100644 index 00000000000..8fa497fe890 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff @@ -0,0 +1,31 @@ +- // MIR for `match_u8_i16_fallback` before MatchBranchSimplification ++ // MIR for `match_u8_i16_fallback` after MatchBranchSimplification + + fn match_u8_i16_fallback(_1: u8) -> i16 { + debug i => _1; + let mut _0: i16; + + bb0: { + switchInt(_1) -> [1: bb2, 2: bb3, otherwise: bb1]; + } + + bb1: { + _0 = const 3_i16; + goto -> bb4; + } + + bb2: { + _0 = const 1_i16; + goto -> bb4; + } + + bb3: { + _0 = const 2_i16; + goto -> bb4; + } + + bb4: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff new file mode 100644 index 00000000000..aa9fcc60a3e --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_u8_u16` before MatchBranchSimplification ++ // MIR for `match_u8_u16` after MatchBranchSimplification + + fn match_u8_u16(_1: EnumBu8) -> u16 { + debug i => _1; + let mut _0: u16; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [1: bb3, 2: bb4, 5: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 5_u16; +- goto -> bb5; +- } +- +- bb3: { +- _0 = const 1_u16; +- goto -> bb5; +- } +- +- bb4: { +- _0 = const 2_u16; +- goto -> bb5; +- } +- +- bb5: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff new file mode 100644 index 00000000000..b47de6a52b7 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff @@ -0,0 +1,37 @@ +- // MIR for `match_u8_u16_2` before MatchBranchSimplification ++ // MIR for `match_u8_u16_2` after MatchBranchSimplification + + fn match_u8_u16_2(_1: EnumBu8) -> i16 { + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(_2) -> [1: bb1, 2: bb2, 5: bb3, otherwise: bb4]; + } + + bb1: { + _0 = const 1_i16; + goto -> bb5; + } + + bb2: { + _0 = const 2_i16; + goto -> bb5; + } + + bb3: { + _0 = const 5_i16; + _0 = const 5_i16; + goto -> bb5; + } + + bb4: { + unreachable; + } + + bb5: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index 4bf14e5a7bd..ca3e5f747d1 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -1,18 +1,28 @@ -// skip-filecheck //@ unit-test: MatchBranchSimplification +#![feature(repr128)] +#![feature(core_intrinsics)] +#![feature(custom_mir)] -// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff -// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff -// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff +use std::intrinsics::mir::*; +// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff fn foo(bar: Option<()>) { + // CHECK-LABEL: fn foo( + // CHECK: = Eq( + // CHECK: switchInt + // CHECK-NOT: switchInt if matches!(bar, None) { () } } +// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff fn bar(i: i32) -> (bool, bool, bool, bool) { + // CHECK-LABEL: fn bar( + // CHECK: = Ne( + // CHECK: = Eq( + // CHECK-NOT: switchInt let a; let b; let c; @@ -38,7 +48,10 @@ fn bar(i: i32) -> (bool, bool, bool, bool) { (a, b, c, d) } +// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff fn match_nested_if() -> bool { + // CHECK-LABEL: fn match_nested_if( + // CHECK-NOT: switchInt let val = match () { () if if if if true { true } else { false } { true } else { false } { true @@ -53,9 +66,221 @@ fn match_nested_if() -> bool { val } +#[repr(u8)] +enum EnumAu8 { + A = 1, + B = 2, +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff +fn match_u8_i16(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_u8_i16( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as i16 (IntToInt); + // CHECH: return + match i { + EnumAu8::A => 1, + EnumAu8::B => 2, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff +// Check for different instruction lengths +#[custom_mir(dialect = "built")] +fn match_u8_i16_2(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_u8_i16_2( + // CHECK: switchInt + mir!( + { + let a = Discriminant(i); + match a { + 1 => bb1, + 2 => bb2, + _ => unreachable_bb, + } + } + bb1 = { + Goto(ret) + } + bb2 = { + RET = 2; + Goto(ret) + } + unreachable_bb = { + Unreachable() + } + ret = { + Return() + } + ) +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff +fn match_u8_i16_failed(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_u8_i16_failed( + // CHECK: switchInt + match i { + EnumAu8::A => 1, + EnumAu8::B => 3, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff +fn match_u8_i16_fallback(i: u8) -> i16 { + // CHECK-LABEL: fn match_u8_i16_fallback( + // CHECK: switchInt + match i { + 1 => 1, + 2 => 2, + _ => 3, + } +} + +#[repr(u8)] +enum EnumBu8 { + A = 1, + B = 2, + C = 5, +} + +// EMIT_MIR matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff +fn match_u8_u16(i: EnumBu8) -> u16 { + // CHECK-LABEL: fn match_u8_u16( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as u16 (IntToInt); + // CHECH: return + match i { + EnumBu8::A => 1, + EnumBu8::B => 2, + EnumBu8::C => 5, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff +// Check for different instruction lengths +#[custom_mir(dialect = "built")] +fn match_u8_u16_2(i: EnumBu8) -> i16 { + // CHECK-LABEL: fn match_u8_u16_2( + // CHECK: switchInt + mir!( + { + let a = Discriminant(i); + match a { + 1 => bb1, + 2 => bb2, + 5 => bb5, + _ => unreachable_bb, + } + } + bb1 = { + RET = 1; + Goto(ret) + } + bb2 = { + RET = 2; + Goto(ret) + } + bb5 = { + RET = 5; + RET = 5; + Goto(ret) + } + unreachable_bb = { + Unreachable() + } + ret = { + Return() + } + ) +} + +#[repr(i8)] +enum EnumAi8 { + A = -1, + B = 2, + C = -3, +} + +// EMIT_MIR matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff +fn match_i8_i16(i: EnumAi8) -> i16 { + // CHECK-LABEL: fn match_i8_i16( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as i16 (IntToInt); + // CHECH: return + match i { + EnumAi8::A => -1, + EnumAi8::B => 2, + EnumAi8::C => -3, + } +} + +// EMIT_MIR matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff +fn match_i8_i16_failed(i: EnumAi8) -> i16 { + // CHECK-LABEL: fn match_i8_i16_failed( + // CHECK: switchInt + match i { + EnumAi8::A => -1, + EnumAi8::B => 2, + EnumAi8::C => 3, + } +} + +#[repr(i16)] +enum EnumAi16 { + A = -1, + B = 2, + C = -3, +} + +// EMIT_MIR matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff +fn match_i16_i8(i: EnumAi16) -> i8 { + // CHECK-LABEL: fn match_i16_i8( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as i8 (IntToInt); + // CHECH: return + match i { + EnumAi16::A => -1, + EnumAi16::B => 2, + EnumAi16::C => -3, + } +} + +#[repr(i128)] +enum EnumAi128 { + A = 1, + B = 2, + C = 3, + D = -1, +} + +// EMIT_MIR matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff +fn match_i128_u128(i: EnumAi128) -> u128 { + // CHECK-LABEL: fn match_i128_u128( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as u128 (IntToInt); + // CHECH: return + match i { + EnumAi128::A => 1, + EnumAi128::B => 2, + EnumAi128::C => 3, + EnumAi128::D => u128::MAX, + } +} + fn main() { let _ = foo(None); let _ = foo(Some(())); let _ = bar(0); let _ = match_nested_if(); + let _ = match_u8_i16(EnumAu8::A); + let _ = match_u8_i16_2(EnumAu8::A); + let _ = match_u8_i16_failed(EnumAu8::A); + let _ = match_u8_i16_fallback(1); + let _ = match_u8_u16(EnumBu8::A); + let _ = match_u8_u16_2(EnumBu8::A); + let _ = match_i8_i16(EnumAi8::A); + let _ = match_i8_i16_failed(EnumAi8::A); + let _ = match_i8_i16(EnumAi8::A); + let _ = match_i16_i8(EnumAi16::A); + let _ = match_i128_u128(EnumAi128::A); } diff --git a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff index 157f9c98353..11a18f58e3a 100644 --- a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff @@ -5,27 +5,32 @@ debug e => _1; let mut _0: u8; let mut _2: isize; ++ let mut _3: isize; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 1_u8; - goto -> bb4; - } - - bb3: { - _0 = const 0_u8; - goto -> bb4; - } - - bb4: { +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 1_u8; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 0_u8; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u8 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff index 19083771fd9..809badc41ba 100644 --- a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff @@ -5,27 +5,32 @@ debug e => _1; let mut _0: i8; let mut _2: isize; ++ let mut _3: isize; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 1_i8; - goto -> bb4; - } - - bb3: { - _0 = const 0_i8; - goto -> bb4; - } - - bb4: { +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 1_i8; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 0_i8; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/run-make/artifact-incr-cache/lib.rs b/tests/run-make/artifact-incr-cache/lib.rs new file mode 100644 index 00000000000..fa4048594e3 --- /dev/null +++ b/tests/run-make/artifact-incr-cache/lib.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +#[inline(never)] +pub fn add(a: u32, b: u32) -> u32 { + a + b +} diff --git a/tests/run-make/artifact-incr-cache/rmake.rs b/tests/run-make/artifact-incr-cache/rmake.rs new file mode 100644 index 00000000000..bb651368081 --- /dev/null +++ b/tests/run-make/artifact-incr-cache/rmake.rs @@ -0,0 +1,25 @@ +// rustc should be able to emit required files (asm, llvm-*, etc) during incremental +// compilation on the first pass by running the code gen as well as on subsequent runs - +// extracting them from the cache +// +// Fixes: rust-lang/rust#89149 +// Fixes: rust-lang/rust#88829 +// Also see discussion at +// <https://internals.rust-lang.org/t/interaction-between-incremental-compilation-and-emit/20551> + +extern crate run_make_support; + +use run_make_support::{rustc, tmp_dir}; + +fn main() { + let inc_dir = tmp_dir(); + + for _ in 0..=1 { + rustc() + .input("lib.rs") + .crate_type("lib") + .emit("obj,asm,dep-info,link,mir,llvm-ir,llvm-bc") + .incremental(&inc_dir) + .run(); + } +} diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index e5939470b46..92d6895143c 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -22,6 +22,7 @@ use run_make_support::object::read::Object; use run_make_support::object::ObjectSection; use run_make_support::object::ObjectSymbol; use run_make_support::object::RelocationTarget; +use run_make_support::set_host_rpath; use run_make_support::tmp_dir; use std::collections::HashSet; @@ -48,8 +49,8 @@ fn main() { let path = std::env::var("PATH").unwrap(); let rustc = std::env::var("RUSTC").unwrap(); let bootstrap_cargo = std::env::var("BOOTSTRAP_CARGO").unwrap(); - let status = std::process::Command::new(bootstrap_cargo) - .args([ + let mut cmd = std::process::Command::new(bootstrap_cargo); + cmd.args([ "build", "--manifest-path", manifest_path.to_str().unwrap(), @@ -62,10 +63,10 @@ fn main() { .env("RUSTC", rustc) .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes") .env("CARGO_TARGET_DIR", &target_dir) - .env("RUSTC_BOOTSTRAP", "1") - .status() - .unwrap(); + .env("RUSTC_BOOTSTRAP", "1"); + set_host_rpath(&mut cmd); + let status = cmd.status().unwrap(); assert!(status.success()); let rlibs_path = target_dir.join(target).join("debug").join("deps"); diff --git a/tests/run-make/cross-lang-lto-riscv-abi/cstart.c b/tests/run-make/cross-lang-lto-riscv-abi/cstart.c new file mode 100644 index 00000000000..660469b75a8 --- /dev/null +++ b/tests/run-make/cross-lang-lto-riscv-abi/cstart.c @@ -0,0 +1,5 @@ +extern void hello(); + +void _start() { + hello(); +} diff --git a/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs new file mode 100644 index 00000000000..c31cf27f9ae --- /dev/null +++ b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs @@ -0,0 +1,9 @@ +#![allow(internal_features)] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn hello() {} diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs new file mode 100644 index 00000000000..2f13cf17169 --- /dev/null +++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs @@ -0,0 +1,74 @@ +//! Make sure that cross-language LTO works on riscv targets, +//! which requires extra abi metadata to be emitted. +//@ needs-matching-clang +//@ needs-llvm-components riscv +extern crate run_make_support; + +use run_make_support::{bin_name, rustc, tmp_dir}; +use std::{ + env, + path::PathBuf, + process::{Command, Output}, + str, +}; + +fn handle_failed_output(output: Output) { + eprintln!("output status: `{}`", output.status); + eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap()); + eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); + std::process::exit(1) +} + +fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) { + eprintln!("Checking target {target}"); + // Rust part + rustc() + .input("riscv-xlto.rs") + .crate_type("rlib") + .target(target) + .panic("abort") + .linker_plugin_lto("on") + .run(); + // C part + let clang = env::var("CLANG").unwrap(); + let mut cmd = Command::new(clang); + let executable = tmp_dir().join("riscv-xlto"); + cmd.arg("-target") + .arg(clang_target) + .arg(format!("-march={carch}")) + .arg(format!("-flto=thin")) + .arg(format!("-fuse-ld=lld")) + .arg("-nostdlib") + .arg("-o") + .arg(&executable) + .arg("cstart.c") + .arg(tmp_dir().join("libriscv_xlto.rlib")); + eprintln!("{cmd:?}"); + let output = cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(output); + } + // Check that the built binary has correct float abi + let llvm_readobj = + PathBuf::from(env::var("LLVM_BIN_DIR").unwrap()).join(bin_name("llvm-readobj")); + let mut cmd = Command::new(llvm_readobj); + cmd.arg("--file-header").arg(executable); + eprintln!("{cmd:?}"); + let output = cmd.output().unwrap(); + if output.status.success() { + assert!( + !(is_double_float + ^ dbg!(str::from_utf8(&output.stdout).unwrap()) + .contains("EF_RISCV_FLOAT_ABI_DOUBLE")) + ) + } else { + handle_failed_output(output); + } +} + +fn main() { + check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true); + check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false); + check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false); + check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true); +} diff --git a/tests/run-make/exit-code/Makefile b/tests/run-make/exit-code/Makefile deleted file mode 100644 index 155e5cd1123..00000000000 --- a/tests/run-make/exit-code/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) success.rs; [ $$? -eq 0 ] - $(RUSTC) --invalid-arg-foo; [ $$? -eq 1 ] - $(RUSTC) compile-error.rs; [ $$? -eq 1 ] - RUSTC_ICE=0 $(RUSTC) -Ztreat-err-as-bug compile-error.rs; [ $$? -eq 101 ] - $(RUSTDOC) -o $(TMPDIR)/exit-code success.rs; [ $$? -eq 0 ] - $(RUSTDOC) --invalid-arg-foo; [ $$? -eq 1 ] - $(RUSTDOC) compile-error.rs; [ $$? -eq 1 ] - $(RUSTDOC) lint-failure.rs; [ $$? -eq 1 ] diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs new file mode 100644 index 00000000000..f387626287e --- /dev/null +++ b/tests/run-make/exit-code/rmake.rs @@ -0,0 +1,43 @@ +// Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations + +extern crate run_make_support; + +use run_make_support::{rustc, rustdoc, tmp_dir}; + +fn main() { + rustc() + .arg("success.rs") + .run(); + + rustc() + .arg("--invalid-arg-foo") + .run_fail_assert_exit_code(1); + + rustc() + .arg("compile-error.rs") + .run_fail_assert_exit_code(1); + + rustc() + .env("RUSTC_ICE", "0") + .arg("-Ztreat-err-as-bug") + .arg("compile-error.rs") + .run_fail_assert_exit_code(101); + + rustdoc() + .arg("success.rs") + .arg("-o") + .arg(tmp_dir().join("exit-code")) + .run(); + + rustdoc() + .arg("--invalid-arg-foo") + .run_fail_assert_exit_code(1); + + rustdoc() + .arg("compile-error.rs") + .run_fail_assert_exit_code(1); + + rustdoc() + .arg("lint-failure.rs") + .run_fail_assert_exit_code(1); +} diff --git a/tests/run-make/rust-lld/Makefile b/tests/run-make/rust-lld/Makefile index f8526530d4d..1ecac479f41 100644 --- a/tests/run-make/rust-lld/Makefile +++ b/tests/run-make/rust-lld/Makefile @@ -4,5 +4,9 @@ include ../tools.mk # needs-rust-lld # ignore-s390x lld does not yet support s390x as target all: - RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Clinker-flavor=gnu-lld-cc -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt + RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Zlinker-features=+lld -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt + $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt + + # while we're here, also check that the last linker feature flag "wins" + RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Clink-self-contained=+linker -Zlinker-features=-lld -Zlinker-features=+lld -Zunstable-options -Clink-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt diff --git a/tests/run-make/version/Makefile b/tests/run-make/version/Makefile deleted file mode 100644 index 3a130545d69..00000000000 --- a/tests/run-make/version/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) -V - $(RUSTC) -vV - $(RUSTC) --version --verbose diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index fc80932caba..348ce0c992f 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -2,23 +2,25 @@ include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" -// Otherwise, we can't check text color -show-text: true - // We check that without this setting, there is no line number displayed. assert-false: "pre.example-line-numbers" +// We set the setting to show the line numbers on code examples. +set-local-storage: {"rustdoc-line-numbers": "true"} +reload: +// We wait for the line numbers to be added into the DOM by the JS... +wait-for: "pre.example-line-numbers" + +// Otherwise, we can't check text color +show-text: true + // Let's now check some CSS properties... define-function: ( "check-colors", [theme, color], block { - // We now set the setting to show the line numbers on code examples. - set-local-storage: {"rustdoc-line-numbers": "true"} // Page will be reloaded in "switch-theme". call-function: ("switch-theme", {"theme": |theme|}) - // We wait for the line numbers to be added into the DOM by the JS... - wait-for: "pre.example-line-numbers" // If the test didn't fail, it means that it was found! assert-css: ( "pre.example-line-numbers", diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml index a9d37048188..441895a7c0e 100644 --- a/tests/rustdoc-gui/scrape-examples-toggle.goml +++ b/tests/rustdoc-gui/scrape-examples-toggle.goml @@ -9,6 +9,7 @@ define-function: ( [theme, toggle_line_color, toggle_line_hover_color], block { call-function: ("switch-theme", {"theme": |theme|}) + reload: // Clicking "More examples..." will open additional examples assert-attribute-false: (".more-examples-toggle", {"open": ""}) @@ -21,6 +22,8 @@ define-function: ( ".toggle-line:hover .toggle-line-inner", {"background-color": |toggle_line_hover_color|}, ) + // We put the toggle in the original state. + click: ".more-examples-toggle" // Moving cursor away from the toggle line to prevent disrupting next test. move-cursor-to: ".search-input" }, diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index d4da23fa156..9825f92b453 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -1,6 +1,108 @@ // The goal of this test is to ensure the color of the text is the one expected. include: "utils.goml" + +define-function: ( + "check-search-color", + [ + theme, count_color, desc_color, path_color, bottom_border_color, keyword_color, + struct_color, associatedtype_color, tymethod_color, method_color, structfield_color, + structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background, grey + ], + block { + call-function: ("switch-theme", {"theme": |theme|}) + + // Waiting for the search results to appear... + wait-for: "#search-tabs" + assert-css: ( + "#search-tabs > button > .count", + {"color": |count_color|}, + ALL, + ) + assert-css: ( + "//*[@class='desc'][text()='Just a normal struct.']", + {"color": |desc_color|}, + ) + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']", + {"color": |path_color|}, + ) + + // Checking the color of the bottom border. + assert-css: ( + ".search-results > a", + {"border-bottom-color": |bottom_border_color|} + ) + + store-value: (entry_color, |path_color|) // color of the search entry + store-value: (hover_entry_color, |hover_path_color|) // color of the hovered/focused search entry + store-value: (background_color, "transparent") + store-value: (hover_background_color, |hover_background|) + store-value: (grey, |grey|) + + call-function: ("check-result-color", { + "result_kind": "keyword", + "color": |keyword_color|, + "hover_color": |keyword_color|, + }) + call-function: ("check-result-color", { + "result_kind": "struct", + "color": |struct_color|, + "hover_color": |struct_color|, + }) + call-function: ("check-result-color", { + "result_kind": "associatedtype", + "color": |associatedtype_color|, + "hover_color": |associatedtype_color|, + }) + call-function: ("check-result-color", { + "result_kind": "tymethod", + "color": |tymethod_color|, + "hover_color": |tymethod_color|, + }) + call-function: ("check-result-color", { + "result_kind": "method", + "color": |method_color|, + "hover_color": |method_color|, + }) + call-function: ("check-result-color", { + "result_kind": "structfield", + "color": |structfield_color|, + "hover_color": |structfield_hover_color|, + }) + call-function: ("check-result-color", { + "result_kind": "macro", + "color": |macro_color|, + "hover_color": |macro_color|, + }) + call-function: ("check-result-color", { + "result_kind": "fn", + "color": |fn_color|, + "hover_color": |fn_color|, + }) + + // Checking the `<a>` container. + move-cursor-to: ".search-input" + focus: ".search-input" // To ensure the `<a>` container isn't focused or hovered. + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", + {"color": |path_color|, "background-color": "transparent"}, + ALL, + ) + + // Checking color and background on hover. + move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']" + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']", + {"color": |hover_path_color|}, + ) + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", + {"color": |hover_path_color|, "background-color": |hover_background|}, + ) + } +) + define-function: ( "check-result-color", [result_kind, color, hover_color], @@ -44,325 +146,85 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo" show-text: true // Ayu theme -call-function: ("switch-theme", {"theme": "ayu"}) - -// Waiting for the search results to appear... -wait-for: "#search-tabs" -assert-css: ( - "#search-tabs > button > .count", - {"color": "#888"}, - ALL, -) -assert-css: ( - "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "#c5c5c5"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#0096cf"}, -) - -// Checking the color of the bottom border. -assert-css: ( - ".search-results > a", - {"border-bottom-color": "#aaa3"} -) - -store-value: (entry_color, "#0096cf") // color of the search entry -store-value: (hover_entry_color, "#fff") // color of the hovered/focused search entry -store-value: (background_color, "transparent") // background color -store-value: (hover_background_color, "#3c3c3c") // hover background color -store-value: (grey, "#999") - -call-function: ( - "check-result-color", { - "result_kind": "keyword", - "color": "#39afd7", - "hover_color": "#39afd7", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "struct", - "color": "#ffa0a5", - "hover_color": "#ffa0a5", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "associatedtype", - "color": "#39afd7", - "hover_color": "#39afd7", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "tymethod", - "color": "#fdd687", - "hover_color": "#fdd687", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "method", - "color": "#fdd687", - "hover_color": "#fdd687", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "structfield", - "color": "#0096cf", - "hover_color": "#fff", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "macro", - "color": "#a37acc", - "hover_color": "#a37acc", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "fn", - "color": "#fdd687", - "hover_color": "#fdd687", - }, -) - -// Checking the `<a>` container. -move-cursor-to: ".search-input" -focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#0096cf", "background-color": "transparent"}, - ALL, -) - -// Checking color and background on hover. -move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']" -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#fff"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#fff", "background-color": "#3c3c3c"}, -) +call-function: ("check-search-color", { + "theme": "ayu", + "count_color": "#888", + "desc_color": "#c5c5c5", + "path_color": "#0096cf", + "bottom_border_color": "#aaa3", + "keyword_color": "#39afd7", + "struct_color": "#ffa0a5", + "associatedtype_color": "#39afd7", + "tymethod_color": "#fdd687", + "method_color": "#fdd687", + "structfield_color": "#0096cf", + "structfield_hover_color": "#fff", + "macro_color": "#a37acc", + "fn_color": "#fdd687", + "hover_path_color": "#fff", + "hover_background": "#3c3c3c", + "grey": "#999", +}) // Dark theme -call-function: ("switch-theme", {"theme": "dark"}) - -// Waiting for the search results to appear... -wait-for: "#search-tabs" -assert-css: ( - "#search-tabs > button > .count", - {"color": "#888"}, - ALL, -) -assert-css: ( - "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "#ddd"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#ddd"}, -) - -// Checking the color of the bottom border. -assert-css: ( - ".search-results > a", - {"border-bottom-color": "#aaa3"} -) - -store-value: (entry_color, "#ddd") // color of the search entry -store-value: (hover_entry_color, "#ddd") // color of the hovered/focused search entry -store-value: (background_color, "transparent") // background color -store-value: (hover_background_color, "#616161") // hover background color -store-value: (grey, "#ccc") - -call-function: ( - "check-result-color", { - "result_kind": "keyword", - "color": "#d2991d", - "hover_color": "#d2991d", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "struct", - "color": "#2dbfb8", - "hover_color": "#2dbfb8", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "associatedtype", - "color": "#d2991d", - "hover_color": "#d2991d", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "tymethod", - "color": "#2bab63", - "hover_color": "#2bab63", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "method", - "color": "#2bab63", - "hover_color": "#2bab63", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "structfield", - "color": "#ddd", - "hover_color": "#ddd", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "macro", - "color": "#09bd00", - "hover_color": "#09bd00", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "fn", - "color": "#2bab63", - "hover_color": "#2bab63", - }, -) - -// Checking the `<a>` container. -move-cursor-to: ".search-input" -focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#ddd", "background-color": "transparent"}, -) +call-function: ("check-search-color", { + "theme": "dark", + "count_color": "#888", + "desc_color": "#ddd", + "path_color": "#ddd", + "bottom_border_color": "#aaa3", + "keyword_color": "#d2991d", + "struct_color": "#2dbfb8", + "associatedtype_color": "#d2991d", + "tymethod_color": "#2bab63", + "method_color": "#2bab63", + "structfield_color": "#ddd", + "structfield_hover_color": "#ddd", + "macro_color": "#09bd00", + "fn_color": "#2bab63", + "hover_path_color": "#ddd", + "hover_background": "#616161", + "grey": "#ccc", +}) // Light theme -call-function: ("switch-theme", {"theme": "light"}) - -// Waiting for the search results to appear... -wait-for: "#search-tabs" -assert-css: ( - "#search-tabs > button > .count", - {"color": "#888"}, - ALL, -) -assert-css: ( - "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "#000"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#000"}, -) - -// Checking the color of the bottom border. -assert-css: ( - ".search-results > a", - {"border-bottom-color": "#aaa3"} -) - -store-value: (entry_color, "#000") // color of the search entry -store-value: (hover_entry_color, "#000") // color of the hovered/focused search entry -store-value: (background_color, "transparent") // background color -store-value: (hover_background_color, "#ccc") // hover background color -store-value: (grey, "#999") - -call-function: ( - "check-result-color", { - "result_kind": "keyword", - "color": "#3873ad", - "hover_color": "#3873ad", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "struct", - "color": "#ad378a", - "hover_color": "#ad378a", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "associatedtype", - "color": "#3873ad", - "hover_color": "#3873ad", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "tymethod", - "color": "#ad7c37", - "hover_color": "#ad7c37", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "method", - "color": "#ad7c37", - "hover_color": "#ad7c37", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "structfield", - "color": "#000", - "hover_color": "#000", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "macro", - "color": "#068000", - "hover_color": "#068000", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "fn", - "color": "#ad7c37", - "hover_color": "#ad7c37", - }, -) - -// Checking the `<a>` container. -move-cursor-to: ".search-input" -focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#000", "background-color": "transparent"}, -) +call-function: ("check-search-color", { + "theme": "light", + "count_color": "#888", + "desc_color": "#000", + "path_color": "#000", + "bottom_border_color": "#aaa3", + "keyword_color": "#3873ad", + "struct_color": "#ad378a", + "associatedtype_color": "#3873ad", + "tymethod_color": "#ad7c37", + "method_color": "#ad7c37", + "structfield_color": "#000", + "structfield_hover_color": "#000", + "macro_color": "#068000", + "fn_color": "#ad7c37", + "hover_path_color": "#000", + "hover_background": "#ccc", + "grey": "#999", +}) // Check the alias. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -// If the text isn't displayed, the browser doesn't compute color style correctly... -show-text: true + +write-into: (".search-input", "thisisanalias") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#search-tabs" define-function: ( "check-alias", [theme, alias, grey], block { call-function: ("switch-theme", {"theme": |theme|}) - write-into: (".search-input", "thisisanalias") - // To be SURE that the search will be run. - press-key: 'Enter' - // Waiting for the search results to appear... - wait-for: "#search-tabs" // Checking that the colors for the alias element are the ones expected. assert-css: (".result-name .path .alias", {"color": |alias|}) assert-css: (".result-name .path .alias > .grey", {"color": |grey|}) - // Leave the search results to prevent reloading with an already filled search input. - press-key: "Escape" }, ) diff --git a/tests/rustdoc-gui/search-result-go-to-first.goml b/tests/rustdoc-gui/search-result-go-to-first.goml index a0bc2bb16ba..f4cfe096386 100644 --- a/tests/rustdoc-gui/search-result-go-to-first.goml +++ b/tests/rustdoc-gui/search-result-go-to-first.goml @@ -3,17 +3,17 @@ // First, we check that the first page doesn't have the string we're looking for to ensure // that the feature is changing page as expected. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -assert-text-false: (".main-heading h1", "Struct test_docs::Foo") +assert-text-false: (".main-heading h1", "Struct test_docs::FooCopy item path") // We now check that we land on the search result page if "go_to_first" isn't set. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo" // Waiting for the search results to appear... wait-for: "#search-tabs" -assert-text-false: (".main-heading h1", "Struct test_docs::Foo") +assert-text-false: (".main-heading h1", "Struct test_docs::FooCopy item path") // Ensure that the search results are displayed, not the "normal" content. assert-css: ("#main-content", {"display": "none"}) // Now we can check that the feature is working as expected! go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true" // Waiting for the page to load... -wait-for-text: (".main-heading h1", "Struct test_docs::Foo") +wait-for-text: (".main-heading h1", "Struct test_docs::FooCopy item path") diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 56d0f8624e8..0011e44ca59 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -36,7 +36,12 @@ wait-for: "#alternative-display #search" assert: "#main-content.hidden" // Now let's check the content of the settings menu. -call-function: ("switch-theme", {"theme": "dark"}) +// If we are on the settings page, the menu doesn't work the same so we set +// the theme manually. +set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + click: "#settings-menu" wait-for: "#settings" diff --git a/tests/rustdoc-gui/toggle-click-deadspace.goml b/tests/rustdoc-gui/toggle-click-deadspace.goml index f115f63ab6b..37bc3f7c372 100644 --- a/tests/rustdoc-gui/toggle-click-deadspace.goml +++ b/tests/rustdoc-gui/toggle-click-deadspace.goml @@ -12,4 +12,4 @@ assert-attribute-false: (".impl-items .toggle", {"open": ""}) // Click the "Trait" part of "impl Trait" and verify it navigates. click: "#impl-Trait-for-Foo h3 a:first-of-type" -assert-text: (".main-heading h1", "Trait lib2::Trait") +assert-text: (".main-heading h1", "Trait lib2::TraitCopy item path") diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml index d9f8726ec53..844dc98a537 100644 --- a/tests/rustdoc-gui/utils.goml +++ b/tests/rustdoc-gui/utils.goml @@ -4,8 +4,15 @@ define-function: ( [theme], block { // Set the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + // Open the settings menu. + click: "#settings-menu" + // Wait for the popover to appear... + wait-for: "#settings" + // Change the setting. + click: "#theme-"+ |theme| + // Close the popover. + click: "#settings-menu" + // Ensure that the local storage was correctly updated. + assert-local-storage: {"rustdoc-theme": |theme|} }, ) diff --git a/tests/rustdoc-ui/auxiliary/include-str-bare-urls.md b/tests/rustdoc-ui/auxiliary/include-str-bare-urls.md new file mode 100644 index 00000000000..b07717d8f02 --- /dev/null +++ b/tests/rustdoc-ui/auxiliary/include-str-bare-urls.md @@ -0,0 +1,10 @@ +HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE! + +Normally, a line with errors on it will also have a comment +marking it up as something that needs to generate an error. + +The test harness doesn't gather hot comments from this file. +Rustdoc will generate an error for the line, and the `.stderr` +snapshot includes this error, but Compiletest doesn't see it. + +If the stderr file changes, make sure the warning points at the URL! diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr index 06a52691310..66622a7654c 100644 --- a/tests/rustdoc-ui/ice-bug-report-url.stderr +++ b/tests/rustdoc-ui/ice-bug-report-url.stderr @@ -12,6 +12,8 @@ error: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md +note: please make sure that you have updated to the latest nightly + note: rustc {version} running on {platform} query stack during panic: diff --git a/tests/rustdoc-ui/include-str-bare-urls.rs b/tests/rustdoc-ui/include-str-bare-urls.rs new file mode 100644 index 00000000000..c452c88cdd3 --- /dev/null +++ b/tests/rustdoc-ui/include-str-bare-urls.rs @@ -0,0 +1,15 @@ +// https://github.com/rust-lang/rust/issues/118549 +// +// HEADS UP! +// +// Normally, a line with errors on it will also have a comment +// marking it up as something that needs to generate an error. +// +// The test harness doesn't gather hot comments from the `.md` file. +// Rustdoc will generate an error for the line, and the `.stderr` +// snapshot includes this error, but Compiletest doesn't see it. +// +// If the stderr file changes, make sure the warning points at the URL! + +#![deny(rustdoc::bare_urls)] +#![doc=include_str!("auxiliary/include-str-bare-urls.md")] diff --git a/tests/rustdoc-ui/include-str-bare-urls.stderr b/tests/rustdoc-ui/include-str-bare-urls.stderr new file mode 100644 index 00000000000..a4234196b23 --- /dev/null +++ b/tests/rustdoc-ui/include-str-bare-urls.stderr @@ -0,0 +1,15 @@ +error: this URL is not a hyperlink + --> $DIR/auxiliary/include-str-bare-urls.md:1:11 + | +LL | HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE! + | ^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com>` + | + = note: bare URLs are not automatically turned into clickable links +note: the lint level is defined here + --> $DIR/include-str-bare-urls.rs:14:9 + | +LL | #![deny(rustdoc::bare_urls)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/intra-doc/warning.rs b/tests/rustdoc-ui/intra-doc/warning.rs index 96b5c2b36a1..ed51b2fa41b 100644 --- a/tests/rustdoc-ui/intra-doc/warning.rs +++ b/tests/rustdoc-ui/intra-doc/warning.rs @@ -47,11 +47,11 @@ pub fn d() {} macro_rules! f { ($f:expr) => { - #[doc = $f] //~ WARNING `BarF` + #[doc = $f] pub fn f() {} } } -f!("Foo\nbar [BarF] bar\nbaz"); +f!("Foo\nbar [BarF] bar\nbaz"); //~ WARNING `BarF` /** # for example, * diff --git a/tests/rustdoc-ui/intra-doc/warning.stderr b/tests/rustdoc-ui/intra-doc/warning.stderr index 19399a0df5b..3a06f1787e0 100644 --- a/tests/rustdoc-ui/intra-doc/warning.stderr +++ b/tests/rustdoc-ui/intra-doc/warning.stderr @@ -69,10 +69,10 @@ LL | bar [BarC] bar = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarD` - --> $DIR/warning.rs:45:1 + --> $DIR/warning.rs:45:9 | LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -82,13 +82,10 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` - --> $DIR/warning.rs:50:9 + --> $DIR/warning.rs:54:4 | -LL | #[doc = $f] - | ^^^^^^^^^^^ -... LL | f!("Foo\nbar [BarF] bar\nbaz"); - | ------------------------------ in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -115,10 +112,10 @@ LL | * time to introduce a link [error] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/warning.rs:68:1 + --> $DIR/warning.rs:68:9 | LL | #[doc = "single line [error]"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -128,10 +125,10 @@ LL | #[doc = "single line [error]"] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/warning.rs:71:1 + --> $DIR/warning.rs:71:9 | LL | #[doc = "single line with \"escaping\" [error]"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: diff --git a/tests/rustdoc-ui/invalid-syntax.stderr b/tests/rustdoc-ui/invalid-syntax.stderr index 6140a06c555..46d7cdb4f7e 100644 --- a/tests/rustdoc-ui/invalid-syntax.stderr +++ b/tests/rustdoc-ui/invalid-syntax.stderr @@ -90,12 +90,13 @@ LL | | /// ``` = note: error from rustc: unknown start of token: \ warning: could not parse code block as Rust code - --> $DIR/invalid-syntax.rs:70:1 + --> $DIR/invalid-syntax.rs:70:9 | -LL | / #[doc = "```"] +LL | #[doc = "```"] + | _________^ LL | | /// \_ LL | | #[doc = "```"] - | |______________^ + | |_____________^ | = help: mark blocks that do not contain Rust code as text: ```text = note: error from rustc: unknown start of token: \ diff --git a/tests/rustdoc-ui/redundant-explicit-links-123677.rs b/tests/rustdoc-ui/redundant-explicit-links-123677.rs new file mode 100644 index 00000000000..f3a5e81f89d --- /dev/null +++ b/tests/rustdoc-ui/redundant-explicit-links-123677.rs @@ -0,0 +1,14 @@ +//@ check-pass +#![deny(rustdoc::redundant_explicit_links)] + +mod bar { + /// [`Rc`](std::rc::Rc) + pub enum Baz {} +} + +pub use bar::*; + +use std::rc::Rc; + +/// [`Rc::allocator`] [foo](std::rc::Rc) +pub fn winit_runner() {} diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr index 000a5b597d2..67b87f353a1 100644 --- a/tests/rustdoc-ui/unescaped_backticks.stderr +++ b/tests/rustdoc-ui/unescaped_backticks.stderr @@ -640,10 +640,10 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:108:1 + --> $DIR/unescaped_backticks.rs:108:9 | LL | #[doc = "`"] - | ^^^^^^^^^^^^ + | ^^^ | = help: the opening or closing backtick of an inline code may be missing = help: if you meant to use a literal backtick, escape it @@ -651,10 +651,10 @@ LL | #[doc = "`"] to this: \` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:115:1 + --> $DIR/unescaped_backticks.rs:115:9 | LL | #[doc = concat!("\\", "`")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = help: the opening backtick of an inline code may be missing change: \` @@ -664,10 +664,10 @@ LL | #[doc = concat!("\\", "`")] to this: \\` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:119:1 + --> $DIR/unescaped_backticks.rs:119:9 | LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: the opening backtick of a previous inline code may be missing change: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`. @@ -677,10 +677,10 @@ LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same a to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:123:1 + --> $DIR/unescaped_backticks.rs:123:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: a previous inline code might be longer than expected change: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`. @@ -690,10 +690,10 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same a to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:127:1 + --> $DIR/unescaped_backticks.rs:127:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: the opening backtick of an inline code may be missing change: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`. @@ -703,10 +703,10 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:131:1 + --> $DIR/unescaped_backticks.rs:131:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: the closing backtick of an inline code may be missing change: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a). diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs index ec06f2f0c5d..2a3dd72749c 100644 --- a/tests/rustdoc/inline_cross/inline_hidden.rs +++ b/tests/rustdoc/inline_cross/inline_hidden.rs @@ -4,9 +4,23 @@ extern crate rustdoc_hidden; +// @has inline_hidden/index.html +// Ensures this item is not inlined. +// @has - '//*[@id="reexport.Foo"]/code' 'pub use rustdoc_hidden::Foo;' #[doc(no_inline)] pub use rustdoc_hidden::Foo; +// Even if the foreign item has `doc(hidden)`, we should be able to inline it. +// @has - '//*[@class="item-name"]/a[@class="struct"]' 'Inlined' +#[doc(inline)] +pub use rustdoc_hidden::Foo as Inlined; + +// Even with this import, we should not see `Foo`. +// @count - '//*[@class="item-name"]' 4 +// @has - '//*[@class="item-name"]/a[@class="struct"]' 'Bar' +// @has - '//*[@class="item-name"]/a[@class="fn"]' 'foo' +pub use rustdoc_hidden::*; + // @has inline_hidden/fn.foo.html // @!has - '//a/@title' 'Foo' pub fn foo(_: Foo) {} diff --git a/tests/rustdoc/primitive/primitive.rs b/tests/rustdoc/primitive/primitive.rs index 32af2636c18..4b89fd9dfb7 100644 --- a/tests/rustdoc/primitive/primitive.rs +++ b/tests/rustdoc/primitive/primitive.rs @@ -1,6 +1,8 @@ #![crate_name = "foo"] #![feature(rustc_attrs)] +#![feature(f16)] +#![feature(f128)] // @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types' // @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32' @@ -13,9 +15,19 @@ // @!has foo/index.html '//span' '🔒' #[rustc_doc_primitive = "i32"] /// this is a test! -mod i32{} +mod i32 {} // @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[rustc_doc_primitive = "bool"] /// hello mod bool {} + +// @has foo/primitive.f16.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[rustc_doc_primitive = "f16"] +/// hello +mod f16 {} + +// @has foo/primitive.f128.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[rustc_doc_primitive = "f128"] +/// hello +mod f128 {} diff --git a/tests/rustdoc/synthetic_auto/supertrait-bounds.rs b/tests/rustdoc/synthetic_auto/supertrait-bounds.rs new file mode 100644 index 00000000000..503e65d0f4f --- /dev/null +++ b/tests/rustdoc/synthetic_auto/supertrait-bounds.rs @@ -0,0 +1,14 @@ +// Check that we don't add bounds to synthetic auto trait impls that are +// already implied by the item (like supertrait bounds). + +// In this case we don't want to add the bounds `T: Copy` and `T: 'static` +// to the auto trait impl because they're implied by the bound `T: Bound` +// on the implementor `Type`. + +pub struct Type<T: Bound>(T); + +// @has supertrait_bounds/struct.Type.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ +// "impl<T> Send for Type<T>where T: Send," + +pub trait Bound: Copy + 'static {} diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs index 3152bf23ca5..f77b318039d 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -22,6 +22,7 @@ fn main() { TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Str => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Pat(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 2ff5aad95dd..53bf5cb1a82 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -67,119 +67,125 @@ LL | TyKind::Array(..) => (), error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:25:9 | -LL | TyKind::Slice(..) => (), +LL | TyKind::Pat(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:26:9 | -LL | TyKind::RawPtr(..) => (), +LL | TyKind::Slice(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:27:9 | -LL | TyKind::Ref(..) => (), +LL | TyKind::RawPtr(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:28:9 | -LL | TyKind::FnDef(..) => (), +LL | TyKind::Ref(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:29:9 | -LL | TyKind::FnPtr(..) => (), +LL | TyKind::FnDef(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:30:9 | -LL | TyKind::Dynamic(..) => (), +LL | TyKind::FnPtr(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:31:9 | -LL | TyKind::Closure(..) => (), +LL | TyKind::Dynamic(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:32:9 | -LL | TyKind::CoroutineClosure(..) => (), +LL | TyKind::Closure(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:33:9 | -LL | TyKind::Coroutine(..) => (), +LL | TyKind::CoroutineClosure(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:34:9 | -LL | TyKind::CoroutineWitness(..) => (), +LL | TyKind::Coroutine(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:35:9 | -LL | TyKind::Never => (), +LL | TyKind::CoroutineWitness(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:36:9 | -LL | TyKind::Tuple(..) => (), +LL | TyKind::Never => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:37:9 | -LL | TyKind::Alias(..) => (), +LL | TyKind::Tuple(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:38:9 | -LL | TyKind::Param(..) => (), +LL | TyKind::Alias(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:39:9 | -LL | TyKind::Bound(..) => (), +LL | TyKind::Param(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:40:9 | -LL | TyKind::Placeholder(..) => (), +LL | TyKind::Bound(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:41:9 | -LL | TyKind::Infer(..) => (), +LL | TyKind::Placeholder(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:42:9 | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using `ty::<kind>` directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:43:9 + | LL | TyKind::Error(_) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` - --> $DIR/ty_tykind_usage.rs:47:12 + --> $DIR/ty_tykind_usage.rs:48:12 | LL | if let TyKind::Int(int_ty) = kind {} | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:49:24 + --> $DIR/ty_tykind_usage.rs:50:24 | LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} | ^^^^^^^^^^ @@ -187,7 +193,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:51:37 + --> $DIR/ty_tykind_usage.rs:52:37 | LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { | ^^^^^^^^^^^ @@ -195,7 +201,7 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:51:53 + --> $DIR/ty_tykind_usage.rs:52:53 | LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { | ^^^^^^^^^^^ @@ -203,12 +209,12 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { = help: try using `Ty` instead error: usage of `ty::TyKind::<kind>` - --> $DIR/ty_tykind_usage.rs:54:9 + --> $DIR/ty_tykind_usage.rs:55:9 | LL | IrTyKind::Bool | --------^^^^^^ | | | help: try using `ty::<kind>` directly: `ty` -error: aborting due to 33 previous errors +error: aborting due to 34 previous errors diff --git a/tests/ui-fulldeps/regions-mock-tcx.rs b/tests/ui-fulldeps/regions-mock-tcx.rs index 970f08377a6..71c0aa2d596 100644 --- a/tests/ui-fulldeps/regions-mock-tcx.rs +++ b/tests/ui-fulldeps/regions-mock-tcx.rs @@ -9,10 +9,9 @@ // - Multiple lifetime parameters // - Arenas -#![feature(rustc_private, libc)] +#![feature(rustc_private)] extern crate rustc_arena; -extern crate libc; // Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta // files. diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs new file mode 100644 index 00000000000..3b52d88de3c --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -0,0 +1,147 @@ +//@ run-pass +//! Test information regarding binary operations. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] + +extern crate rustc_hir; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::mir::mono::Instance; +use stable_mir::mir::visit::{Location, MirVisitor}; +use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind}; +use stable_mir::ty::{RigidTy, TyKind}; +use std::collections::HashSet; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::ControlFlow; + +/// This function tests that we can correctly get type information from binary operations. +fn test_binops() -> ControlFlow<()> { + // Find items in the local crate. + let items = stable_mir::all_local_items(); + let mut instances = + items.into_iter().map(|item| Instance::try_from(item).unwrap()).collect::<Vec<_>>(); + while let Some(instance) = instances.pop() { + // The test below shouldn't have recursion in it. + let Some(body) = instance.body() else { + continue; + }; + let mut visitor = Visitor { locals: body.locals(), calls: Default::default() }; + visitor.visit_body(&body); + instances.extend(visitor.calls.into_iter()); + } + ControlFlow::Continue(()) +} + +struct Visitor<'a> { + locals: &'a [LocalDecl], + calls: HashSet<Instance>, +} + +impl<'a> MirVisitor for Visitor<'a> { + fn visit_statement(&mut self, stmt: &Statement, _loc: Location) { + match &stmt.kind { + StatementKind::Assign(place, Rvalue::BinaryOp(op, rhs, lhs)) => { + let ret_ty = place.ty(self.locals).unwrap(); + let op_ty = op.ty(rhs.ty(self.locals).unwrap(), lhs.ty(self.locals).unwrap()); + assert_eq!(ret_ty, op_ty, "Operation type should match the assigned place type"); + } + _ => {} + } + } + + fn visit_terminator(&mut self, term: &Terminator, _loc: Location) { + match &term.kind { + TerminatorKind::Call { func, .. } => { + let TyKind::RigidTy(RigidTy::FnDef(def, args)) = + func.ty(self.locals).unwrap().kind() + else { + return; + }; + self.calls.insert(Instance::resolve(def, &args).unwrap()); + } + _ => {} + } + } +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "binop_input.rs"; + generate_input(&path).unwrap(); + let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + run!(args, test_binops).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + macro_rules! binop_int {{ + ($fn:ident, $typ:ty) => {{ + pub fn $fn(lhs: $typ, rhs: $typ) {{ + let eq = lhs == rhs; + let lt = lhs < rhs; + let le = lhs <= rhs; + + let sum = lhs + rhs; + let mult = lhs * sum; + let shift = mult << 2; + let bit_or = shift | rhs; + let cmp = lhs.cmp(&bit_or); + + // Try to avoid the results above being pruned + std::hint::black_box(((eq, lt, le), cmp)); + }} + }} + }} + + binop_int!(binop_u8, u8); + binop_int!(binop_i64, i64); + + pub fn binop_bool(lhs: bool, rhs: bool) {{ + let eq = lhs == rhs; + let or = lhs | eq; + let lt = lhs < or; + let cmp = lhs.cmp(&rhs); + + // Try to avoid the results above being pruned + std::hint::black_box((lt, cmp)); + }} + + pub fn binop_char(lhs: char, rhs: char) {{ + let eq = lhs == rhs; + let lt = lhs < rhs; + let cmp = lhs.cmp(&rhs); + + // Try to avoid the results above being pruned + std::hint::black_box(([eq, lt], cmp)); + }} + + pub fn binop_ptr(lhs: *const char, rhs: *const char) {{ + let eq = lhs == rhs; + let lt = lhs < rhs; + let cmp = lhs.cmp(&rhs); + let off = unsafe {{ lhs.offset(2) }}; + + // Try to avoid the results above being pruned + std::hint::black_box(([eq, lt], cmp, off)); + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs new file mode 100644 index 00000000000..171850b89bb --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -0,0 +1,115 @@ +//@ run-pass +//! Test information regarding intrinsics and ensure we can retrieve the fallback body if it exists. +//! +//! This tests relies on the intrinsics implementation, and requires one intrinsic with and one +//! without a body. It doesn't matter which intrinsic is called here, and feel free to update that +//! if needed. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] + +extern crate rustc_hir; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::mir::mono::{Instance, InstanceKind}; +use stable_mir::mir::visit::{Location, MirVisitor}; +use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind}; +use stable_mir::ty::{RigidTy, TyKind}; +use std::collections::HashSet; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::ControlFlow; + +/// This function tests that we can correctly get type information from binary operations. +fn test_intrinsics() -> ControlFlow<()> { + // Find items in the local crate. + let main_def = stable_mir::all_local_items()[0]; + let main_instance = Instance::try_from(main_def).unwrap(); + let main_body = main_instance.body().unwrap(); + let mut visitor = CallsVisitor { locals: main_body.locals(), calls: Default::default() }; + visitor.visit_body(&main_body); + + let calls = visitor.calls; + assert_eq!(calls.len(), 2, "Expected 2 calls, but found: {calls:?}"); + for intrinsic in &calls { + check_intrinsic(intrinsic) + } + + ControlFlow::Continue(()) +} + +/// This check is unfortunately tight to the implementation of intrinsics. +/// +/// We want to ensure that StableMIR can handle intrinsics with and without fallback body. +/// +/// If by any chance this test breaks because you changed how an intrinsic is implemented, please +/// update the test to invoke a different intrinsic. +fn check_intrinsic(intrinsic: &Instance) { + assert_eq!(intrinsic.kind, InstanceKind::Intrinsic); + let name = intrinsic.intrinsic_name().unwrap(); + if intrinsic.has_body() { + let Some(body) = intrinsic.body() else { unreachable!("Expected a body") }; + assert!(!body.blocks.is_empty()); + assert_eq!(&name, "likely"); + } else { + assert!(intrinsic.body().is_none()); + assert_eq!(&name, "size_of_val"); + } +} + +struct CallsVisitor<'a> { + locals: &'a [LocalDecl], + calls: HashSet<Instance>, +} + +impl<'a> MirVisitor for CallsVisitor<'a> { + fn visit_terminator(&mut self, term: &Terminator, _loc: Location) { + match &term.kind { + TerminatorKind::Call { func, .. } => { + let TyKind::RigidTy(RigidTy::FnDef(def, args)) = + func.ty(self.locals).unwrap().kind() + else { + return; + }; + self.calls.insert(Instance::resolve(def, &args).unwrap()); + } + _ => {} + } + } +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "binop_input.rs"; + generate_input(&path).unwrap(); + let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + run!(args, test_intrinsics).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + #![feature(core_intrinsics)] + use std::intrinsics::*; + pub fn use_intrinsics(init: bool) -> bool {{ + let sz = unsafe {{ size_of_val("hi") }}; + likely(init && sz == 2) + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/abi/c-stack-returning-int64.rs b/tests/ui/abi/c-stack-returning-int64.rs index 1fd7fe417a5..05c8af90ab3 100644 --- a/tests/ui/abi/c-stack-returning-int64.rs +++ b/tests/ui/abi/c-stack-returning-int64.rs @@ -1,14 +1,10 @@ //@ run-pass //@ ignore-sgx no libc -#![feature(rustc_private)] - -extern crate libc; - use std::ffi::CString; mod mlibc { - use libc::{c_char, c_long, c_longlong}; + use std::ffi::{c_char, c_long, c_longlong}; extern "C" { pub fn atol(x: *const c_char) -> c_long; diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index 33a7194c102..167b7a4e36e 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -3,19 +3,17 @@ // statics cannot. This ensures that there's some form of error if this is // attempted. -#![feature(rustc_private)] - -extern crate libc; +use std::ffi::c_int; #[link(name = "rust_test_helpers", kind = "static")] extern "C" { - static mut rust_dbg_static_mut: libc::c_int; + static mut rust_dbg_static_mut: c_int; pub fn rust_dbg_static_mut_check_four(); } -unsafe fn static_bound(_: &'static libc::c_int) {} +unsafe fn static_bound(_: &'static c_int) {} -fn static_bound_set(a: &'static mut libc::c_int) { +fn static_bound_set(a: &'static mut c_int) { *a = 3; } diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr index 4d5f26ac08c..983325c1abd 100644 --- a/tests/ui/abi/statics/static-mut-foreign.stderr +++ b/tests/ui/abi/statics/static-mut-foreign.stderr @@ -1,5 +1,5 @@ warning: creating a shared reference to mutable static is discouraged - --> $DIR/static-mut-foreign.rs:33:18 + --> $DIR/static-mut-foreign.rs:31:18 | LL | static_bound(&rust_dbg_static_mut); | ^^^^^^^^^^^^^^^^^^^^ shared reference to mutable static @@ -14,7 +14,7 @@ LL | static_bound(addr_of!(rust_dbg_static_mut)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: creating a mutable reference to mutable static is discouraged - --> $DIR/static-mut-foreign.rs:35:22 + --> $DIR/static-mut-foreign.rs:33:22 | LL | static_bound_set(&mut rust_dbg_static_mut); | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static diff --git a/tests/ui/array-slice-vec/vec-macro-no-std.rs b/tests/ui/array-slice-vec/vec-macro-no-std.rs index 76a1b4951d6..1b5ab536dcb 100644 --- a/tests/ui/array-slice-vec/vec-macro-no-std.rs +++ b/tests/ui/array-slice-vec/vec-macro-no-std.rs @@ -7,8 +7,6 @@ extern crate std as other; -extern crate libc; - #[macro_use] extern crate alloc; diff --git a/tests/ui/array-slice-vec/vector-no-ann.stderr b/tests/ui/array-slice-vec/vector-no-ann.stderr index 24b6abfb342..716971eb120 100644 --- a/tests/ui/array-slice-vec/vector-no-ann.stderr +++ b/tests/ui/array-slice-vec/vector-no-ann.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Vec<T>` +error[E0282]: type annotations needed for `Vec<_>` --> $DIR/vector-no-ann.rs:2:9 | LL | let _foo = Vec::new(); diff --git a/tests/ui/asm/aarch64/type-check-2-2.stderr b/tests/ui/asm/aarch64/type-check-2-2.stderr index 41f7c01dc82..760aaefac83 100644 --- a/tests/ui/asm/aarch64/type-check-2-2.stderr +++ b/tests/ui/asm/aarch64/type-check-2-2.stderr @@ -8,8 +8,8 @@ LL | asm!("{}", in(reg) x); | help: consider assigning a value | -LL | let x: u64 = 0; - | +++ +LL | let x: u64 = 42; + | ++++ error[E0381]: used binding `y` isn't initialized --> $DIR/type-check-2-2.rs:22:9 @@ -21,8 +21,8 @@ LL | asm!("{}", inout(reg) y); | help: consider assigning a value | -LL | let mut y: u64 = 0; - | +++ +LL | let mut y: u64 = 42; + | ++++ error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/type-check-2-2.rs:28:13 diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index 6da1b89ed67..4a98d37aca0 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -16,7 +16,7 @@ #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "rlib"] #![no_core] -#![cfg_attr(x86_64_allowed, allow(bad_asm_style))] + #[rustc_builtin_macro] macro_rules! asm { diff --git a/tests/ui/asm/x86_64/type-check-5.stderr b/tests/ui/asm/x86_64/type-check-5.stderr index 7970e76d6a1..4fb75993463 100644 --- a/tests/ui/asm/x86_64/type-check-5.stderr +++ b/tests/ui/asm/x86_64/type-check-5.stderr @@ -8,8 +8,8 @@ LL | asm!("{}", in(reg) x); | help: consider assigning a value | -LL | let x: u64 = 0; - | +++ +LL | let x: u64 = 42; + | ++++ error[E0381]: used binding `y` isn't initialized --> $DIR/type-check-5.rs:18:9 @@ -21,8 +21,8 @@ LL | asm!("{}", inout(reg) y); | help: consider assigning a value | -LL | let mut y: u64 = 0; - | +++ +LL | let mut y: u64 = 42; + | ++++ error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/type-check-5.rs:24:13 diff --git a/tests/ui/associated-types/associated-types-outlives.rs b/tests/ui/associated-types/associated-types-outlives.rs index 55c276280b9..245218067b4 100644 --- a/tests/ui/associated-types/associated-types-outlives.rs +++ b/tests/ui/associated-types/associated-types-outlives.rs @@ -3,10 +3,10 @@ // fn body, causing this (invalid) code to be accepted. pub trait Foo<'a> { - type Bar; + type Bar: Clone; } -impl<'a, T:'a> Foo<'a> for T { +impl<'a, T: 'a> Foo<'a> for T { type Bar = &'a T; } diff --git a/tests/ui/associated-types/associated-types-outlives.stderr b/tests/ui/associated-types/associated-types-outlives.stderr index deeedd22266..c97af672c33 100644 --- a/tests/ui/associated-types/associated-types-outlives.stderr +++ b/tests/ui/associated-types/associated-types-outlives.stderr @@ -10,6 +10,11 @@ LL | drop(x); | ^ move out of `x` occurs here LL | return f(y); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | 's: loop { y = denormalise(&x).clone(); break } + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/issue-25700.stderr b/tests/ui/associated-types/issue-25700.stderr index 4e432c0e702..fb0e63c207a 100644 --- a/tests/ui/associated-types/issue-25700.stderr +++ b/tests/ui/associated-types/issue-25700.stderr @@ -7,6 +7,12 @@ LL | drop(t); | - value moved here LL | drop(t); | ^ value used here after move + | +note: if `S<()>` implemented `Clone`, you could clone the value + --> $DIR/issue-25700.rs:1:1 + | +LL | struct S<T: 'static>(#[allow(dead_code)] Option<&'static T>); + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error 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 1990d0ffe2a..ffb97ca04ac 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -5,7 +5,6 @@ fn foo() -> Box<dyn std::future::Future<Output = u32>> { 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 index be67c78221a..4b1ce300b56 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr @@ -7,15 +7,6 @@ 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 +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs new file mode 100644 index 00000000000..a43906d01e5 --- /dev/null +++ b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs @@ -0,0 +1,27 @@ +//@ edition: 2021 +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(async_closure)] + +fn constrain<T: async FnOnce()>(t: T) -> T { + t +} + +fn call_once<T>(f: impl FnOnce() -> T) -> T { + f() +} + +async fn async_call_once<T>(f: impl async FnOnce() -> T) -> T { + f().await +} + +fn main() { + let c = constrain(async || {}); + call_once(c); + + let c = constrain(async || {}); + async_call_once(c); +} diff --git a/tests/ui/async-await/async-closures/different-projection-lengths-for-different-upvars.rs b/tests/ui/async-await/async-closures/different-projection-lengths-for-different-upvars.rs new file mode 100644 index 00000000000..2313db506be --- /dev/null +++ b/tests/ui/async-await/async-closures/different-projection-lengths-for-different-upvars.rs @@ -0,0 +1,16 @@ +//@ check-pass +//@ edition: 2021 +// issue: rust-lang/rust#123697 + +#![feature(async_closure)] + +struct S { t: i32 } + +fn test(s: &S, t: &i32) { + async || { + println!("{}", s.t); + println!("{}", t); + }; +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs new file mode 100644 index 00000000000..8fc9924a12f --- /dev/null +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs @@ -0,0 +1,23 @@ +//@ edition: 2021 + +#![feature(async_closure)] + +struct DropMe; + +trait Impossible {} +fn trait_error<T: Impossible>() {} + +pub fn main() { + let b = DropMe; + let async_closure = async move || { + // Type error here taints the environment. This causes us to fallback all + // variables to `Error`. This means that when we compute the upvars for the + // *outer* coroutine-closure, we don't actually see any upvars since `MemCategorization` + // and `ExprUseVisitor`` will bail early when it sees error. This means + // that our underlying assumption that the parent and child captures are + // compatible ends up being broken, previously leading to an ICE. + trait_error::<()>(); + //~^ ERROR the trait bound `(): Impossible` is not satisfied + let _b = b; + }; +} diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr new file mode 100644 index 00000000000..b4dc3e268bd --- /dev/null +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): Impossible` is not satisfied + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:19:23 + | +LL | trait_error::<()>(); + | ^^ the trait `Impossible` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:7:1 + | +LL | trait Impossible {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `trait_error` + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:8:19 + | +LL | fn trait_error<T: Impossible>() {} + | ^^^^^^^^^^ required by this bound in `trait_error` + +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/moro-example.rs b/tests/ui/async-await/async-closures/moro-example.rs new file mode 100644 index 00000000000..5a8f42c7ca5 --- /dev/null +++ b/tests/ui/async-await/async-closures/moro-example.rs @@ -0,0 +1,43 @@ +//@ check-pass +//@ edition: 2021 + +#![feature(async_closure)] + +use std::future::Future; +use std::pin::Pin; +use std::{marker::PhantomData, sync::Mutex}; + +type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>; + +pub struct Scope<'scope, 'env: 'scope> { + enqueued: Mutex<Vec<BoxFuture<'scope, ()>>>, + phantom: PhantomData<&'env ()>, +} + +impl<'scope, 'env: 'scope> Scope<'scope, 'env> { + pub fn spawn(&'scope self, future: impl Future<Output = ()> + Send + 'scope) { + self.enqueued.lock().unwrap().push(Box::pin(future)); + } +} + +fn scope_with_closure<'env, B>(_body: B) -> BoxFuture<'env, ()> +where + for<'scope> B: async FnOnce(&'scope Scope<'scope, 'env>), +{ + todo!() +} + +type ScopeRef<'scope, 'env> = &'scope Scope<'scope, 'env>; + +async fn go<'a>(value: &'a i32) { + let closure = async |scope: ScopeRef<'_, 'a>| { + let _future1 = scope.spawn(async { + // Make sure that `*value` is immutably borrowed with lifetime of + // `'a` and not with the lifetime of the containing coroutine-closure. + let _v = *value; + }); + }; + scope_with_closure(closure).await; +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/mut-ref-reborrow.rs b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs new file mode 100644 index 00000000000..9f2cbd7ce1c --- /dev/null +++ b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs @@ -0,0 +1,27 @@ +//@ aux-build:block-on.rs +//@ run-pass +//@ check-run-results +//@ revisions: e2021 e2018 +//@[e2018] edition:2018 +//@[e2021] edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { f().await; } + +pub async fn async_closure(x: &mut i32) { + let c = async move || { + *x += 1; + }; + call_once(c).await; +} + +fn main() { + block_on::block_on(async { + let mut x = 0; + async_closure(&mut x).await; + assert_eq!(x, 1); + }); +} diff --git a/tests/ui/async-await/async-closures/no-borrow-from-env.rs b/tests/ui/async-await/async-closures/no-borrow-from-env.rs new file mode 100644 index 00000000000..fe84aeeb32f --- /dev/null +++ b/tests/ui/async-await/async-closures/no-borrow-from-env.rs @@ -0,0 +1,44 @@ +//@ edition: 2021 +//@ check-pass + +#![feature(async_closure)] + +fn outlives<'a>(_: impl Sized + 'a) {} + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +fn simple<'a>(x: &'a i32) { + let c = async || { println!("{}", *x); }; + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); + + let c = async move || { println!("{}", *x); }; + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); +} + +struct S<'a>(&'a i32); + +fn through_field<'a>(x: S<'a>) { + let c = async || { println!("{}", *x.0); }; + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); + + let c = async move || { println!("{}", *x.0); }; + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); +} + +fn through_field_and_ref<'a>(x: &S<'a>) { + let c = async || { println!("{}", *x.0); }; + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); + + let c = async move || { println!("{}", *x.0); }; + outlives::<'a>(c()); + // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/overlapping-projs.rs b/tests/ui/async-await/async-closures/overlapping-projs.rs new file mode 100644 index 00000000000..6dd00b16103 --- /dev/null +++ b/tests/ui/async-await/async-closures/overlapping-projs.rs @@ -0,0 +1,27 @@ +//@ aux-build:block-on.rs +//@ edition:2021 +//@ run-pass +//@ check-run-results + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +async fn async_main() { + let x = &mut 0; + let y = &mut 0; + let c = async || { + *x = 1; + *y = 2; + }; + call_once(c).await; + println!("{x} {y}"); +} + +fn main() { + block_on::block_on(async_main()); +} diff --git a/tests/ui/async-await/async-closures/overlapping-projs.run.stdout b/tests/ui/async-await/async-closures/overlapping-projs.run.stdout new file mode 100644 index 00000000000..8d04f961a03 --- /dev/null +++ b/tests/ui/async-await/async-closures/overlapping-projs.run.stdout @@ -0,0 +1 @@ +1 2 diff --git a/tests/ui/async-await/async-closures/precise-captures.call.run.stdout b/tests/ui/async-await/async-closures/precise-captures.call.run.stdout new file mode 100644 index 00000000000..6062556837c --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.call.run.stdout @@ -0,0 +1,29 @@ +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +after await +fixed +untouched + +after call +drop first +after await +uncaptured + +after call +drop first +after await +uncaptured diff --git a/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout b/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout new file mode 100644 index 00000000000..ddb02d47600 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout @@ -0,0 +1,29 @@ +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +fixed +after await +uncaptured + +after call +after await +fixed +untouched + +after call +drop first +after await +uncaptured + +after call +drop first +after await +uncaptured diff --git a/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout b/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout new file mode 100644 index 00000000000..ddb02d47600 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout @@ -0,0 +1,29 @@ +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +fixed +after await +uncaptured + +after call +after await +fixed +untouched + +after call +drop first +after await +uncaptured + +after call +drop first +after await +uncaptured diff --git a/tests/ui/async-await/async-closures/precise-captures.rs b/tests/ui/async-await/async-closures/precise-captures.rs new file mode 100644 index 00000000000..e82dd1dbaf0 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.rs @@ -0,0 +1,157 @@ +//@ aux-build:block-on.rs +//@ edition:2021 +//@ run-pass +//@ check-run-results +//@ revisions: call call_once force_once + +// call - Call the closure regularly. +// call_once - Call the closure w/ `async FnOnce`, so exercising the by_move shim. +// force_once - Force the closure mode to `FnOnce`, so exercising what was fixed +// in <https://github.com/rust-lang/rust/pull/123350>. + +#![feature(async_closure)] +#![allow(unused_mut)] + +extern crate block_on; + +#[cfg(any(call, force_once))] +macro_rules! call { + ($c:expr) => { ($c)() } +} + +#[cfg(call_once)] +async fn call_once(f: impl async FnOnce()) { + f().await +} + +#[cfg(call_once)] +macro_rules! call { + ($c:expr) => { call_once($c) } +} + +#[cfg(not(force_once))] +macro_rules! guidance { + ($c:expr) => { $c } +} + +#[cfg(force_once)] +fn infer_fnonce(c: impl async FnOnce()) -> impl async FnOnce() { c } + +#[cfg(force_once)] +macro_rules! guidance { + ($c:expr) => { infer_fnonce($c) } +} + +#[derive(Debug)] +struct Drop(&'static str); + +impl std::ops::Drop for Drop { + fn drop(&mut self) { + println!("{}", self.0); + } +} + +struct S { + a: i32, + b: Drop, + c: Drop, +} + +async fn async_main() { + // Precise capture struct + { + let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture &mut struct + { + let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct by move + { + let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async move || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture &mut struct by move + { + let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async move || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + // `s` is still captured fully as `&mut S`. + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct, consume field + { + let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") }; + let c = guidance!(async move || { + // s.a = 2; // FIXME(async_closures): Figure out why this fails + drop(s.b); + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct by move, consume field + { + let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") }; + let c = guidance!(async move || { + // s.a = 2; // FIXME(async_closures): Figure out why this fails + drop(s.b); + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } +} + +fn main() { + block_on::block_on(async_main()); +} diff --git a/tests/ui/async-await/async-closures/truncated-fields-when-imm.rs b/tests/ui/async-await/async-closures/truncated-fields-when-imm.rs new file mode 100644 index 00000000000..5c718638d80 --- /dev/null +++ b/tests/ui/async-await/async-closures/truncated-fields-when-imm.rs @@ -0,0 +1,17 @@ +//@ edition: 2021 +//@ check-pass + +#![feature(async_closure)] + +pub struct Struct { + pub path: String, +} + +// In `upvar.rs`, `truncate_capture_for_optimization` means that we don't actually +// capture `&(*s.path)` here, but instead just `&(*s)`, but ONLY when the upvar is +// immutable. This means that the assumption we have in `ByMoveBody` pass is wrong. +pub fn test(s: &Struct) { + let c = async move || { let path = &s.path; }; +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs new file mode 100644 index 00000000000..17681161e20 --- /dev/null +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs @@ -0,0 +1,47 @@ +//@ edition: 2018 + +// This is `no-borrow-from-env.rs`, but under edition 2018 we still want to make +// sure that we don't ICE or anything, even if precise closure captures means +// that we can't actually borrowck successfully. + +#![feature(async_closure)] + +fn outlives<'a>(_: impl Sized + 'a) {} + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +fn simple<'a>(x: &'a i32) { + let c = async || { println!("{}", *x); }; //~ ERROR `x` does not live long enough + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); + + let c = async move || { println!("{}", *x); }; + outlives::<'a>(c()); //~ ERROR `c` does not live long enough + outlives::<'a>(call_once(c)); //~ ERROR cannot move out of `c` +} + +struct S<'a>(&'a i32); + +fn through_field<'a>(x: S<'a>) { + let c = async || { println!("{}", *x.0); }; //~ ERROR `x` does not live long enough + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); + + let c = async move || { println!("{}", *x.0); }; //~ ERROR cannot move out of `x` + outlives::<'a>(c()); //~ ERROR `c` does not live long enough + outlives::<'a>(call_once(c)); //~ ERROR cannot move out of `c` +} + +fn through_field_and_ref<'a>(x: &S<'a>) { + let c = async || { println!("{}", *x.0); }; //~ ERROR `x` does not live long enough + outlives::<'a>(c()); + outlives::<'a>(call_once(c)); //~ ERROR explicit lifetime required in the type of `x` + + let c = async move || { println!("{}", *x.0); }; + outlives::<'a>(c()); //~ ERROR `c` does not live long enough + // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr new file mode 100644 index 00000000000..569028934cb --- /dev/null +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -0,0 +1,152 @@ +error[E0597]: `x` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:16:13 + | +LL | fn simple<'a>(x: &'a i32) { + | -- lifetime `'a` defined here +LL | let c = async || { println!("{}", *x); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +LL | outlives::<'a>(c()); +LL | outlives::<'a>(call_once(c)); + | ------------ argument requires that `x` is borrowed for `'a` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `c` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:21:20 + | +LL | fn simple<'a>(x: &'a i32) { + | -- lifetime `'a` defined here +... +LL | let c = async move || { println!("{}", *x); }; + | - binding `c` declared here +LL | outlives::<'a>(c()); + | ^-- + | | + | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` +LL | outlives::<'a>(call_once(c)); +LL | } + | - `c` dropped here while still borrowed + +error[E0505]: cannot move out of `c` because it is borrowed + --> $DIR/without-precise-captures-we-are-powerless.rs:22:30 + | +LL | fn simple<'a>(x: &'a i32) { + | -- lifetime `'a` defined here +... +LL | let c = async move || { println!("{}", *x); }; + | - binding `c` declared here +LL | outlives::<'a>(c()); + | --- + | | + | borrow of `c` occurs here + | argument requires that `c` is borrowed for `'a` +LL | outlives::<'a>(call_once(c)); + | ^ move out of `c` occurs here + +error[E0597]: `x` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:28:13 + | +LL | fn through_field<'a>(x: S<'a>) { + | -- lifetime `'a` defined here +LL | let c = async || { println!("{}", *x.0); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +LL | outlives::<'a>(c()); +LL | outlives::<'a>(call_once(c)); + | ------------ argument requires that `x` is borrowed for `'a` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/without-precise-captures-we-are-powerless.rs:32:13 + | +LL | fn through_field<'a>(x: S<'a>) { + | -- lifetime `'a` defined here +LL | let c = async || { println!("{}", *x.0); }; + | ---------------------------------- borrow of `x` occurs here +LL | outlives::<'a>(c()); +LL | outlives::<'a>(call_once(c)); + | ------------ argument requires that `x` is borrowed for `'a` +LL | +LL | let c = async move || { println!("{}", *x.0); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `x` occurs here + +error[E0597]: `c` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:33:20 + | +LL | fn through_field<'a>(x: S<'a>) { + | -- lifetime `'a` defined here +... +LL | let c = async move || { println!("{}", *x.0); }; + | - binding `c` declared here +LL | outlives::<'a>(c()); + | ^-- + | | + | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` +LL | outlives::<'a>(call_once(c)); +LL | } + | - `c` dropped here while still borrowed + +error[E0505]: cannot move out of `c` because it is borrowed + --> $DIR/without-precise-captures-we-are-powerless.rs:34:30 + | +LL | fn through_field<'a>(x: S<'a>) { + | -- lifetime `'a` defined here +... +LL | let c = async move || { println!("{}", *x.0); }; + | - binding `c` declared here +LL | outlives::<'a>(c()); + | --- + | | + | borrow of `c` occurs here + | argument requires that `c` is borrowed for `'a` +LL | outlives::<'a>(call_once(c)); + | ^ move out of `c` occurs here + +error[E0597]: `x` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:38:13 + | +LL | fn through_field_and_ref<'a>(x: &S<'a>) { + | -- lifetime `'a` defined here +LL | let c = async || { println!("{}", *x.0); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +LL | outlives::<'a>(c()); +LL | outlives::<'a>(call_once(c)); + | ------------ argument requires that `x` is borrowed for `'a` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/without-precise-captures-we-are-powerless.rs:40:20 + | +LL | fn through_field_and_ref<'a>(x: &S<'a>) { + | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` +... +LL | outlives::<'a>(call_once(c)); + | ^^^^^^^^^^^^ lifetime `'a` required + +error[E0597]: `c` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:43:20 + | +LL | fn through_field_and_ref<'a>(x: &S<'a>) { + | -- lifetime `'a` defined here +... +LL | let c = async move || { println!("{}", *x.0); }; + | - binding `c` declared here +LL | outlives::<'a>(c()); + | ^-- + | | + | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` +LL | // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails +LL | } + | - `c` dropped here while still borrowed + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0505, E0597, E0621. +For more information about an error, try `rustc --explain E0505`. diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs new file mode 100644 index 00000000000..8ad99a4c201 --- /dev/null +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.rs @@ -0,0 +1,17 @@ +//@ edition: 2021 + +fn call(_: impl Fn() -> bool) {} + +async fn test() { + call(|| -> Option<()> { + //~^ ERROR expected + if true { + false + //~^ ERROR mismatched types + } + true + //~^ ERROR mismatched types + }) +} + +fn main() {} diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr new file mode 100644 index 00000000000..70cd9f924ac --- /dev/null +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr @@ -0,0 +1,46 @@ +error[E0308]: mismatched types + --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:9:13 + | +LL | / if true { +LL | | false + | | ^^^^^ expected `()`, found `bool` +LL | | +LL | | } + | |_________- expected this to be `()` + +error[E0308]: mismatched types + --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9 + | +LL | true + | ^^^^ expected `Option<()>`, found `bool` + | + = note: expected enum `Option<()>` + found type `bool` + +error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to be a closure that returns `bool`, but it returns `Option<()>` + --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10 + | +LL | call(|| -> Option<()> { + | _____----_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | if true { +LL | | false +... | +LL | | +LL | | }) + | |_____^ expected `bool`, found `Option<()>` + | + = note: expected type `bool` + found enum `Option<()>` +note: required by a bound in `call` + --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:3:25 + | +LL | fn call(_: impl Fn() -> bool) {} + | ^^^^ required by this bound in `call` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0308. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr index 92f38d5a796..640d946421a 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr @@ -62,7 +62,7 @@ error[E0308]: mismatched types --> $DIR/async-closure-gate.rs:27:5 | LL | fn foo3() { - | - help: a return type might be missing here: `-> _` + | - help: try adding a return type: `-> impl Future<Output = ()>` LL | / async { LL | | LL | | let _ = #[track_caller] || { @@ -78,7 +78,7 @@ error[E0308]: mismatched types --> $DIR/async-closure-gate.rs:44:5 | LL | fn foo5() { - | - help: a return type might be missing here: `-> _` + | - help: try adding a return type: `-> impl Future<Output = ()>` LL | / async { LL | | LL | | let _ = || { diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr index 92f38d5a796..640d946421a 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr @@ -62,7 +62,7 @@ error[E0308]: mismatched types --> $DIR/async-closure-gate.rs:27:5 | LL | fn foo3() { - | - help: a return type might be missing here: `-> _` + | - help: try adding a return type: `-> impl Future<Output = ()>` LL | / async { LL | | LL | | let _ = #[track_caller] || { @@ -78,7 +78,7 @@ error[E0308]: mismatched types --> $DIR/async-closure-gate.rs:44:5 | LL | fn foo5() { - | - help: a return type might be missing here: `-> _` + | - help: try adding a return type: `-> impl Future<Output = ()>` LL | / async { LL | | LL | | let _ = || { diff --git a/tests/ui/augmented-assignments.rs b/tests/ui/augmented-assignments.rs index bd2435a78bf..8b263e03593 100644 --- a/tests/ui/augmented-assignments.rs +++ b/tests/ui/augmented-assignments.rs @@ -1,5 +1,6 @@ use std::ops::AddAssign; +#[derive(Clone)] struct Int(i32); impl AddAssign for Int { @@ -16,6 +17,7 @@ fn main() { x; //~^ ERROR cannot move out of `x` because it is borrowed //~| move out of `x` occurs here + //~| HELP consider cloning let y = Int(2); //~^ HELP consider changing this to be mutable diff --git a/tests/ui/augmented-assignments.stderr b/tests/ui/augmented-assignments.stderr index d1096aea279..6b2900dd5d1 100644 --- a/tests/ui/augmented-assignments.stderr +++ b/tests/ui/augmented-assignments.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/augmented-assignments.rs:16:5 + --> $DIR/augmented-assignments.rs:17:5 | LL | let mut x = Int(1); | ----- binding `x` declared here @@ -8,9 +8,14 @@ LL | x ... LL | x; | ^ move out of `x` occurs here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | x.clone(); + | ++++++++ error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/augmented-assignments.rs:23:5 + --> $DIR/augmented-assignments.rs:25:5 | LL | y | ^ cannot borrow as mutable diff --git a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs b/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs index 5330b7a92a3..bcab5f238c3 100644 --- a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs +++ b/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs @@ -5,7 +5,7 @@ #![crate_name = "check_static_recursion_foreign_helper"] #![crate_type = "lib"] -extern crate libc; +use std::ffi::c_int; #[no_mangle] -pub static test_static: libc::c_int = 0; +pub static test_static: c_int = 0; diff --git a/tests/ui/binop/issue-77910-1.stderr b/tests/ui/binop/issue-77910-1.stderr index 6402e568188..74deac900d4 100644 --- a/tests/ui/binop/issue-77910-1.stderr +++ b/tests/ui/binop/issue-77910-1.stderr @@ -32,8 +32,8 @@ LL | xs | help: consider assigning a value | -LL | let xs = todo!(); - | +++++++++ +LL | let xs = &42; + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/binop/issue-77910-2.stderr b/tests/ui/binop/issue-77910-2.stderr index a14560ff188..7087f2cdf41 100644 --- a/tests/ui/binop/issue-77910-2.stderr +++ b/tests/ui/binop/issue-77910-2.stderr @@ -21,8 +21,8 @@ LL | xs | help: consider assigning a value | -LL | let xs = todo!(); - | +++++++++ +LL | let xs = &42; + | +++++ error: aborting due to 2 previous errors diff --git a/tests/ui/binop/multiply-is-deref-on-rhs.rs b/tests/ui/binop/multiply-is-deref-on-rhs.rs new file mode 100644 index 00000000000..7c24e1b4d57 --- /dev/null +++ b/tests/ui/binop/multiply-is-deref-on-rhs.rs @@ -0,0 +1,8 @@ +pub fn test(y: &i32) { + let x; + x = () + *y + //~^ ERROR cannot multiply `()` by `&i32` +} + +fn main() {} diff --git a/tests/ui/binop/multiply-is-deref-on-rhs.stderr b/tests/ui/binop/multiply-is-deref-on-rhs.stderr new file mode 100644 index 00000000000..e157f4f58ca --- /dev/null +++ b/tests/ui/binop/multiply-is-deref-on-rhs.stderr @@ -0,0 +1,16 @@ +error[E0369]: cannot multiply `()` by `&i32` + --> $DIR/multiply-is-deref-on-rhs.rs:4:5 + | +LL | x = () + | -- () +LL | *y + | ^- &i32 + | +help: you might have meant to write a semicolon here + | +LL | x = (); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/borrowck/argument_number_mismatch_ice.stderr b/tests/ui/borrowck/argument_number_mismatch_ice.stderr index 2a6a6dbc64c..702cebb86ba 100644 --- a/tests/ui/borrowck/argument_number_mismatch_ice.stderr +++ b/tests/ui/borrowck/argument_number_mismatch_ice.stderr @@ -12,6 +12,11 @@ error[E0594]: cannot assign to `*input`, which is behind a `&` reference | LL | *input = self.0; | ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition + | +LL | fn example(&self, input: &mut i32) { + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrow-tuple-fields.stderr b/tests/ui/borrowck/borrow-tuple-fields.stderr index e324ebfb50f..8ea7a9a4989 100644 --- a/tests/ui/borrowck/borrow-tuple-fields.stderr +++ b/tests/ui/borrowck/borrow-tuple-fields.stderr @@ -10,6 +10,12 @@ LL | let y = x; LL | LL | r.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let r = &x.0; +LL + let r = x.0.clone(); + | error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable --> $DIR/borrow-tuple-fields.rs:18:13 @@ -42,6 +48,12 @@ LL | let y = x; | ^ move out of `x` occurs here LL | r.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let r = &x.0; +LL + let r = x.0.clone(); + | error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable --> $DIR/borrow-tuple-fields.rs:33:13 diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr index e582ec605de..b96949fbb0e 100644 --- a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr +++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr @@ -10,6 +10,12 @@ LL | &*a, | --- borrow of `*a` occurs here LL | a); | ^ move out of `a` occurs here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - &*a, +LL + a.clone(), + | error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/borrowck-bad-nested-calls-move.rs:32:9 @@ -22,6 +28,12 @@ LL | &*a, | --- borrow of `*a` occurs here LL | a); | ^ move out of `a` occurs here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - &*a, +LL + a.clone(), + | error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-block-uninit.stderr b/tests/ui/borrowck/borrowck-block-uninit.stderr index 07c09f1f443..4db98a7a0dc 100644 --- a/tests/ui/borrowck/borrowck-block-uninit.stderr +++ b/tests/ui/borrowck/borrowck-block-uninit.stderr @@ -10,8 +10,8 @@ LL | println!("{}", x); | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr index 7c0cda31c97..e23ca534e74 100644 --- a/tests/ui/borrowck/borrowck-break-uninit-2.stderr +++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr @@ -10,8 +10,8 @@ LL | println!("{}", x); = 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) help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr index 0d879c6fb7d..0367d224f80 100644 --- a/tests/ui/borrowck/borrowck-break-uninit.stderr +++ b/tests/ui/borrowck/borrowck-break-uninit.stderr @@ -10,8 +10,8 @@ LL | println!("{}", x); = 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) help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr index 411d85b8e05..9066891d298 100644 --- a/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr +++ b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -38,6 +38,11 @@ LL | let [y, z @ ..] = x; LL | }; LL | &x; | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let [y, z @ ..] = x.clone(); + | ++++++++ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable --> $DIR/borrowck-closures-slice-patterns.rs:33:13 @@ -79,6 +84,12 @@ LL | let [y, z @ ..] = *x; LL | }; LL | &x; | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let [y, z @ ..] = *x; +LL + let [y, z @ ..] = x.clone(); + | error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable --> $DIR/borrowck-closures-slice-patterns.rs:59:13 diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.stderr b/tests/ui/borrowck/borrowck-field-sensitivity.stderr index 11812847dd1..ea552ff7820 100644 --- a/tests/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/tests/ui/borrowck/borrowck-field-sensitivity.stderr @@ -49,6 +49,12 @@ LL | drop(x.b); | ^^^ move out of `x.b` occurs here LL | drop(**p); | --- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let p = &x.b; +LL + let p = x.b.clone(); + | error[E0505]: cannot move out of `x.b` because it is borrowed --> $DIR/borrowck-field-sensitivity.rs:41:14 @@ -61,6 +67,12 @@ LL | let _y = A { a: 3, .. x }; | ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here LL | drop(**p); | --- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let p = &x.b; +LL + let p = x.b.clone(); + | error[E0499]: cannot borrow `x.a` as mutable more than once at a time --> $DIR/borrowck-field-sensitivity.rs:48:13 diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.rs b/tests/ui/borrowck/borrowck-fn-in-const-a.rs index d4ceae2963b..d52ec342b1a 100644 --- a/tests/ui/borrowck/borrowck-fn-in-const-a.rs +++ b/tests/ui/borrowck/borrowck-fn-in-const-a.rs @@ -9,4 +9,5 @@ const MOVE: fn(&String) -> String = { }; fn main() { + println!("{}", MOVE(&String::new())); } diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.stderr b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr index e05696864fd..7bf0f859fdd 100644 --- a/tests/ui/borrowck/borrowck-fn-in-const-a.stderr +++ b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr @@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*x` which is behind a shared reference | LL | return *x | ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - return *x +LL + return x.clone() + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-in-static.rs b/tests/ui/borrowck/borrowck-in-static.rs index a45f7b18e07..864dff40f46 100644 --- a/tests/ui/borrowck/borrowck-in-static.rs +++ b/tests/ui/borrowck/borrowck-in-static.rs @@ -1,6 +1,6 @@ // check that borrowck looks inside consts/statics -static FN : &'static (dyn Fn() -> (Box<dyn Fn()->Box<i32>>) + Sync) = &|| { +static FN : &'static (dyn Fn() -> Box<dyn Fn()->Box<i32>> + Sync) = &|| { let x = Box::new(0); Box::new(|| x) //~ ERROR cannot move out of `x`, a captured variable in an `Fn` closure }; diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr index 8171e6950ac..745b02ae21b 100644 --- a/tests/ui/borrowck/borrowck-in-static.stderr +++ b/tests/ui/borrowck/borrowck-in-static.stderr @@ -7,6 +7,11 @@ LL | Box::new(|| x) | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait | | | captured by this `Fn` closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Box::new(|| x.clone()) + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr index a27b6956b30..bfe3c60a84a 100644 --- a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr +++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr @@ -8,8 +8,8 @@ LL | i | help: consider assigning a value | -LL | let i: isize = 0; - | +++ +LL | let i: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr index 16f4c40f529..a248a6d85b6 100644 --- a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr +++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr @@ -8,8 +8,8 @@ LL | i | help: consider assigning a value | -LL | let i: isize = 0; - | +++ +LL | let i: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-init-in-fru.stderr b/tests/ui/borrowck/borrowck-init-in-fru.stderr index f27993e10b4..b5c332a90bc 100644 --- a/tests/ui/borrowck/borrowck-init-in-fru.stderr +++ b/tests/ui/borrowck/borrowck-init-in-fru.stderr @@ -8,8 +8,8 @@ LL | origin = Point { x: 10, ..origin }; | help: consider assigning a value | -LL | let mut origin: Point = todo!(); - | +++++++++ +LL | let mut origin: Point = value; + | +++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-init-op-equal.stderr b/tests/ui/borrowck/borrowck-init-op-equal.stderr index 241d24341cb..d621c4ab46e 100644 --- a/tests/ui/borrowck/borrowck-init-op-equal.stderr +++ b/tests/ui/borrowck/borrowck-init-op-equal.stderr @@ -8,8 +8,8 @@ LL | v += 1; | help: consider assigning a value | -LL | let v: isize = 0; - | +++ +LL | let v: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.stderr b/tests/ui/borrowck/borrowck-init-plus-equal.stderr index 65de6e8bf5d..109321386ba 100644 --- a/tests/ui/borrowck/borrowck-init-plus-equal.stderr +++ b/tests/ui/borrowck/borrowck-init-plus-equal.stderr @@ -8,8 +8,8 @@ LL | v = v + 1; | help: consider assigning a value | -LL | let mut v: isize = 0; - | +++ +LL | let mut v: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.fixed b/tests/ui/borrowck/borrowck-issue-2657-2.fixed index e5aaf7d2de7..e532aa3e68c 100644 --- a/tests/ui/borrowck/borrowck-issue-2657-2.fixed +++ b/tests/ui/borrowck/borrowck-issue-2657-2.fixed @@ -5,7 +5,7 @@ fn main() { match x { Some(ref y) => { - let _b = y; //~ ERROR cannot move out + let _b = y.clone(); //~ ERROR cannot move out } _ => {} } diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.stderr b/tests/ui/borrowck/borrowck-issue-2657-2.stderr index 6fab19000fc..16186792b93 100644 --- a/tests/ui/borrowck/borrowck-issue-2657-2.stderr +++ b/tests/ui/borrowck/borrowck-issue-2657-2.stderr @@ -9,6 +9,11 @@ help: consider removing the dereference here LL - let _b = *y; LL + let _b = y; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let _b = *y; +LL + let _b = y.clone(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-issue-48962.stderr b/tests/ui/borrowck/borrowck-issue-48962.stderr index ee174f6736e..6e821a4c6b0 100644 --- a/tests/ui/borrowck/borrowck-issue-48962.stderr +++ b/tests/ui/borrowck/borrowck-issue-48962.stderr @@ -17,6 +17,11 @@ LL | {src}; | --- value moved here LL | src.0 = 66; | ^^^^^^^^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | {src.clone()}; + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr index 86479043a06..370ae058f44 100644 --- a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr +++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -13,6 +13,12 @@ LL | println!("v={}", *v); LL | }); LL | w.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let w = &v; +LL + let w = v.clone(); + | error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 @@ -29,6 +35,12 @@ LL | println!("v={}", *v); LL | }); LL | w.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let w = &v; +LL + let w = v.clone(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr index d1fbc5b47db..8a8005dbb83 100644 --- a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr +++ b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr @@ -9,6 +9,12 @@ LL | take(v); | ^ move out of `v` occurs here LL | w.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let w = &v; +LL + let w = v.clone(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr index a41c4af98e7..a23a203d999 100644 --- a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr +++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr @@ -10,6 +10,12 @@ LL | let z = *a; | ^^ move out of `*a` occurs here LL | b.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let b = &a; +LL + let b = a.clone(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr index 7213f85ad98..ebc3b6ebcac 100644 --- a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr +++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -9,6 +9,11 @@ help: consider removing the dereference here LL - let y = *x; LL + let y = x; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = *x; +LL + let y = x.clone(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr index 88eb6c8ceee..acf426906c3 100644 --- a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr +++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr @@ -10,6 +10,12 @@ LL | let t1 = t0; LL | *t1 = 22; LL | p.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let p: &isize = &*t0; // Freezes `*t0` +LL + let p: &isize = t0.clone(); // Freezes `*t0` + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed index 8d5ebbc7744..a19db7e5cd3 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed @@ -2,6 +2,6 @@ use std::rc::Rc; pub fn main() { - let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); + let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2]).clone()).into_iter(); //~^ ERROR [E0507] } diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 076f0ce3440..577c2de38be 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -12,6 +12,10 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); | ++++++++++++++++++++++++++++ + +help: consider cloning the value if the performance cost is acceptable + | +LL | let _x = Rc::new(vec![1, 2]).clone().into_iter(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr index dce1f4d0775..774aac3ec9c 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr @@ -9,6 +9,11 @@ help: consider removing the dereference here LL - let _x = *Rc::new("hi".to_string()); LL + let _x = Rc::new("hi".to_string()); | +help: consider cloning the value if the performance cost is acceptable + | +LL - let _x = *Rc::new("hi".to_string()); +LL + let _x = Rc::new("hi".to_string()).clone(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.rs b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs index d01fb261894..b24d9b932cd 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-static-item.rs +++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs @@ -8,7 +8,8 @@ static BAR: Foo = Foo { foo: 5 }; fn test(f: Foo) { - let _f = Foo{foo: 4, ..f}; + let f = Foo { foo: 4, ..f }; + println!("{}", f.foo); } fn main() { diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr index 07dcaf875e7..86bddacbdc7 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr @@ -1,8 +1,14 @@ error[E0507]: cannot move out of static item `BAR` - --> $DIR/borrowck-move-out-of-static-item.rs:15:10 + --> $DIR/borrowck-move-out-of-static-item.rs:16:10 | LL | test(BAR); | ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrowck-move-out-of-static-item.rs:3:1 + | +LL | struct Foo { + | ^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr index 8408d99156a..4d9477f8581 100644 --- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr +++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr @@ -9,6 +9,12 @@ LL | let S { x: ax } = a; | ^^ move out of `a.x` occurs here LL | f(pb); | -- borrow later used here + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/borrowck-move-subcomponent.rs:6:1 + | +LL | struct S { + | ^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-multiple-captures.stderr b/tests/ui/borrowck/borrowck-multiple-captures.stderr index 70abe7b346e..fdac4c27cee 100644 --- a/tests/ui/borrowck/borrowck-multiple-captures.stderr +++ b/tests/ui/borrowck/borrowck-multiple-captures.stderr @@ -14,6 +14,12 @@ LL | drop(x1); ... LL | borrow(&*p1); | ---- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let p1 = &x1; +LL + let p1 = x1.clone(); + | error[E0505]: cannot move out of `x2` because it is borrowed --> $DIR/borrowck-multiple-captures.rs:12:19 @@ -30,6 +36,12 @@ LL | drop(x2); ... LL | borrow(&*p2); | ---- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let p2 = &x2; +LL + let p2 = x2.clone(); + | error[E0382]: use of moved value: `x1` --> $DIR/borrowck-multiple-captures.rs:27:19 @@ -93,6 +105,12 @@ LL | drop(x); ... LL | borrow(&*p); | --- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let p = &x; +LL + let p = x.clone(); + | error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:52:14 diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr index 723b19f4124..1602058c183 100644 --- a/tests/ui/borrowck/borrowck-overloaded-call.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr @@ -29,6 +29,12 @@ LL | s(" world".to_string()); | - value moved here LL | s(" world".to_string()); | ^ value used here after move + | +note: if `SFnOnce` implemented `Clone`, you could clone the value + --> $DIR/borrowck-overloaded-call.rs:41:1 + | +LL | struct SFnOnce { + | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr index b4106702cd1..3e874ed1a2f 100644 --- a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr @@ -8,6 +8,10 @@ help: consider borrowing here | LL | let bad = &v[0]; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let bad = v[0].clone(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-return.stderr b/tests/ui/borrowck/borrowck-return.stderr index a1bc3008ea8..f680b9af4f0 100644 --- a/tests/ui/borrowck/borrowck-return.stderr +++ b/tests/ui/borrowck/borrowck-return.stderr @@ -8,8 +8,8 @@ LL | return x; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-storage-dead.stderr b/tests/ui/borrowck/borrowck-storage-dead.stderr index a08e2a7b535..5f29c61c7eb 100644 --- a/tests/ui/borrowck/borrowck-storage-dead.stderr +++ b/tests/ui/borrowck/borrowck-storage-dead.stderr @@ -8,8 +8,8 @@ LL | let _ = x + 1; | help: consider assigning a value | -LL | let x: i32 = 0; - | +++ +LL | let x: i32 = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs index 1f6ed6d46aa..f0d067477c6 100644 --- a/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs +++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs @@ -2,20 +2,63 @@ // move, when the struct implements Drop. struct B; -struct S { a: isize, b: B } -impl Drop for S { fn drop(&mut self) { } } +struct S<K> { a: isize, b: B, c: K } +impl<K> Drop for S<K> { fn drop(&mut self) { } } -struct T { a: isize, mv: Box<isize> } +struct T { a: isize, b: Box<isize> } impl Drop for T { fn drop(&mut self) { } } -fn f(s0:S) { - let _s2 = S{a: 2, ..s0}; - //~^ ERROR [E0509] +struct V<K> { a: isize, b: Box<isize>, c: K } +impl<K> Drop for V<K> { fn drop(&mut self) { } } + +#[derive(Clone)] +struct Clonable; + +mod not_all_clone { + use super::*; + fn a(s0: S<()>) { + let _s2 = S { a: 2, ..s0 }; + //~^ ERROR [E0509] + } + fn b(s0: S<B>) { + let _s2 = S { a: 2, ..s0 }; + //~^ ERROR [E0509] + //~| ERROR [E0509] + } + fn c<K: Clone>(s0: S<K>) { + let _s2 = S { a: 2, ..s0 }; + //~^ ERROR [E0509] + //~| ERROR [E0509] + } } +mod all_clone { + use super::*; + fn a(s0: T) { + let _s2 = T { a: 2, ..s0 }; + //~^ ERROR [E0509] + } + + fn b(s0: T) { + let _s2 = T { ..s0 }; + //~^ ERROR [E0509] + } + + fn c(s0: T) { + let _s2 = T { a: 2, b: s0.b }; + //~^ ERROR [E0509] + } + + fn d<K: Clone>(s0: V<K>) { + let _s2 = V { a: 2, ..s0 }; + //~^ ERROR [E0509] + //~| ERROR [E0509] + } -fn g(s0:T) { - let _s2 = T{a: 2, ..s0}; - //~^ ERROR [E0509] + fn e(s0: V<Clonable>) { + let _s2 = V { a: 2, ..s0 }; + //~^ ERROR [E0509] + //~| ERROR [E0509] + } } fn main() { } diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr index af32f279100..bc11204acf2 100644 --- a/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr +++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr @@ -1,21 +1,191 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:12:15 +error[E0509]: cannot move out of type `S<()>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:20:19 | -LL | let _s2 = S{a: 2, ..s0}; - | ^^^^^^^^^^^^^ - | | - | cannot move out of here - | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait +LL | let _s2 = S { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait + | +note: `B` doesn't implement `Copy` or `Clone` + --> $DIR/borrowck-struct-update-with-dtor.rs:4:1 + | +LL | struct B; + | ^^^^^^^^ +help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = S { a: 2, b: s0.b.clone(), ..s0 }; + | +++++++++++++++++ + +error[E0509]: cannot move out of type `S<B>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:24:19 + | +LL | let _s2 = S { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait + | +note: `B` doesn't implement `Copy` or `Clone` + --> $DIR/borrowck-struct-update-with-dtor.rs:4:1 + | +LL | struct B; + | ^^^^^^^^ +help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = S { a: 2, b: s0.b.clone(), c: s0.c.clone() }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0509]: cannot move out of type `S<B>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:24:19 + | +LL | let _s2 = S { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.c` has type `B`, which does not implement the `Copy` trait + | +note: `B` doesn't implement `Copy` or `Clone` + --> $DIR/borrowck-struct-update-with-dtor.rs:4:1 + | +LL | struct B; + | ^^^^^^^^ +help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = S { a: 2, b: s0.b.clone(), c: s0.c.clone() }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:29:19 + | +LL | let _s2 = S { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait + | +note: `B` doesn't implement `Copy` or `Clone` + --> $DIR/borrowck-struct-update-with-dtor.rs:4:1 + | +LL | struct B; + | ^^^^^^^^ +help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = S { a: 2, b: s0.b.clone(), ..s0 }; + | +++++++++++++++++ + +error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:29:19 + | +LL | let _s2 = S { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = S { a: 2, c: s0.c.clone(), ..s0 }; + | +++++++++++++++++ + +error[E0509]: cannot move out of type `T`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:37:19 + | +LL | let _s2 = T { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = T { a: 2, b: s0.b.clone() }; + | ~~~~~~~~~~~~~~~~~ + +error[E0509]: cannot move out of type `T`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:42:19 + | +LL | let _s2 = T { ..s0 }; + | ^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = T { b: s0.b.clone(), ..s0 }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0509]: cannot move out of type `T`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:17:15 + --> $DIR/borrowck-struct-update-with-dtor.rs:47:32 + | +LL | let _s2 = T { a: 2, b: s0.b }; + | ^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _s2 = T { a: 2, b: s0.b.clone() }; + | ++++++++ + +error[E0509]: cannot move out of type `V<K>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:52:19 + | +LL | let _s2 = V { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = V { a: 2, b: s0.b.clone(), ..s0 }; + | +++++++++++++++++ + +error[E0509]: cannot move out of type `V<K>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:52:19 + | +LL | let _s2 = V { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = V { a: 2, c: s0.c.clone(), ..s0 }; + | +++++++++++++++++ + +error[E0509]: cannot move out of type `V<Clonable>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:58:19 + | +LL | let _s2 = V { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _s2 = V { a: 2, b: s0.b.clone(), ..s0 }; + | +++++++++++++++++ + +error[E0509]: cannot move out of type `V<Clonable>`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:58:19 + | +LL | let _s2 = V { a: 2, ..s0 }; + | ^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.c` has type `Clonable`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax | -LL | let _s2 = T{a: 2, ..s0}; - | ^^^^^^^^^^^^^ - | | - | cannot move out of here - | move occurs because `s0.mv` has type `Box<isize>`, which does not implement the `Copy` trait +LL | let _s2 = V { a: 2, c: s0.c.clone(), ..s0 }; + | +++++++++++++++++ -error: aborting due to 2 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0509`. diff --git a/tests/ui/borrowck/borrowck-unary-move.stderr b/tests/ui/borrowck/borrowck-unary-move.stderr index e6c3869f67a..598ecb53778 100644 --- a/tests/ui/borrowck/borrowck-unary-move.stderr +++ b/tests/ui/borrowck/borrowck-unary-move.stderr @@ -9,6 +9,12 @@ LL | free(x); | ^ move out of `x` occurs here LL | *y | -- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = &*x; +LL + let y = x.clone(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-unboxed-closures.stderr b/tests/ui/borrowck/borrowck-unboxed-closures.stderr index 3634676463c..a4513bd614e 100644 --- a/tests/ui/borrowck/borrowck-unboxed-closures.stderr +++ b/tests/ui/borrowck/borrowck-unboxed-closures.stderr @@ -29,15 +29,13 @@ LL | f(1, 2); LL | f(1, 2); | ^ value used here after move | -note: this value implements `FnOnce`, which causes it to be moved when called - --> $DIR/borrowck-unboxed-closures.rs:11:5 +note: `FnOnce` closures can only be called once + --> $DIR/borrowck-unboxed-closures.rs:10:8 | +LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | f(1, 2); - | ^ -help: consider further restricting this bound - | -LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) { - | ++++++ + | ------- this value implements `FnOnce`, which causes it to be moved when called error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.stderr b/tests/ui/borrowck/borrowck-uninit-after-item.stderr index 06bb419aa3b..c6d52a049d2 100644 --- a/tests/ui/borrowck/borrowck-uninit-after-item.stderr +++ b/tests/ui/borrowck/borrowck-uninit-after-item.stderr @@ -9,8 +9,8 @@ LL | baz(bar); | help: consider assigning a value | -LL | let bar = 0; - | +++ +LL | let bar = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr index fdbb451bde4..aaa33f08ff5 100644 --- a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr +++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr @@ -8,8 +8,8 @@ LL | x += 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:9:5 @@ -21,8 +21,8 @@ LL | x -= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:12:5 @@ -34,8 +34,8 @@ LL | x *= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:15:5 @@ -47,8 +47,8 @@ LL | x /= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:18:5 @@ -60,8 +60,8 @@ LL | x %= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:21:5 @@ -73,8 +73,8 @@ LL | x ^= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:24:5 @@ -86,8 +86,8 @@ LL | x &= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:27:5 @@ -99,8 +99,8 @@ LL | x |= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:30:5 @@ -112,8 +112,8 @@ LL | x <<= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:33:5 @@ -125,8 +125,8 @@ LL | x >>= 1; | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error: aborting due to 10 previous errors diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr index 73fded7545c..d6759b8e1cf 100644 --- a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr +++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr @@ -8,8 +8,8 @@ LL | let _y = &**x; | help: consider assigning a value | -LL | let x: &&Box<i32> = todo!(); - | +++++++++ +LL | let x: &&Box<i32> = &&Box::new(42); + | ++++++++++++++++ error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-ref-chain.rs:11:14 @@ -21,7 +21,7 @@ LL | let _y = &**x; | help: consider assigning a value | -LL | let x: &&S<i32, i32> = todo!(); +LL | let x: &&S<i32, i32> = &&value; | +++++++++ error[E0381]: used binding `x` isn't initialized @@ -34,8 +34,8 @@ LL | let _y = &**x; | help: consider assigning a value | -LL | let x: &&i32 = todo!(); - | +++++++++ +LL | let x: &&i32 = &&42; + | ++++++ error[E0381]: partially assigned binding `a` isn't fully initialized --> $DIR/borrowck-uninit-ref-chain.rs:18:5 diff --git a/tests/ui/borrowck/borrowck-uninit.stderr b/tests/ui/borrowck/borrowck-uninit.stderr index 1e004baa143..9538baeafd1 100644 --- a/tests/ui/borrowck/borrowck-uninit.stderr +++ b/tests/ui/borrowck/borrowck-uninit.stderr @@ -8,8 +8,8 @@ LL | foo(x); | help: consider assigning a value | -LL | let x: isize = 0; - | +++ +LL | let x: isize = 42; + | ++++ error[E0381]: used binding `a` isn't initialized --> $DIR/borrowck-uninit.rs:14:32 diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed b/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed new file mode 100644 index 00000000000..947c7f5b744 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed @@ -0,0 +1,11 @@ +//@ run-rustfix +#[allow(unused_mut)] +fn test() { + let w: &mut [isize] = &mut []; + w[5] = 0; //~ ERROR [E0381] + + let mut w: &mut [isize] = &mut []; + w[5] = 0; //~ ERROR [E0381] +} + +fn main() { test(); } diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs index d30b1de5cd0..a00fda60abb 100644 --- a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs +++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs @@ -1,3 +1,5 @@ +//@ run-rustfix +#[allow(unused_mut)] fn test() { let w: &mut [isize]; w[5] = 0; //~ ERROR [E0381] diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr index 18e808f10d0..6ec4390ae8d 100644 --- a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr +++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr @@ -1,5 +1,5 @@ error[E0381]: used binding `w` isn't initialized - --> $DIR/borrowck-use-in-index-lvalue.rs:3:5 + --> $DIR/borrowck-use-in-index-lvalue.rs:5:5 | LL | let w: &mut [isize]; | - binding declared here but left uninitialized @@ -8,11 +8,11 @@ LL | w[5] = 0; | help: consider assigning a value | -LL | let w: &mut [isize] = todo!(); +LL | let w: &mut [isize] = &mut []; | +++++++++ error[E0381]: used binding `w` isn't initialized - --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 + --> $DIR/borrowck-use-in-index-lvalue.rs:8:5 | LL | let mut w: &mut [isize]; | ----- binding declared here but left uninitialized @@ -21,7 +21,7 @@ LL | w[5] = 0; | help: consider assigning a value | -LL | let mut w: &mut [isize] = todo!(); +LL | let mut w: &mut [isize] = &mut []; | +++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed new file mode 100644 index 00000000000..f6ea5f0b6b8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed @@ -0,0 +1,12 @@ +// Variation on `borrowck-use-uninitialized-in-cast` in which we do a +// trait cast from an uninitialized source. Issue #20791. +//@ run-rustfix +#![allow(unused_variables, dead_code)] + +trait Foo { fn dummy(&self) { } } +impl Foo for i32 { } + +fn main() { + let x: &i32 = &42; + let y = x as *const dyn Foo; //~ ERROR [E0381] +} diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs index 3ce72161814..a384fdbf950 100644 --- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs @@ -1,5 +1,7 @@ // Variation on `borrowck-use-uninitialized-in-cast` in which we do a // trait cast from an uninitialized source. Issue #20791. +//@ run-rustfix +#![allow(unused_variables, dead_code)] trait Foo { fn dummy(&self) { } } impl Foo for i32 { } diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr index dcbaa75333e..ef04979f1cd 100644 --- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr @@ -1,5 +1,5 @@ error[E0381]: used binding `x` isn't initialized - --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13 + --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:11:13 | LL | let x: &i32; | - binding declared here but left uninitialized @@ -8,8 +8,8 @@ LL | let y = x as *const dyn Foo; | help: consider assigning a value | -LL | let x: &i32 = todo!(); - | +++++++++ +LL | let x: &i32 = &42; + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed new file mode 100644 index 00000000000..9c72015d747 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed @@ -0,0 +1,10 @@ +// Check that we detect unused values that are cast to other things. +// The problem was specified to casting to `*`, as creating unsafe +// pointers was not being fully checked. Issue #20791. +//@ run-rustfix +#![allow(unused_variables)] + +fn main() { + let x: &i32 = &42; + let y = x as *const i32; //~ ERROR [E0381] +} diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs index a355a546dc6..290deb0f257 100644 --- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs @@ -1,6 +1,8 @@ // Check that we detect unused values that are cast to other things. // The problem was specified to casting to `*`, as creating unsafe // pointers was not being fully checked. Issue #20791. +//@ run-rustfix +#![allow(unused_variables)] fn main() { let x: &i32; diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr index 7ccf6a4c3fc..22a3b721179 100644 --- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr @@ -1,5 +1,5 @@ error[E0381]: used binding `x` isn't initialized - --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13 + --> $DIR/borrowck-use-uninitialized-in-cast.rs:9:13 | LL | let x: &i32; | - binding declared here but left uninitialized @@ -8,8 +8,8 @@ LL | let y = x as *const i32; | help: consider assigning a value | -LL | let x: &i32 = todo!(); - | +++++++++ +LL | let x: &i32 = &42; + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs index 1bda7a49713..ec074d2cf1c 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -47,6 +47,7 @@ fn c() { //~| NOTE cannot move out of here //~| NOTE move occurs because //~| HELP consider borrowing here + //~| HELP consider cloning } fn d() { @@ -66,6 +67,7 @@ fn d() { //~| NOTE cannot move out of here //~| NOTE move occurs because //~| HELP consider borrowing here + //~| HELP consider cloning } fn e() { @@ -86,6 +88,7 @@ fn e() { //~| NOTE cannot move out of here //~| NOTE move occurs because //~| HELP consider borrowing here + //~| HELP consider cloning } fn main() {} diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 024cb006c26..fff997fd555 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -53,9 +53,13 @@ help: consider borrowing here | LL | let a = &vec[0]; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = vec[0].clone(); + | ++++++++ error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:56:11 | LL | match vec { | ^^^ cannot move out of here @@ -73,7 +77,7 @@ LL + [ | error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:65:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:66:13 | LL | let a = vec[0]; | ^^^^^^ @@ -85,9 +89,13 @@ help: consider borrowing here | LL | let a = &vec[0]; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = vec[0].clone(); + | ++++++++ error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:74:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:76:11 | LL | match vec { | ^^^ cannot move out of here @@ -106,7 +114,7 @@ LL + [_a, _b, _c] => {} | error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:85:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:87:13 | LL | let a = vec[0]; | ^^^^^^ @@ -118,6 +126,10 @@ help: consider borrowing here | LL | let a = &vec[0]; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = vec[0].clone(); + | ++++++++ error: aborting due to 8 previous errors diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr index ee4fcadf55a..f0eaf4bac7d 100644 --- a/tests/ui/borrowck/clone-on-ref.stderr +++ b/tests/ui/borrowck/clone-on-ref.stderr @@ -52,6 +52,11 @@ LL | LL | println!("{b:?}"); | ----- borrow later used here | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/clone-on-ref.rs:19:1 + | +LL | struct A; + | ^^^^^^^^ help: consider annotating `A` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/borrowck/clone-span-on-try-operator.fixed b/tests/ui/borrowck/clone-span-on-try-operator.fixed index 59253c98079..59a162e72c1 100644 --- a/tests/ui/borrowck/clone-span-on-try-operator.fixed +++ b/tests/ui/borrowck/clone-span-on-try-operator.fixed @@ -7,5 +7,5 @@ impl Foo { } fn main() { let foo = &Foo; - <Foo as Clone>::clone(&(*foo)).foo(); //~ ERROR cannot move out + <Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out } diff --git a/tests/ui/borrowck/clone-span-on-try-operator.stderr b/tests/ui/borrowck/clone-span-on-try-operator.stderr index adf84e49a9f..c2c63f94943 100644 --- a/tests/ui/borrowck/clone-span-on-try-operator.stderr +++ b/tests/ui/borrowck/clone-span-on-try-operator.stderr @@ -15,6 +15,11 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | <Foo as Clone>::clone(&(*foo)).foo(); | +++++++++++++++++++++++ + +help: consider cloning the value if the performance cost is acceptable + | +LL - (*foo).foo(); +LL + foo.clone().foo(); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr index 1f32ece3d3d..b4775496f4f 100644 --- a/tests/ui/borrowck/issue-101119.stderr +++ b/tests/ui/borrowck/issue-101119.stderr @@ -4,11 +4,25 @@ error[E0382]: use of moved value: `state` LL | fn fill_memory_blocks_mt(state: &mut State) { | ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait LL | loop { + | ---- inside of this loop LL | once(move || { | ^^^^^^^ value moved into closure here, in previous iteration of loop LL | LL | fill_segment(state); | ----- use occurs due to use in closure + | +note: consider changing this parameter type in function `fill_segment` to borrow instead if owning the value isn't necessary + --> $DIR/issue-101119.rs:14:20 + | +LL | fn fill_segment(_: &mut State) {} + | ------------ ^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function +note: if `State` implemented `Clone`, you could clone the value + --> $DIR/issue-101119.rs:1:1 + | +LL | struct State; + | ^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-103250.stderr b/tests/ui/borrowck/issue-103250.stderr index b7ece5d971d..104bded5b0b 100644 --- a/tests/ui/borrowck/issue-103250.stderr +++ b/tests/ui/borrowck/issue-103250.stderr @@ -9,8 +9,8 @@ LL | Err(last_error) | help: consider assigning a value | -LL | let mut last_error: Box<dyn std::error::Error> = todo!(); - | +++++++++ +LL | let mut last_error: Box<dyn std::error::Error> = Box::new(value); + | +++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr index 7a281e8aa30..94421c35c65 100644 --- a/tests/ui/borrowck/issue-103624.stderr +++ b/tests/ui/borrowck/issue-103624.stderr @@ -9,6 +9,12 @@ LL | spawn_blocking(move || { LL | LL | self.b; | ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait + | +note: if `StructB` implemented `Clone`, you could clone the value + --> $DIR/issue-103624.rs:23:1 + | +LL | struct StructB {} + | ^^^^^^^^^^^^^^ error[E0521]: borrowed data escapes outside of method --> $DIR/issue-103624.rs:14:9 diff --git a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr index ab42205d510..701f00d079d 100644 --- a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr +++ b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr @@ -11,6 +11,11 @@ note: `Example::<E, FakeParam>::change` takes ownership of the receiver `self`, | LL | unsafe fn change<NewFakeParam>(self) -> Example<E, NewFakeParam> { | ^^^^ +note: if `Example<E, NoLifetime>` implemented `Clone`, you could clone the value + --> $DIR/issue-119915-bad-clone-suggestion.rs:3:1 + | +LL | struct Example<E, FakeParam>(PhantomData<(fn(E), fn(FakeParam))>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr index 5ca0a7fb885..e2c3a9d5a26 100644 --- a/tests/ui/borrowck/issue-17718-static-move.stderr +++ b/tests/ui/borrowck/issue-17718-static-move.stderr @@ -4,6 +4,11 @@ error[E0507]: cannot move out of static item `FOO` LL | let _a = FOO; | ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/issue-17718-static-move.rs:1:1 + | +LL | struct Foo; + | ^^^^^^^^^^ help: consider borrowing here | LL | let _a = &FOO; diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 97294afd3df..1da6f0bef02 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -19,6 +19,11 @@ error[E0507]: cannot move out of a mutable reference LL | let a = unsafe { *mut_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait | +note: if `T` implemented `Clone`, you could clone the value + --> $DIR/issue-20801.rs:3:1 + | +LL | struct T(u8); + | ^^^^^^^^ help: consider removing the dereference here | LL - let a = unsafe { *mut_ref() }; @@ -31,6 +36,11 @@ error[E0507]: cannot move out of a shared reference LL | let b = unsafe { *imm_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait | +note: if `T` implemented `Clone`, you could clone the value + --> $DIR/issue-20801.rs:3:1 + | +LL | struct T(u8); + | ^^^^^^^^ help: consider removing the dereference here | LL - let b = unsafe { *imm_ref() }; @@ -43,6 +53,11 @@ error[E0507]: cannot move out of a raw pointer LL | let c = unsafe { *mut_ptr() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait | +note: if `T` implemented `Clone`, you could clone the value + --> $DIR/issue-20801.rs:3:1 + | +LL | struct T(u8); + | ^^^^^^^^ help: consider removing the dereference here | LL - let c = unsafe { *mut_ptr() }; @@ -55,6 +70,11 @@ error[E0507]: cannot move out of a raw pointer LL | let d = unsafe { *const_ptr() }; | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait | +note: if `T` implemented `Clone`, you could clone the value + --> $DIR/issue-20801.rs:3:1 + | +LL | struct T(u8); + | ^^^^^^^^ help: consider removing the dereference here | LL - let d = unsafe { *const_ptr() }; diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr index 58d1c8c0f73..216f8d49b1b 100644 --- a/tests/ui/borrowck/issue-24267-flow-exit.stderr +++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr @@ -10,8 +10,8 @@ LL | println!("{}", x); = 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) help: consider assigning a value | -LL | let x: i32 = 0; - | +++ +LL | let x: i32 = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/issue-24267-flow-exit.rs:18:20 @@ -25,8 +25,8 @@ LL | println!("{}", x); = 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) help: consider assigning a value | -LL | let x: i32 = 0; - | +++ +LL | let x: i32 = 42; + | ++++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr index e19f37538c1..8705b8450fc 100644 --- a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr +++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr @@ -9,8 +9,8 @@ LL | ref u if true => {} | help: consider assigning a value | -LL | let e: i32 = 0; - | +++ +LL | let e: i32 = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr index f032ea779dd..0e4a8d42f6e 100644 --- a/tests/ui/borrowck/issue-64453.stderr +++ b/tests/ui/borrowck/issue-64453.stderr @@ -22,6 +22,11 @@ error[E0507]: cannot move out of static item `settings_dir` | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let settings_data = from_string(settings_dir.clone()); + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.stderr b/tests/ui/borrowck/issue-87456-point-to-closure.stderr index a15909df07b..a0c7cac2add 100644 --- a/tests/ui/borrowck/issue-87456-point-to-closure.stderr +++ b/tests/ui/borrowck/issue-87456-point-to-closure.stderr @@ -14,6 +14,10 @@ help: consider borrowing here | LL | let _foo: String = &val; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let _foo: String = val.clone(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/let_underscore_temporary.rs b/tests/ui/borrowck/let_underscore_temporary.rs index 0a24df08925..d1bdabd4eca 100644 --- a/tests/ui/borrowck/let_underscore_temporary.rs +++ b/tests/ui/borrowck/let_underscore_temporary.rs @@ -7,8 +7,9 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 - //~^ ERROR temporary value dropped while borrowed + let a = 0; + &a + //~^ ERROR does not live long enough }; let _ = if let Some(ref s) = num { s } else { &0 }; let _ = if let Some(mut s) = num { @@ -21,8 +22,9 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 - //~^ ERROR temporary value dropped while borrowed + let a = 0; + &a + //~^ ERROR does not live long enough }; } @@ -33,8 +35,9 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 - //~^ ERROR temporary value dropped while borrowed + let a = 0; + &a + //~^ ERROR does not live long enough }; let _: _ = if let Some(ref s) = num { s } else { &0 }; let _: _ = if let Some(mut s) = num { @@ -47,8 +50,9 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 - //~^ ERROR temporary value dropped while borrowed + let a = 0; + &a + //~^ ERROR does not live long enough }; } @@ -63,8 +67,9 @@ fn matched(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 - //~^ ERROR temporary value dropped while borrowed + let a = 0; + &a + //~^ ERROR does not live long enough } { _ => {} }; @@ -83,8 +88,9 @@ fn matched(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 - //~^ ERROR temporary value dropped while borrowed + let a = 0; + &a + //~^ ERROR does not live long enough } { _ => {} }; diff --git a/tests/ui/borrowck/let_underscore_temporary.stderr b/tests/ui/borrowck/let_underscore_temporary.stderr index 6bccf329181..90b3462ebf8 100644 --- a/tests/ui/borrowck/let_underscore_temporary.stderr +++ b/tests/ui/borrowck/let_underscore_temporary.stderr @@ -1,117 +1,69 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/let_underscore_temporary.rs:10:14 +error[E0597]: `a` does not live long enough + --> $DIR/let_underscore_temporary.rs:11:9 | -LL | let _ = if let Some(s) = &mut num { - | _____________- -LL | | *s += 1; -LL | | s -LL | | } else { -LL | | &mut 0 - | | ^ creates a temporary value which is freed while still in use -LL | | -LL | | }; - | | - - | | | - | |_____temporary value is freed at the end of this statement - | borrow later used here - | - = note: consider using a `let` binding to create a longer lived value +LL | let a = 0; + | - binding `a` declared here +LL | &a + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `a` dropped here while still borrowed -error[E0716]: temporary value dropped while borrowed - --> $DIR/let_underscore_temporary.rs:24:14 - | -LL | let _ = if let Some(ref mut s) = num { - | _____________- -LL | | *s += 1; -LL | | s -LL | | } else { -LL | | &mut 0 - | | ^ creates a temporary value which is freed while still in use -LL | | -LL | | }; - | | - - | | | - | |_____temporary value is freed at the end of this statement - | borrow later used here +error[E0597]: `a` does not live long enough + --> $DIR/let_underscore_temporary.rs:26:9 | - = note: consider using a `let` binding to create a longer lived value +LL | let a = 0; + | - binding `a` declared here +LL | &a + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `a` dropped here while still borrowed -error[E0716]: temporary value dropped while borrowed - --> $DIR/let_underscore_temporary.rs:36:14 - | -LL | let _: _ = if let Some(s) = &mut num { - | ________________- -LL | | *s += 1; -LL | | s -LL | | } else { -LL | | &mut 0 - | | ^ creates a temporary value which is freed while still in use -LL | | -LL | | }; - | | - - | | | - | |_____temporary value is freed at the end of this statement - | borrow later used here +error[E0597]: `a` does not live long enough + --> $DIR/let_underscore_temporary.rs:39:9 | - = note: consider using a `let` binding to create a longer lived value +LL | let a = 0; + | - binding `a` declared here +LL | &a + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `a` dropped here while still borrowed -error[E0716]: temporary value dropped while borrowed - --> $DIR/let_underscore_temporary.rs:50:14 +error[E0597]: `a` does not live long enough + --> $DIR/let_underscore_temporary.rs:54:9 | -LL | let _: _ = if let Some(ref mut s) = num { - | ________________- -LL | | *s += 1; -LL | | s -LL | | } else { -LL | | &mut 0 - | | ^ creates a temporary value which is freed while still in use -LL | | -LL | | }; - | | - - | | | - | |_____temporary value is freed at the end of this statement - | borrow later used here - | - = note: consider using a `let` binding to create a longer lived value +LL | let a = 0; + | - binding `a` declared here +LL | &a + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `a` dropped here while still borrowed -error[E0716]: temporary value dropped while borrowed - --> $DIR/let_underscore_temporary.rs:66:14 - | -LL | match if let Some(s) = &mut num { - | ___________- -LL | | *s += 1; -LL | | s -LL | | } else { -LL | | &mut 0 - | | ^ creates a temporary value which is freed while still in use -LL | | -LL | | } { - | | - - | | | - | |_____temporary value is freed at the end of this statement - | borrow later used here +error[E0597]: `a` does not live long enough + --> $DIR/let_underscore_temporary.rs:71:9 | - = note: consider using a `let` binding to create a longer lived value +LL | let a = 0; + | - binding `a` declared here +LL | &a + | ^^ borrowed value does not live long enough +LL | +LL | } { + | - `a` dropped here while still borrowed -error[E0716]: temporary value dropped while borrowed - --> $DIR/let_underscore_temporary.rs:86:14 - | -LL | match if let Some(ref mut s) = num { - | ___________- -LL | | *s += 1; -LL | | s -LL | | } else { -LL | | &mut 0 - | | ^ creates a temporary value which is freed while still in use -LL | | -LL | | } { - | | - - | | | - | |_____temporary value is freed at the end of this statement - | borrow later used here +error[E0597]: `a` does not live long enough + --> $DIR/let_underscore_temporary.rs:92:9 | - = note: consider using a `let` binding to create a longer lived value +LL | let a = 0; + | - binding `a` declared here +LL | &a + | ^^ borrowed value does not live long enough +LL | +LL | } { + | - `a` dropped here while still borrowed error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0716`. +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr index 0d5edadcb46..43f4e820857 100644 --- a/tests/ui/borrowck/move-error-in-promoted-2.stderr +++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr @@ -6,6 +6,12 @@ LL | &([S][0],); | | | cannot move out of here | move occurs because value has type `S`, which does not implement the `Copy` trait + | +note: if `S` implemented `Clone`, you could clone the value + --> $DIR/move-error-in-promoted-2.rs:3:1 + | +LL | struct S; + | ^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/move-error-in-promoted.stderr b/tests/ui/borrowck/move-error-in-promoted.stderr index 03c0297c5a9..8d42df24e27 100644 --- a/tests/ui/borrowck/move-error-in-promoted.stderr +++ b/tests/ui/borrowck/move-error-in-promoted.stderr @@ -6,6 +6,11 @@ LL | let _ = S1(C[0]).clone(); | | | cannot move out of here | move occurs because value has type `S2`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _ = S1(C[0].clone()).clone(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr index 83f9e19aa0d..40b64398aef 100644 --- a/tests/ui/borrowck/move-error-snippets.stderr +++ b/tests/ui/borrowck/move-error-snippets.stderr @@ -9,6 +9,11 @@ LL | let a = $c; LL | sss!(); | ------ in this macro invocation | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-error-snippets.rs:9:1 + | +LL | struct A; + | ^^^^^^^^ = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider borrowing here | diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr index 70078582713..c951ce8e3cd 100644 --- a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr +++ b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -3,24 +3,48 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference | LL | *u.a | ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *u.a +LL + u.a.clone() + | error[E0507]: cannot move out of `*u.b` which is behind a mutable reference --> $DIR/move-from-union-field-issue-66500.rs:16:5 | LL | *u.b | ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *u.b +LL + u.b.clone() + | error[E0507]: cannot move out of `*u.c` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:20:5 | LL | *u.c | ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *u.c +LL + u.c.clone() + | error[E0507]: cannot move out of `*u.d` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:24:5 | LL | *u.d | ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *u.d +LL + u.d.clone() + | error: aborting due to 4 previous errors diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr index 6619fb42c28..a4e70b50646 100644 --- a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr +++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr @@ -3,12 +3,24 @@ error[E0507]: cannot move out of a shared reference | LL | static Y: usize = get(*&X); | ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/move-in-static-initializer-issue-38520.rs:5:1 + | +LL | struct Foo(usize); + | ^^^^^^^^^^ error[E0507]: cannot move out of a shared reference --> $DIR/move-in-static-initializer-issue-38520.rs:13:22 | LL | const Z: usize = get(*&X); | ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/move-in-static-initializer-issue-38520.rs:5:1 + | +LL | struct Foo(usize); + | ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr index 92acba640d7..4305539f1b6 100644 --- a/tests/ui/borrowck/suggest-assign-rvalue.stderr +++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr @@ -8,8 +8,8 @@ LL | apple(chaenomeles); | help: consider assigning a value | -LL | let chaenomeles = 0; - | +++ +LL | let chaenomeles = 42; + | ++++ error[E0381]: used binding `my_float` isn't initialized --> $DIR/suggest-assign-rvalue.rs:23:30 @@ -22,8 +22,8 @@ LL | println!("my_float: {}", my_float); = 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) help: consider assigning a value | -LL | let my_float: f32 = 0.0; - | +++++ +LL | let my_float: f32 = 3.14159; + | +++++++++ error[E0381]: used binding `demo` isn't initialized --> $DIR/suggest-assign-rvalue.rs:26:28 @@ -50,8 +50,8 @@ LL | println!("demo_no: {:?}", demo_no); = 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) help: consider assigning a value | -LL | let demo_no: DemoNoDef = todo!(); - | +++++++++ +LL | let demo_no: DemoNoDef = value; + | +++++++ error[E0381]: used binding `arr` isn't initialized --> $DIR/suggest-assign-rvalue.rs:34:27 @@ -64,7 +64,7 @@ LL | println!("arr: {:?}", arr); = 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) help: consider assigning a value | -LL | let arr: [i32; 5] = todo!(); +LL | let arr: [i32; 5] = [42; 5]; | +++++++++ error[E0381]: used binding `foo` isn't initialized @@ -106,8 +106,8 @@ LL | println!("my_int: {}", *my_int); = 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) help: consider assigning a value | -LL | let my_int: &i32 = todo!(); - | +++++++++ +LL | let my_int: &i32 = &42; + | +++++ error[E0381]: used binding `hello` isn't initialized --> $DIR/suggest-assign-rvalue.rs:49:27 @@ -120,8 +120,8 @@ LL | println!("hello: {}", hello); = 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) help: consider assigning a value | -LL | let hello: &str = todo!(); - | +++++++++ +LL | let hello: &str = ""; + | ++++ error[E0381]: used binding `never` isn't initialized --> $DIR/suggest-assign-rvalue.rs:53:27 diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.rs b/tests/ui/borrowck/trait-impl-argument-difference-ice.rs new file mode 100644 index 00000000000..872507cc4de --- /dev/null +++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.rs @@ -0,0 +1,25 @@ +// Issue https://github.com/rust-lang/rust/issues/123414 +trait MemoryUnit { + extern "C" fn read_word(&mut self) -> u8; + extern "C" fn read_dword(Self::Assoc<'_>) -> u16; + //~^ WARNING anonymous parameters are deprecated and will be removed in the next edition + //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + //~| ERROR associated type `Assoc` not found for `Self` +} + +struct ROM {} + +impl MemoryUnit for ROM { +//~^ ERROR not all trait items implemented, missing: `read_word` + extern "C" fn read_dword(&'_ self) -> u16 { + //~^ ERROR method `read_dword` has a `&self` declaration in the impl, but not in the trait + let a16 = self.read_word() as u16; + //~^ ERROR cannot borrow `*self` as mutable, as it is behind a `&` reference + let b16 = self.read_word() as u16; + //~^ ERROR cannot borrow `*self` as mutable, as it is behind a `&` reference + + (b16 << 8) | a16 + } +} + +pub fn main() {} diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr new file mode 100644 index 00000000000..5c70eccfbd3 --- /dev/null +++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr @@ -0,0 +1,60 @@ +warning: anonymous parameters are deprecated and will be removed in the next edition + --> $DIR/trait-impl-argument-difference-ice.rs:4:30 + | +LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; + | ^^^^^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: Self::Assoc<'_>` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686> + = note: `#[warn(anonymous_parameters)]` on by default + +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/trait-impl-argument-difference-ice.rs:4:36 + | +LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; + | ^^^^^ associated type `Assoc` not found + +error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait + --> $DIR/trait-impl-argument-difference-ice.rs:14:5 + | +LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; + | ------------------------------------------------- trait method declared without `&self` +... +LL | extern "C" fn read_dword(&'_ self) -> u16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&self` used in impl + +error[E0046]: not all trait items implemented, missing: `read_word` + --> $DIR/trait-impl-argument-difference-ice.rs:12:1 + | +LL | extern "C" fn read_word(&mut self) -> u8; + | ----------------------------------------- `read_word` from trait +... +LL | impl MemoryUnit for ROM { + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation + +error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference + --> $DIR/trait-impl-argument-difference-ice.rs:16:19 + | +LL | let a16 = self.read_word() as u16; + | ^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition + | +LL | extern "C" fn read_dword(&'_ mut self) -> u16 { + | ~~~~~~~~~~~~ + +error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference + --> $DIR/trait-impl-argument-difference-ice.rs:18:19 + | +LL | let b16 = self.read_word() as u16; + | ^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition + | +LL | extern "C" fn read_dword(&'_ mut self) -> u16 { + | ~~~~~~~~~~~~ + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0046, E0185, E0220, E0596. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed index 8add3a5f2b6..3b4f7c8465c 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed @@ -9,7 +9,7 @@ fn call<F>(f: F) where F : Fn() { fn main() { let y = vec![format!("World")]; call(|| { - <Vec<String> as Clone>::clone(&y).into_iter(); + <Vec<String> as Clone>::clone(&y.clone()).into_iter(); //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure }); } diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index a2ff70255f5..177e9c8d248 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -16,6 +16,10 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | <Vec<String> as Clone>::clone(&y).into_iter(); | +++++++++++++++++++++++++++++++ + +help: consider cloning the value if the performance cost is acceptable + | +LL | y.clone().into_iter(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr index 8b8cea3fe84..53ff5f0107d 100644 --- a/tests/ui/box/leak-alloc.stderr +++ b/tests/ui/box/leak-alloc.stderr @@ -11,6 +11,12 @@ LL | drop(alloc); LL | LL | use_value(*theref) | ------- borrow later used here + | +note: if `Alloc` implemented `Clone`, you could clone the value + --> $DIR/leak-alloc.rs:8:1 + | +LL | struct Alloc {} + | ^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/btreemap/btreemap_dropck.stderr b/tests/ui/btreemap/btreemap_dropck.stderr index 805c2112bdc..873f8cf9a01 100644 --- a/tests/ui/btreemap/btreemap_dropck.stderr +++ b/tests/ui/btreemap/btreemap_dropck.stderr @@ -9,6 +9,12 @@ LL | drop(s); | ^ move out of `s` occurs here LL | } | - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap` + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]); +LL + let _map = BTreeMap::from_iter([((), PrintOnDrop(s.clone()))]); + | error: aborting due to 1 previous error diff --git a/tests/ui/cfg/cfg-attr-cfg.rs b/tests/ui/cfg/cfg-attr-cfg.rs index 5b49966d544..67d97e760d7 100644 --- a/tests/ui/cfg/cfg-attr-cfg.rs +++ b/tests/ui/cfg/cfg-attr-cfg.rs @@ -4,5 +4,5 @@ //@ pretty-expanded FIXME #23616 -#[cfg_attr(foo, cfg(bar))] +#[cfg_attr(FALSE, cfg(bar))] fn main() { } diff --git a/tests/ui/cfg/cfg-attr-crate.rs b/tests/ui/cfg/cfg-attr-crate.rs index 7868b006e27..444704d132a 100644 --- a/tests/ui/cfg/cfg-attr-crate.rs +++ b/tests/ui/cfg/cfg-attr-crate.rs @@ -3,6 +3,6 @@ //@ pretty-expanded FIXME #23616 -#![cfg_attr(not_used, no_core)] +#![cfg_attr(FALSE, no_core)] fn main() { } diff --git a/tests/ui/cfg/cfg-macros-notfoo.rs b/tests/ui/cfg/cfg-macros-notfoo.rs index c47f4332aa3..9feb06be73e 100644 --- a/tests/ui/cfg/cfg-macros-notfoo.rs +++ b/tests/ui/cfg/cfg-macros-notfoo.rs @@ -1,11 +1,9 @@ //@ run-pass -//@ compile-flags: // check that cfg correctly chooses between the macro impls (see also // cfg-macros-foo.rs) - -#[cfg(foo)] +#[cfg(FALSE)] #[macro_use] mod foo { macro_rules! bar { @@ -13,7 +11,7 @@ mod foo { } } -#[cfg(not(foo))] +#[cfg(not(FALSE))] #[macro_use] mod foo { macro_rules! bar { diff --git a/tests/ui/cfg/cfg-match-arm.rs b/tests/ui/cfg/cfg-match-arm.rs index a41337a19a3..e646a63b8fb 100644 --- a/tests/ui/cfg/cfg-match-arm.rs +++ b/tests/ui/cfg/cfg-match-arm.rs @@ -10,9 +10,9 @@ enum Foo { fn foo(f: Foo) { match f { Foo::Bar => {}, - #[cfg(not(asdfa))] + #[cfg(not(FALSE))] Foo::Baz => {}, - #[cfg(afsd)] + #[cfg(FALSE)] Basdfwe => {} } } diff --git a/tests/ui/cfg/cfg-panic-abort.rs b/tests/ui/cfg/cfg-panic-abort.rs index 49adfd55c68..448fde21086 100644 --- a/tests/ui/cfg/cfg-panic-abort.rs +++ b/tests/ui/cfg/cfg-panic-abort.rs @@ -2,15 +2,11 @@ //@ compile-flags: -C panic=abort //@ no-prefer-dynamic - #[cfg(panic = "unwind")] pub fn bad() -> i32 { } #[cfg(not(panic = "abort"))] pub fn bad() -> i32 { } -#[cfg(panic = "some_imaginary_future_panic_handler")] -pub fn bad() -> i32 { } - #[cfg(panic = "abort")] pub fn main() { } diff --git a/tests/ui/cfg/cfg-panic.rs b/tests/ui/cfg/cfg-panic.rs index 0f1f539ebe3..4e3ed0cd9c2 100644 --- a/tests/ui/cfg/cfg-panic.rs +++ b/tests/ui/cfg/cfg-panic.rs @@ -2,15 +2,11 @@ //@ compile-flags: -C panic=unwind //@ needs-unwind - #[cfg(panic = "abort")] pub fn bad() -> i32 { } #[cfg(not(panic = "unwind"))] pub fn bad() -> i32 { } -#[cfg(panic = "some_imaginary_future_panic_handler")] -pub fn bad() -> i32 { } - #[cfg(panic = "unwind")] pub fn main() { } diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 6de5eb5c4c6..9245f6d9757 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -7,49 +7,49 @@ fn main() { let a = 413; - #[cfg(unset)] + #[cfg(FALSE)] let a = (); assert_eq!(a, 413); let mut b = 612; - #[cfg(unset)] + #[cfg(FALSE)] { b = 1111; } assert_eq!(b, 612); - #[cfg(unset)] + #[cfg(FALSE)] undefined_fn(); - #[cfg(unset)] + #[cfg(FALSE)] undefined_macro!(); - #[cfg(unset)] + #[cfg(FALSE)] undefined_macro![]; - #[cfg(unset)] + #[cfg(FALSE)] undefined_macro!{}; // pretty printer bug... - // #[cfg(unset)] + // #[cfg(FALSE)] // undefined_macro!{} - let () = (#[cfg(unset)] 341,); // Should this also work on parens? - let t = (1, #[cfg(unset)] 3, 4); + let () = (#[cfg(FALSE)] 341,); // Should this also work on parens? + let t = (1, #[cfg(FALSE)] 3, 4); assert_eq!(t, (1, 4)); let f = |_: u32, _: u32| (); - f(2, 1, #[cfg(unset)] 6); + f(2, 1, #[cfg(FALSE)] 6); - let _: u32 = a.clone(#[cfg(unset)] undefined); + let _: u32 = a.clone(#[cfg(FALSE)] undefined); - let _: [(); 0] = [#[cfg(unset)] 126]; - let t = [#[cfg(unset)] 1, 2, 6]; + let _: [(); 0] = [#[cfg(FALSE)] 126]; + let t = [#[cfg(FALSE)] 1, 2, 6]; assert_eq!(t, [2, 6]); { let r; - #[cfg(unset)] + #[cfg(FALSE)] (r = 5); - #[cfg(not(unset))] + #[cfg(not(FALSE))] (r = 10); assert_eq!(r, 10); } @@ -69,13 +69,13 @@ fn main() { } } - let n = if_cfg!(unset? { + let n = if_cfg!(FALSE? { 413 } else { 612 }); - assert_eq!((#[cfg(unset)] 1, #[cfg(not(unset))] 2), (2,)); + assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,)); assert_eq!(n, 612); // check that lints work diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index f39663adda2..a4f334dd696 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -6,31 +6,31 @@ // Crate use statements -#[cfg(bogus)] +#[cfg(FALSE)] use flippity; -#[cfg(bogus)] +#[cfg(FALSE)] static b: bool = false; static b: bool = true; mod rustrt { - #[cfg(bogus)] + #[cfg(FALSE)] extern "C" { // This symbol doesn't exist and would be a link error if this // module was codegened - pub fn bogus(); + pub fn FALSE(); } extern "C" {} } -#[cfg(bogus)] +#[cfg(FALSE)] type t = isize; type t = bool; -#[cfg(bogus)] +#[cfg(FALSE)] enum tg { foo, } @@ -39,12 +39,12 @@ enum tg { bar, } -#[cfg(bogus)] +#[cfg(FALSE)] struct r { i: isize, } -#[cfg(bogus)] +#[cfg(FALSE)] fn r(i: isize) -> r { r { i: i } } @@ -57,11 +57,11 @@ fn r(i: isize) -> r { r { i: i } } -#[cfg(bogus)] +#[cfg(FALSE)] mod m { // This needs to parse but would fail in typeck. Since it's not in // the current config it should not be typechecked. - pub fn bogus() { + pub fn FALSE() { return 0; } } @@ -69,22 +69,22 @@ mod m { mod m { // Submodules have slightly different code paths than the top-level // module, so let's make sure this jazz works here as well - #[cfg(bogus)] + #[cfg(FALSE)] pub fn f() {} pub fn f() {} } -// Since the bogus configuration isn't defined main will just be +// Since the FALSE configuration isn't defined main will just be // parsed, but nothing further will be done with it -#[cfg(bogus)] +#[cfg(FALSE)] pub fn main() { panic!() } pub fn main() { // Exercise some of the configured items in ways that wouldn't be possible - // if they had the bogus definition + // if they had the FALSE definition assert!((b)); let _x: t = true; let _y: tg = tg::bar; @@ -93,14 +93,14 @@ pub fn main() { } fn test_in_fn_ctxt() { - #[cfg(bogus)] + #[cfg(FALSE)] fn f() { panic!() } fn f() {} f(); - #[cfg(bogus)] + #[cfg(FALSE)] static i: isize = 0; static i: isize = 1; assert_eq!(i, 1); @@ -109,7 +109,7 @@ fn test_in_fn_ctxt() { mod test_foreign_items { pub mod rustrt { extern "C" { - #[cfg(bogus)] + #[cfg(FALSE)] pub fn write() -> String; pub fn write() -> String; } @@ -117,7 +117,7 @@ mod test_foreign_items { } mod test_use_statements { - #[cfg(bogus)] + #[cfg(FALSE)] use flippity_foo; } @@ -127,24 +127,24 @@ mod test_methods { } impl Fooable for Foo { - #[cfg(bogus)] + #[cfg(FALSE)] fn what(&self) {} fn what(&self) {} - #[cfg(bogus)] + #[cfg(FALSE)] fn the(&self) {} fn the(&self) {} } trait Fooable { - #[cfg(bogus)] + #[cfg(FALSE)] fn what(&self); fn what(&self); - #[cfg(bogus)] + #[cfg(FALSE)] fn the(&self); fn the(&self); diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs index b9548e91183..9b3208cb87c 100644 --- a/tests/ui/cfg/diagnostics-reexport.rs +++ b/tests/ui/cfg/diagnostics-reexport.rs @@ -14,7 +14,7 @@ pub use a::x; //~| NOTE no `x` in `a` mod a { - #[cfg(no)] + #[cfg(FALSE)] pub fn x() {} //~^ NOTE found an item that was configured out } @@ -25,10 +25,10 @@ pub use b::{x, y}; //~| NOTE no `y` in `b` mod b { - #[cfg(no)] + #[cfg(FALSE)] pub fn x() {} //~^ NOTE found an item that was configured out - #[cfg(no)] + #[cfg(FALSE)] pub fn y() {} //~^ NOTE found an item that was configured out } diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index 011ef6e101d..493132d462a 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `FALSE` LL | #[cfg(FALSE)] | ^^^^^ | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(FALSE)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr index d6c377e21ad..09a1c950267 100644 --- a/tests/ui/check-cfg/cargo-feature.none.stderr +++ b/tests/ui/check-cfg/cargo-feature.none.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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`, `ub_checks`, `unix`, `windows` = help: consider using a Cargo feature instead or adding `println!("cargo:rustc-check-cfg=cfg(tokio_unstable)");` to the top of a `build.rs` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr index 11dfd4fa4b6..4db9c66fc86 100644 --- a/tests/ui/check-cfg/cargo-feature.some.stderr +++ b/tests/ui/check-cfg/cargo-feature.some.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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`, `ub_checks`, `unix`, `windows` = help: consider using a Cargo feature instead or adding `println!("cargo:rustc-check-cfg=cfg(tokio_unstable)");` to the top of a `build.rs` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration 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 index 7d374fc81d3..9c190117e74 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `value` LL | #[cfg(value)] | ^^^^^ | - = help: expected names are: `bar`, `bee`, `clippy`, `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: expected names are: `bar`, `bee`, `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(value)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default 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 index 13e6891c353..7113790b83a 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_value` LL | #[cfg(my_value)] | ^^^^^^^^ | - = help: expected names are: `bar`, `clippy`, `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: expected names are: `bar`, `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(my_value)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr index a2f9ccfec05..ba9f5f4acbd 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `linux` LL | #[cfg(linux)] | ^^^^^ help: found config with similar value: `target_os = "linux"` | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(linux)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index 37637e3b153..446b8f408e3 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `target_architecture` LL | #[cfg(target(os = "linux", architecture = "arm"))] | ^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr index 4f770e91c58..d2870263342 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index c7eaf435f75..b24b10bb615 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index c7eaf435f75..b24b10bb615 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr index 3ed5c77e2a4..6ca7ed93625 100644 --- a/tests/ui/check-cfg/exhaustive-names.stderr +++ b/tests/ui/check-cfg/exhaustive-names.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 007f9de0331..87fabf8245f 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -44,7 +44,7 @@ warning: unexpected `cfg` condition name: `uu` LL | #[cfg_attr(uu, test)] | ^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(uu)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr index f2660e4775b..1afdbe84d34 100644 --- a/tests/ui/check-cfg/stmt-no-ice.stderr +++ b/tests/ui/check-cfg/stmt-no-ice.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `crossbeam_loom` LL | #[cfg(crossbeam_loom)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(crossbeam_loom)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr index a0386403e25..467f9675f7f 100644 --- a/tests/ui/check-cfg/well-known-names.stderr +++ b/tests/ui/check-cfg/well-known-names.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition name: `features` LL | #[cfg(features = "foo")] | ^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `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: expected names are: `clippy`, `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`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(features, values("foo"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs index fa062a3fe2e..2758a793538 100644 --- a/tests/ui/check-cfg/well-known-values.rs +++ b/tests/ui/check-cfg/well-known-values.rs @@ -14,6 +14,7 @@ #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_target_thread_local)] +#![feature(cfg_ub_checks)] // This part makes sure that none of the well known names are // unexpected. @@ -71,6 +72,8 @@ //~^ WARN unexpected `cfg` condition value test = "_UNEXPECTED_VALUE", //~^ WARN unexpected `cfg` condition value + ub_checks = "_UNEXPECTED_VALUE", + //~^ WARN unexpected `cfg` condition value unix = "_UNEXPECTED_VALUE", //~^ WARN unexpected `cfg` condition value windows = "_UNEXPECTED_VALUE", diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 31553371101..729794150f6 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:26:5 + --> $DIR/well-known-values.rs:27:5 | LL | clippy = "_UNEXPECTED_VALUE", | ^^^^^^---------------------- @@ -11,7 +11,7 @@ LL | clippy = "_UNEXPECTED_VALUE", = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:28:5 + --> $DIR/well-known-values.rs:29:5 | LL | debug_assertions = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^---------------------- @@ -22,7 +22,7 @@ LL | debug_assertions = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:30:5 + --> $DIR/well-known-values.rs:31:5 | LL | doc = "_UNEXPECTED_VALUE", | ^^^---------------------- @@ -33,7 +33,7 @@ LL | doc = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:32:5 + --> $DIR/well-known-values.rs:33:5 | LL | doctest = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -44,7 +44,7 @@ LL | doctest = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:34:5 + --> $DIR/well-known-values.rs:35:5 | LL | miri = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -55,7 +55,7 @@ LL | miri = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:36:5 + --> $DIR/well-known-values.rs:37:5 | LL | overflow_checks = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^---------------------- @@ -66,7 +66,7 @@ LL | overflow_checks = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:38:5 + --> $DIR/well-known-values.rs:39:5 | LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | panic = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:40:5 + --> $DIR/well-known-values.rs:41:5 | LL | proc_macro = "_UNEXPECTED_VALUE", | ^^^^^^^^^^---------------------- @@ -86,7 +86,7 @@ LL | proc_macro = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:42:5 + --> $DIR/well-known-values.rs:43:5 | LL | relocation_model = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | relocation_model = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:44:5 + --> $DIR/well-known-values.rs:45:5 | LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | sanitize = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:46:5 + --> $DIR/well-known-values.rs:47:5 | LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | target_abi = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:48:5 + --> $DIR/well-known-values.rs:49:5 | LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | target_arch = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:50:5 + --> $DIR/well-known-values.rs:51:5 | LL | target_endian = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | target_endian = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:52:5 + --> $DIR/well-known-values.rs:53:5 | LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | target_env = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:54:5 + --> $DIR/well-known-values.rs:55:5 | LL | target_family = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | target_family = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:56:5 + --> $DIR/well-known-values.rs:57:5 | LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,7 +158,7 @@ LL | target_feature = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:58:5 + --> $DIR/well-known-values.rs:59:5 | LL | target_has_atomic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | target_has_atomic = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:60:5 + --> $DIR/well-known-values.rs:61:5 | LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:62:5 + --> $DIR/well-known-values.rs:63:5 | LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:64:5 + --> $DIR/well-known-values.rs:65:5 | LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -194,7 +194,7 @@ LL | target_os = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:66:5 + --> $DIR/well-known-values.rs:67:5 | LL | target_pointer_width = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ LL | target_pointer_width = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:68:5 + --> $DIR/well-known-values.rs:69:5 | LL | target_thread_local = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^---------------------- @@ -214,7 +214,7 @@ LL | target_thread_local = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:70:5 + --> $DIR/well-known-values.rs:71:5 | LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | target_vendor = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:72:5 + --> $DIR/well-known-values.rs:73:5 | LL | test = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -234,7 +234,18 @@ LL | test = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:74:5 + --> $DIR/well-known-values.rs:75:5 + | +LL | ub_checks = "_UNEXPECTED_VALUE", + | ^^^^^^^^^---------------------- + | | + | help: remove the value + | + = note: no expected value for `ub_checks` + = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration + +warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` + --> $DIR/well-known-values.rs:77:5 | LL | unix = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -245,7 +256,7 @@ LL | unix = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:76:5 + --> $DIR/well-known-values.rs:79:5 | LL | windows = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -256,7 +267,7 @@ LL | windows = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `linuz` - --> $DIR/well-known-values.rs:82:7 + --> $DIR/well-known-values.rs:85:7 | LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | ^^^^^^^^^^^^------- @@ -266,5 +277,5 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `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`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration -warning: 27 warnings emitted +warning: 28 warnings emitted diff --git a/tests/ui/check-static-recursion-foreign.rs b/tests/ui/check-static-recursion-foreign.rs index 97db47d0bd6..5a0ff7b5962 100644 --- a/tests/ui/check-static-recursion-foreign.rs +++ b/tests/ui/check-static-recursion-foreign.rs @@ -6,12 +6,9 @@ //@ pretty-expanded FIXME #23616 -#![feature(rustc_private)] - extern crate check_static_recursion_foreign_helper; -extern crate libc; -use libc::c_int; +use std::ffi::c_int; extern "C" { static test_static: c_int; diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/check-static-values-constraints.stderr index dee1f2b1210..fe5f2a34272 100644 --- a/tests/ui/check-static-values-constraints.stderr +++ b/tests/ui/check-static-values-constraints.stderr @@ -160,6 +160,10 @@ help: consider borrowing here | LL | &x | + +help: consider cloning the value if the performance cost is acceptable + | +LL | x.clone() + | ++++++++ error: aborting due to 17 previous errors diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr index 8a32f0d99e7..f8ed792e3c6 100644 --- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr @@ -79,8 +79,8 @@ LL | let c1 = || match x { }; | help: consider assigning a value | -LL | let x: u8 = 0; - | +++ +LL | let x: u8 = 42; + | ++++ error: aborting due to 8 previous errors diff --git a/tests/ui/closures/return-value-lifetime-error.fixed b/tests/ui/closures/return-value-lifetime-error.fixed new file mode 100644 index 00000000000..bf1f7e4a6cf --- /dev/null +++ b/tests/ui/closures/return-value-lifetime-error.fixed @@ -0,0 +1,16 @@ +//@ run-rustfix +use std::collections::HashMap; + +fn main() { + let vs = vec![0, 0, 1, 1, 3, 4, 5, 6, 3, 3, 3]; + + let mut counts = HashMap::new(); + for num in vs { + let count = counts.entry(num).or_insert(0); + *count += 1; + } + + let _ = counts.iter().max_by_key(|(_, v)| **v); + //~^ ERROR lifetime may not live long enough + //~| HELP dereference the return value +} diff --git a/tests/ui/closures/return-value-lifetime-error.rs b/tests/ui/closures/return-value-lifetime-error.rs new file mode 100644 index 00000000000..411c91f413e --- /dev/null +++ b/tests/ui/closures/return-value-lifetime-error.rs @@ -0,0 +1,16 @@ +//@ run-rustfix +use std::collections::HashMap; + +fn main() { + let vs = vec![0, 0, 1, 1, 3, 4, 5, 6, 3, 3, 3]; + + let mut counts = HashMap::new(); + for num in vs { + let count = counts.entry(num).or_insert(0); + *count += 1; + } + + let _ = counts.iter().max_by_key(|(_, v)| v); + //~^ ERROR lifetime may not live long enough + //~| HELP dereference the return value +} diff --git a/tests/ui/closures/return-value-lifetime-error.stderr b/tests/ui/closures/return-value-lifetime-error.stderr new file mode 100644 index 00000000000..a0ad127db28 --- /dev/null +++ b/tests/ui/closures/return-value-lifetime-error.stderr @@ -0,0 +1,16 @@ +error: lifetime may not live long enough + --> $DIR/return-value-lifetime-error.rs:13:47 + | +LL | let _ = counts.iter().max_by_key(|(_, v)| v); + | ------- ^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure is &'2 &i32 + | has type `&'1 (&i32, &i32)` + | +help: dereference the return value + | +LL | let _ = counts.iter().max_by_key(|(_, v)| **v); + | ++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed new file mode 100644 index 00000000000..0fa6ac1dd99 --- /dev/null +++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed @@ -0,0 +1,9 @@ +// Check that revisioned `run-rustfix` does not fail with issues related to `.` in crate name. +//@ revisions: foo +//@[foo] run-rustfix +#![deny(unused_variables)] + +fn main() { + let _x = 0usize; + //~^ ERROR unused variable: `x` +} diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr new file mode 100644 index 00000000000..74384ef24af --- /dev/null +++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr @@ -0,0 +1,14 @@ +error: unused variable: `x` + --> $DIR/run-rustfix-revisions.rs:7:9 + | +LL | let x = 0usize; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/run-rustfix-revisions.rs:4:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.rs b/tests/ui/compiletest-self-test/run-rustfix-revisions.rs new file mode 100644 index 00000000000..84c5b7a2d0a --- /dev/null +++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.rs @@ -0,0 +1,9 @@ +// Check that revisioned `run-rustfix` does not fail with issues related to `.` in crate name. +//@ revisions: foo +//@[foo] run-rustfix +#![deny(unused_variables)] + +fn main() { + let x = 0usize; + //~^ ERROR unused variable: `x` +} diff --git a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs index 72b0db5da84..bca29f0da2b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs +++ b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs @@ -1,13 +1,11 @@ // Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint. -//@ compile-flags: --cfg TRUE - #![deny(unused)] #[cfg_attr(FALSE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes fn _f() {} -#[cfg_attr(TRUE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes +#[cfg_attr(not(FALSE),)] //~ ERROR `#[cfg_attr]` does not expand to any attributes fn _g() {} fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr index 87b69881353..a858afe2f2b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr @@ -1,21 +1,21 @@ error: `#[cfg_attr]` does not expand to any attributes - --> $DIR/cfg-attr-empty-is-unused.rs:7:1 + --> $DIR/cfg-attr-empty-is-unused.rs:5:1 | LL | #[cfg_attr(FALSE,)] | ^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/cfg-attr-empty-is-unused.rs:5:9 + --> $DIR/cfg-attr-empty-is-unused.rs:3:9 | LL | #![deny(unused)] | ^^^^^^ = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` error: `#[cfg_attr]` does not expand to any attributes - --> $DIR/cfg-attr-empty-is-unused.rs:10:1 + --> $DIR/cfg-attr-empty-is-unused.rs:8:1 | -LL | #[cfg_attr(TRUE,)] - | ^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(not(FALSE),)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/conditional-compilation/cfg-generic-params.rs b/tests/ui/conditional-compilation/cfg-generic-params.rs index 76ba7f9b86e..2a83be21498 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.rs +++ b/tests/ui/conditional-compilation/cfg-generic-params.rs @@ -1,36 +1,36 @@ //@ compile-flags:--cfg yes -fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(no)] T>() {} -fn f_ty<#[cfg(no)] 'a: 'a, #[cfg(yes)] T>() {} +fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(FALSE)] T>() {} +fn f_ty<#[cfg(FALSE)] 'a: 'a, #[cfg(yes)] T>() {} -type FnGood = for<#[cfg(yes)] 'a, #[cfg(no)] T> fn(); // OK -type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn(); +type FnGood = for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> fn(); // OK +type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); //~^ ERROR only lifetime parameters can be used in this context -type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(no)] T> Copy; // OK -type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; +type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> Copy; // OK +type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; //~^ ERROR only lifetime parameters can be used in this context -struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(no)] T> u8: Copy; // OK -struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; +struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> u8: Copy; // OK +struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy; //~^ ERROR only lifetime parameters can be used in this context -fn f_lt_no<#[cfg_attr(no, unknown)] 'a>() {} // OK +fn f_lt_no<#[cfg_attr(FALSE, unknown)] 'a>() {} // OK fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} //~^ ERROR cannot find attribute `unknown` in this scope -fn f_ty_no<#[cfg_attr(no, unknown)] T>() {} // OK +fn f_ty_no<#[cfg_attr(FALSE, unknown)] T>() {} // OK fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} //~^ ERROR cannot find attribute `unknown` in this scope -type FnNo = for<#[cfg_attr(no, unknown)] 'a> fn(); // OK +type FnNo = for<#[cfg_attr(FALSE, unknown)] 'a> fn(); // OK type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); //~^ ERROR cannot find attribute `unknown` in this scope -type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK +type PolyNo = dyn for<#[cfg_attr(FALSE, unknown)] 'a> Copy; // OK type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; //~^ ERROR cannot find attribute `unknown` in this scope -struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK +struct WhereNo where for<#[cfg_attr(FALSE, unknown)] 'a> u8: Copy; // OK struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; //~^ ERROR cannot find attribute `unknown` in this scope diff --git a/tests/ui/conditional-compilation/cfg-generic-params.stderr b/tests/ui/conditional-compilation/cfg-generic-params.stderr index 4143e2019ae..563616be36b 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.stderr +++ b/tests/ui/conditional-compilation/cfg-generic-params.stderr @@ -29,30 +29,30 @@ LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; | ^^^^^^^ error[E0658]: only lifetime parameters can be used in this context - --> $DIR/cfg-generic-params.rs:7:45 + --> $DIR/cfg-generic-params.rs:7:48 | -LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn(); - | ^ +LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); + | ^ | = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information = help: add `#![feature(non_lifetime_binders)]` 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 lifetime parameters can be used in this context - --> $DIR/cfg-generic-params.rs:11:51 + --> $DIR/cfg-generic-params.rs:11:54 | -LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; - | ^ +LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; + | ^ | = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information = help: add `#![feature(non_lifetime_binders)]` 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 lifetime parameters can be used in this context - --> $DIR/cfg-generic-params.rs:15:54 + --> $DIR/cfg-generic-params.rs:15:57 | -LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; - | ^ +LL | struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy; + | ^ | = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.rs b/tests/ui/conditional-compilation/cfg-in-crate-1.rs index 59be27a065e..ecd3722bf4c 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.rs +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.rs @@ -1,3 +1,3 @@ //@ error-pattern: `main` function not found -#![cfg(bar)] +#![cfg(FALSE)] diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr index 98be6d01f1b..6067a3a921c 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr @@ -1,8 +1,8 @@ error[E0601]: `main` function not found in crate `cfg_in_crate_1` - --> $DIR/cfg-in-crate-1.rs:3:13 + --> $DIR/cfg-in-crate-1.rs:3:15 | -LL | #![cfg(bar)] - | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` +LL | #![cfg(FALSE)] + | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` error: aborting due to 1 previous error diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs index 0ddbd8a156d..ae85f38e645 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs @@ -2,10 +2,10 @@ #![feature(custom_test_frameworks)] fn main() { - let _ = #[cfg(unset)] (); + let _ = #[cfg(FALSE)] (); //~^ ERROR removing an expression is not supported in this position - let _ = 1 + 2 + #[cfg(unset)] 3; + let _ = 1 + 2 + #[cfg(FALSE)] 3; //~^ ERROR removing an expression is not supported in this position - let _ = [1, 2, 3][#[cfg(unset)] 1]; + let _ = [1, 2, 3][#[cfg(FALSE)] 1]; //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr index 933b7dc184a..06eaa59efdd 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr @@ -1,19 +1,19 @@ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:5:13 | -LL | let _ = #[cfg(unset)] (); +LL | let _ = #[cfg(FALSE)] (); | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:7:21 | -LL | let _ = 1 + 2 + #[cfg(unset)] 3; +LL | let _ = 1 + 2 + #[cfg(FALSE)] 3; | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:9:23 | -LL | let _ = [1, 2, 3][#[cfg(unset)] 1]; +LL | let _ = [1, 2, 3][#[cfg(FALSE)] 1]; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/const-arg-in-const-arg.rs b/tests/ui/const-generics/const-arg-in-const-arg.rs index 6d30943ab7e..27b74489fe8 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.rs +++ b/tests/ui/const-generics/const-arg-in-const-arg.rs @@ -2,8 +2,8 @@ // we use a single revision because this should have a `full` revision // but right now that ICEs and I(@BoxyUwU) could not get stderr normalization to work -#![cfg_attr(full, feature(generic_const_exprs))] -#![cfg_attr(full, allow(incomplete_features))] +// #![cfg_attr(full, feature(generic_const_exprs))] +// #![cfg_attr(full, allow(incomplete_features))] const fn foo<T>() -> usize { std::mem::size_of::<T>() } const fn bar<const N: usize>() -> usize { N } diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed b/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed new file mode 100644 index 00000000000..da48c62df21 --- /dev/null +++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed @@ -0,0 +1,6 @@ +//@ run-rustfix +pub struct X<const N: usize = { + let s: &'static str = ""; s.len() //~ ERROR E0381 +}>; + +fn main() {} diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.rs b/tests/ui/const-generics/const-generic-default-wont-borrowck.rs index e64adacac9f..0d7d87100b7 100644 --- a/tests/ui/const-generics/const-generic-default-wont-borrowck.rs +++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.rs @@ -1,4 +1,5 @@ -struct X<const N: usize = { +//@ run-rustfix +pub struct X<const N: usize = { let s: &'static str; s.len() //~ ERROR E0381 }>; diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr b/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr index 4cea35f1c8e..83e7f88eda7 100644 --- a/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr +++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr @@ -1,5 +1,5 @@ error[E0381]: used binding `s` isn't initialized - --> $DIR/const-generic-default-wont-borrowck.rs:2:26 + --> $DIR/const-generic-default-wont-borrowck.rs:3:26 | LL | let s: &'static str; s.len() | - ^ `*s` used here but it isn't initialized @@ -8,8 +8,8 @@ LL | let s: &'static str; s.len() | help: consider assigning a value | -LL | let s: &'static str = todo!(); s.len() - | +++++++++ +LL | let s: &'static str = ""; s.len() + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/doesnt_infer.rs b/tests/ui/const-generics/defaults/doesnt_infer.rs index 9c59e672d8e..e14c08fc148 100644 --- a/tests/ui/const-generics/defaults/doesnt_infer.rs +++ b/tests/ui/const-generics/defaults/doesnt_infer.rs @@ -9,5 +9,5 @@ impl<const N: u32> Foo<N> { fn main() { let foo = Foo::<1>::foo(); let foo = Foo::foo(); - //~^ error: type annotations needed for `Foo<N>` + //~^ ERROR type annotations needed for `Foo<_>` } diff --git a/tests/ui/const-generics/defaults/doesnt_infer.stderr b/tests/ui/const-generics/defaults/doesnt_infer.stderr index 65ee0ecfdc5..93d58603397 100644 --- a/tests/ui/const-generics/defaults/doesnt_infer.stderr +++ b/tests/ui/const-generics/defaults/doesnt_infer.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Foo<N>` +error[E0282]: type annotations needed for `Foo<_>` --> $DIR/doesnt_infer.rs:11:9 | LL | let foo = Foo::foo(); 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 5b296a14869..5ee42c19dd3 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations needed for `Mask<_, N>` +error[E0283]: type annotations needed for `Mask<_, _>` --> $DIR/issue-91614.rs:6:9 | LL | let y = Mask::<_, _>::splat(false); 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 f27d52a1437..5cda4681b5c 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 @@ -18,7 +18,7 @@ help: try adding a `where` bound LL | pub const fn new() -> Self where [(); Self::SIZE]: { | +++++++++++++++++++++++ -error[E0282]: type annotations needed for `ArrayHolder<X>` +error[E0282]: type annotations needed for `ArrayHolder<_>` --> $DIR/issue-62504.rs:26:9 | LL | let mut array = ArrayHolder::new(); 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 1664669eee0..beb159779ff 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,7 +22,7 @@ note: tuple struct defined here LL | struct ArrayHolder<const X: usize>([u32; X]); | ^^^^^^^^^^^ -error[E0282]: type annotations needed for `ArrayHolder<X>` +error[E0282]: type annotations needed for `ArrayHolder<_>` --> $DIR/issue-62504.rs:26:9 | LL | let mut array = ArrayHolder::new(); diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs new file mode 100644 index 00000000000..dd0b1e8c9f7 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs @@ -0,0 +1,15 @@ +// ICE unknown alias DefKind: AnonConst +// issue: rust-lang/rust#116710 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct A<const N: u32 = 1, const M: u32 = u8>; +//~^ ERROR expected value, found builtin type `u8` + +trait Trait {} +impl<const N: u32> Trait for A<N> {} + +impl<const N: u32> Trait for A<N> {} +//~^ ERROR conflicting implementations of trait `Trait` for type `A<_>` + +pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr new file mode 100644 index 00000000000..80ac96d4870 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr @@ -0,0 +1,19 @@ +error[E0423]: expected value, found builtin type `u8` + --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:6:43 + | +LL | struct A<const N: u32 = 1, const M: u32 = u8>; + | ^^ not a value + +error[E0119]: conflicting implementations of trait `Trait` for type `A<_>` + --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:12:1 + | +LL | impl<const N: u32> Trait for A<N> {} + | --------------------------------- first implementation here +LL | +LL | impl<const N: u32> Trait for A<N> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0423. +For more information about an error, try `rustc --explain E0119`. 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 96fd9ed5f04..0a28c5b80bf 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -4,6 +4,8 @@ error: internal compiler error[E0080]: evaluation of constant value failed LL | const X: i32 = 1 / 0; | ^^^^^ attempt to divide `1_i32` by zero +note: please make sure that you have updated to the latest nightly + 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` diff --git a/tests/ui/consts/const_fn_unsize.rs b/tests/ui/consts/const_fn_unsize.rs index f96a6088fd3..15d717e7e12 100644 --- a/tests/ui/consts/const_fn_unsize.rs +++ b/tests/ui/consts/const_fn_unsize.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(slice_ptr_len)] use std::ptr::NonNull; diff --git a/tests/ui/consts/do-not-ice-on-field-access-of-err-type.rs b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.rs new file mode 100644 index 00000000000..a2e336b703e --- /dev/null +++ b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.rs @@ -0,0 +1,9 @@ +trait Foo {} +impl<T> Foo for T {} + +fn main() { + let array = [(); { loop {} }]; //~ ERROR constant evaluation is taking a long time + + let tup = (7,); + let x: &dyn Foo = &tup.0; +} diff --git a/tests/ui/consts/do-not-ice-on-field-access-of-err-type.stderr b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.stderr new file mode 100644 index 00000000000..02b8904fbde --- /dev/null +++ b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.stderr @@ -0,0 +1,17 @@ +error: constant evaluation is taking a long time + --> $DIR/do-not-ice-on-field-access-of-err-type.rs:5:24 + | +LL | let array = [(); { loop {} }]; + | ^^^^^^^ + | + = 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/do-not-ice-on-field-access-of-err-type.rs:5:22 + | +LL | let array = [(); { loop {} }]; + | ^^^^^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr index 5a38d023d6f..ccaed03b4c1 100644 --- a/tests/ui/consts/issue-78655.stderr +++ b/tests/ui/consts/issue-78655.stderr @@ -8,8 +8,8 @@ LL | &x | help: consider assigning a value | -LL | let x = 0; - | +++ +LL | let x = 42; + | ++++ error: could not evaluate constant pattern --> $DIR/issue-78655.rs:7:9 diff --git a/tests/ui/consts/value-suggestion-ice-123906.rs b/tests/ui/consts/value-suggestion-ice-123906.rs new file mode 100644 index 00000000000..531bbc15852 --- /dev/null +++ b/tests/ui/consts/value-suggestion-ice-123906.rs @@ -0,0 +1,8 @@ +fn as_chunks<const N: usize>() -> [u8; N] { + loop { + break; + //~^ ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/consts/value-suggestion-ice-123906.stderr b/tests/ui/consts/value-suggestion-ice-123906.stderr new file mode 100644 index 00000000000..8e2c316400d --- /dev/null +++ b/tests/ui/consts/value-suggestion-ice-123906.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/value-suggestion-ice-123906.rs:3:9 + | +LL | fn as_chunks<const N: usize>() -> [u8; N] { + | ------- expected `[u8; ]` because of this return type +LL | loop { + | ---- this loop is expected to be of type `[u8; N]` +LL | break; + | ^^^^^ expected `[u8; N]`, found `()` + | +help: give the `break` a value of the expected type + | +LL | break value; + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs b/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs new file mode 100644 index 00000000000..65da2c3f5c7 --- /dev/null +++ b/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only + +#[no_mangle] +pub fn baz<F>(mut cb: F, data: u32) where F: FnMut(u32) { + cb(data); +} + +#[no_mangle] +pub fn bar<F>(cb: F, data: u32) where F: FnMut(u32) { + baz(cb, data); +} + +#[no_mangle] +pub fn foo<F>(cb: F, data: u32) where F: FnMut(u32) { + bar(cb, data); +} + +pub fn capture_backtrace() -> std::backtrace::Backtrace { + let mut bt = None; + foo(|_| bt = Some(std::backtrace::Backtrace::capture()), 42); + bt.unwrap() +} diff --git a/tests/ui/debuginfo/backtrace-line-tables-only.rs b/tests/ui/debuginfo/backtrace-line-tables-only.rs new file mode 100644 index 00000000000..044f59e483a --- /dev/null +++ b/tests/ui/debuginfo/backtrace-line-tables-only.rs @@ -0,0 +1,49 @@ +// Test that when debug info only includes line tables that backtrace is still generated +// successfully. +// Original test: +// <https://github.com/rust-lang/backtrace-rs/tree/6fa4b85b9962c3e1be8c2e5cc605cd078134152b/crates/line-tables-only>. +// Part of <https://github.com/rust-lang/rust/issues/122899> porting some backtrace tests to rustc. +// This test diverges from the original test in that it now uses a Rust library auxiliary because +// rustc now has `-Cdebuginfo=line-tables-only`. +// ignore-tidy-linelength +//@ run-pass +//@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only +//@ ignore-android FIXME #17520 +//@ ignore-fuchsia Backtraces not symbolized +//@ needs-unwind +//@ aux-build: line-tables-only-helper.rs + +#![feature(backtrace_frames)] + +extern crate line_tables_only_helper; + +use std::backtrace::Backtrace; + +fn assert_contains( + backtrace: &Backtrace, + expected_name: &str, + expected_file: &str, + expected_line: u32, +) { + // FIXME(jieyouxu): fix this ugly fragile test when `BacktraceFrame` has accessors like... + // `symbols()`. + let backtrace = format!("{:#?}", backtrace); + eprintln!("{}", backtrace); + assert!(backtrace.contains(expected_name), "backtrace does not contain expected name {}", expected_name); + assert!(backtrace.contains(expected_file), "backtrace does not contain expected file {}", expected_file); + assert!(backtrace.contains(&expected_line.to_string()), "backtrace does not contain expected line {}", expected_line); +} + +fn main() { + std::env::set_var("RUST_BACKTRACE", "1"); + let backtrace = line_tables_only_helper::capture_backtrace(); + + // FIXME(jieyouxu): for some forsaken reason on i686-msvc `foo` doesn't have an entry in the + // line tables? + #[cfg(not(all(target_pointer_width = "32", target_env = "msvc")))] + { + assert_contains(&backtrace, "foo", "line-tables-only-helper.rs", 5); + } + assert_contains(&backtrace, "bar", "line-tables-only-helper.rs", 10); + assert_contains(&backtrace, "baz", "line-tables-only-helper.rs", 15); +} diff --git a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr index c538061b365..2de4ee4eabd 100644 --- a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr @@ -8,6 +8,10 @@ LL | struct StructA(String); | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -19,6 +23,10 @@ LL | struct StructA(String); | = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -30,6 +38,10 @@ LL | struct StructA(String); | = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -41,6 +53,10 @@ LL | struct StructA(String); | = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -52,6 +68,10 @@ LL | struct StructA(String); | = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -63,6 +83,10 @@ LL | struct StructA(String); | = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -74,6 +98,10 @@ LL | struct StructA(String); | = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -85,6 +113,10 @@ LL | struct StructA(String); | = note: `#[derive(Hash)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 @@ -96,78 +128,142 @@ LL | struct StructA(String); | = note: `#[derive(Clone)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | struct StructA(String.clone()); + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:28:9 | LL | self.0 | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | self.0.clone() + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:38:20 | LL | let x = &{ self.0 }; | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let x = &{ self.0.clone() }; + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:45:12 | LL | ({ self.0 }) == ({ other.0 }) | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | ({ self.0.clone() }) == ({ other.0 }) + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:45:28 | LL | ({ self.0 }) == ({ other.0 }) | ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | ({ self.0 }) == ({ other.0.clone() }) + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:53:36 | LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | PartialOrd::partial_cmp(&{ self.0.clone() }, &{ other.0 }) + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:53:49 | LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0.clone() }) + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:68:20 | LL | let x = &{ self.0 }; | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let x = &{ self.0.clone() }; + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:75:12 | LL | ({ self.0 }) == ({ other.0 }) | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | ({ self.0.clone() }) == ({ other.0 }) + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:75:28 | LL | ({ self.0 }) == ({ other.0 }) | ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | ({ self.0 }) == ({ other.0.clone() }) + | ++++++++ error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:83:36 | LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | PartialOrd::partial_cmp(&{ self.0.clone() }, &{ other.0 }) + | ++++++++ error[E0507]: cannot move out of `other` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:83:49 | LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0.clone() }) + | ++++++++ error[E0507]: cannot move out of `arg` which is behind a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:92:5 | LL | arg.0 | ^^^^^ move occurs because `arg.0` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | arg.0.clone() + | ++++++++ error: aborting due to 21 previous errors diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 151be6901b0..26ac532263f 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -36,6 +36,11 @@ LL | #[repr(packed)] LL | struct X(Y); | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait | +note: if `Y` implemented `Clone`, you could clone the value + --> $DIR/deriving-with-repr-packed.rs:16:1 + | +LL | struct Y(usize); + | ^^^^^^^^ = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index a0274527975..9f8a9f30ff6 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -1005,8 +1005,8 @@ impl ::core::default::Default for Fieldless { impl ::core::hash::Hash for Fieldless { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state) + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state) } } #[automatically_derived] @@ -1015,9 +1015,9 @@ impl ::core::marker::StructuralPartialEq for Fieldless { } impl ::core::cmp::PartialEq for Fieldless { #[inline] fn eq(&self, other: &Fieldless) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr } } #[automatically_derived] @@ -1032,18 +1032,18 @@ impl ::core::cmp::PartialOrd for Fieldless { #[inline] fn partial_cmp(&self, other: &Fieldless) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr) } } #[automatically_derived] impl ::core::cmp::Ord for Fieldless { #[inline] fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) } } @@ -1096,8 +1096,8 @@ impl ::core::default::Default for Mixed { impl ::core::hash::Hash for Mixed { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state); + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state); match self { Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state), Mixed::S { d1: __self_0, d2: __self_1 } => { @@ -1114,9 +1114,9 @@ impl ::core::marker::StructuralPartialEq for Mixed { } impl ::core::cmp::PartialEq for Mixed { #[inline] fn eq(&self, other: &Mixed) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag && + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => *__self_0 == *__arg1_0, @@ -1143,8 +1143,8 @@ impl ::core::cmp::PartialOrd for Mixed { #[inline] fn partial_cmp(&self, other: &Mixed) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), @@ -1157,8 +1157,8 @@ impl ::core::cmp::PartialOrd for Mixed { cmp => cmp, }, _ => - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, - &__arg1_tag), + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr), } } } @@ -1166,9 +1166,9 @@ impl ::core::cmp::PartialOrd for Mixed { impl ::core::cmp::Ord for Mixed { #[inline] fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) { ::core::cmp::Ordering::Equal => match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => @@ -1225,8 +1225,8 @@ impl ::core::fmt::Debug for Fielded { impl ::core::hash::Hash for Fielded { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state); + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state); match self { Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state), Fielded::Y(__self_0) => ::core::hash::Hash::hash(__self_0, state), @@ -1240,9 +1240,9 @@ impl ::core::marker::StructuralPartialEq for Fielded { } impl ::core::cmp::PartialEq for Fielded { #[inline] fn eq(&self, other: &Fielded) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag && + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => *__self_0 == *__arg1_0, @@ -1270,8 +1270,8 @@ impl ::core::cmp::PartialOrd for Fielded { #[inline] fn partial_cmp(&self, other: &Fielded) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), @@ -1280,8 +1280,8 @@ impl ::core::cmp::PartialOrd for Fielded { (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), _ => - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, - &__arg1_tag), + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr), } } } @@ -1289,9 +1289,9 @@ impl ::core::cmp::PartialOrd for Fielded { impl ::core::cmp::Ord for Fielded { #[inline] fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) { ::core::cmp::Ordering::Equal => match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => @@ -1346,8 +1346,8 @@ impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for EnumGeneric<T, U> { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state); + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state); match self { EnumGeneric::One(__self_0) => ::core::hash::Hash::hash(__self_0, state), @@ -1363,9 +1363,9 @@ impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq> ::core::cmp::PartialEq for EnumGeneric<T, U> { #[inline] fn eq(&self, other: &EnumGeneric<T, U>) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag && + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => *__self_0 == *__arg1_0, @@ -1392,16 +1392,16 @@ impl<T: ::core::cmp::PartialOrd, U: ::core::cmp::PartialOrd> #[inline] fn partial_cmp(&self, other: &EnumGeneric<T, U>) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), _ => - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, - &__arg1_tag), + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr), } } } @@ -1410,9 +1410,9 @@ impl<T: ::core::cmp::Ord, U: ::core::cmp::Ord> ::core::cmp::Ord for EnumGeneric<T, U> { #[inline] fn cmp(&self, other: &EnumGeneric<T, U>) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) { ::core::cmp::Ordering::Equal => match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => diff --git a/tests/ui/does-nothing.rs b/tests/ui/does-nothing.rs deleted file mode 100644 index e4992e2cfd3..00000000000 --- a/tests/ui/does-nothing.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); } -//~^ ERROR cannot find value `this_does_nothing_what_the` in this scope diff --git a/tests/ui/does-nothing.stderr b/tests/ui/does-nothing.stderr deleted file mode 100644 index d5ea3626e81..00000000000 --- a/tests/ui/does-nothing.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0425]: cannot find value `this_does_nothing_what_the` in this scope - --> $DIR/does-nothing.rs:1:32 - | -LL | fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/drop/repeat-drop-2.stderr b/tests/ui/drop/repeat-drop-2.stderr index 009a2057212..cea7baf6976 100644 --- a/tests/ui/drop/repeat-drop-2.stderr +++ b/tests/ui/drop/repeat-drop-2.stderr @@ -32,8 +32,8 @@ LL | let _ = [x; 0]; | help: consider assigning a value | -LL | let x: u8 = 0; - | +++ +LL | let x: u8 = 42; + | ++++ error: aborting due to 3 previous errors diff --git a/tests/ui/dropck/drop-with-active-borrows-1.stderr b/tests/ui/dropck/drop-with-active-borrows-1.stderr index 229514c6fee..7d1633267f0 100644 --- a/tests/ui/dropck/drop-with-active-borrows-1.stderr +++ b/tests/ui/dropck/drop-with-active-borrows-1.stderr @@ -9,6 +9,11 @@ LL | drop(a); | ^ move out of `a` occurs here LL | for s in &b { | -- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let b: Vec<&str> = a.clone().lines().collect(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs index b346953e187..ad47553d5b7 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.rs +++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs @@ -6,6 +6,6 @@ fn main() { let x = 0; let y = &x as *const _; + //~^ error: type annotations needed let _ = y.is_null(); - //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699] } diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr index 663843ad7bc..2792d1e7400 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr +++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr @@ -1,9 +1,17 @@ -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type - --> $DIR/edition-raw-pointer-method-2018.rs:9:15 +error[E0282]: type annotations needed for `*const _` + --> $DIR/edition-raw-pointer-method-2018.rs:8:9 | +LL | let y = &x as *const _; + | ^ +LL | LL | let _ = y.is_null(); - | ^^^^^^^ + | ------- cannot call a method on a raw pointer with an unknown pointee type + | +help: consider giving `y` an explicit type, where the placeholders `_` are specified + | +LL | let y: *const _ = &x as *const _; + | ++++++++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0699`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/error-codes/E0069.stderr b/tests/ui/error-codes/E0069.stderr index 20ff8c258a0..ef6c411ae58 100644 --- a/tests/ui/error-codes/E0069.stderr +++ b/tests/ui/error-codes/E0069.stderr @@ -5,6 +5,11 @@ LL | fn foo() -> u8 { | -- expected `u8` because of this return type LL | return; | ^^^^^^ return type is not `()` + | +help: give the `return` a value of the expected type + | +LL | return 42; + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0449.fixed b/tests/ui/error-codes/E0449.fixed new file mode 100644 index 00000000000..c7b4566303d --- /dev/null +++ b/tests/ui/error-codes/E0449.fixed @@ -0,0 +1,18 @@ +//@ run-rustfix + +#![allow(warnings)] + +struct Bar; + +trait Foo { + fn foo(); +} + + impl Bar {} //~ ERROR E0449 + + impl Foo for Bar { //~ ERROR E0449 + fn foo() {} //~ ERROR E0449 +} + +fn main() { +} diff --git a/tests/ui/error-codes/E0449.rs b/tests/ui/error-codes/E0449.rs index eba0d479e97..32d9b35169c 100644 --- a/tests/ui/error-codes/E0449.rs +++ b/tests/ui/error-codes/E0449.rs @@ -1,3 +1,7 @@ +//@ run-rustfix + +#![allow(warnings)] + struct Bar; trait Foo { diff --git a/tests/ui/error-codes/E0449.stderr b/tests/ui/error-codes/E0449.stderr index cf41bcce8c2..c6a98269a19 100644 --- a/tests/ui/error-codes/E0449.stderr +++ b/tests/ui/error-codes/E0449.stderr @@ -1,24 +1,24 @@ error[E0449]: visibility qualifiers are not permitted here - --> $DIR/E0449.rs:7:1 + --> $DIR/E0449.rs:11:1 | LL | pub impl Bar {} - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual impl items instead error[E0449]: visibility qualifiers are not permitted here - --> $DIR/E0449.rs:9:1 + --> $DIR/E0449.rs:13:1 | LL | pub impl Foo for Bar { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/E0449.rs:10:5 + --> $DIR/E0449.rs:14:5 | LL | pub fn foo() {} - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr index c8a48961cb3..900cb706bd9 100644 --- a/tests/ui/error-codes/E0504.stderr +++ b/tests/ui/error-codes/E0504.stderr @@ -13,6 +13,12 @@ LL | println!("child function: {}", fancy_num.num); ... LL | println!("main function: {}", fancy_ref.num); | ------------- borrow later used here + | +note: if `FancyNum` implemented `Clone`, you could clone the value + --> $DIR/E0504.rs:1:1 + | +LL | struct FancyNum { + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr index 250680d2c1c..ce01298a70d 100644 --- a/tests/ui/error-codes/E0505.stderr +++ b/tests/ui/error-codes/E0505.stderr @@ -10,6 +10,12 @@ LL | eat(x); | ^ move out of `x` occurs here LL | _ref_to_val.use_ref(); | ----------- borrow later used here + | +note: if `Value` implemented `Clone`, you could clone the value + --> $DIR/E0505.rs:1:1 + | +LL | struct Value {} + | ^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0507.stderr b/tests/ui/error-codes/E0507.stderr index 767fedfccbf..60a4daa9d38 100644 --- a/tests/ui/error-codes/E0507.stderr +++ b/tests/ui/error-codes/E0507.stderr @@ -11,6 +11,11 @@ note: `TheDarkKnight::nothing_is_true` takes ownership of the receiver `self`, w | LL | fn nothing_is_true(self) {} | ^^^^ +note: if `TheDarkKnight` implemented `Clone`, you could clone the value + --> $DIR/E0507.rs:3:1 + | +LL | struct TheDarkKnight; + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0508-fail.stderr b/tests/ui/error-codes/E0508-fail.stderr index 1153b1d09c7..96d3bcb67a5 100644 --- a/tests/ui/error-codes/E0508-fail.stderr +++ b/tests/ui/error-codes/E0508-fail.stderr @@ -7,6 +7,11 @@ LL | let _value = array[0]; | cannot move out of here | move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/E0508-fail.rs:1:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ help: consider borrowing here | LL | let _value = &array[0]; diff --git a/tests/ui/error-codes/E0508.stderr b/tests/ui/error-codes/E0508.stderr index 4c864e24144..c1b622e2432 100644 --- a/tests/ui/error-codes/E0508.stderr +++ b/tests/ui/error-codes/E0508.stderr @@ -7,6 +7,11 @@ LL | let _value = array[0]; | cannot move out of here | move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/E0508.rs:1:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ help: consider borrowing here | LL | let _value = &array[0]; diff --git a/tests/ui/error-codes/E0509.stderr b/tests/ui/error-codes/E0509.stderr index 59843a5491a..75c372d0440 100644 --- a/tests/ui/error-codes/E0509.stderr +++ b/tests/ui/error-codes/E0509.stderr @@ -7,6 +7,11 @@ LL | let fancy_field = drop_struct.fancy; | cannot move out of here | move occurs because `drop_struct.fancy` has type `FancyNum`, which does not implement the `Copy` trait | +note: if `FancyNum` implemented `Clone`, you could clone the value + --> $DIR/E0509.rs:1:1 + | +LL | struct FancyNum { + | ^^^^^^^^^^^^^^^ help: consider borrowing here | LL | let fancy_field = &drop_struct.fancy; diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs index 72d83215ade..c139b347d99 100644 --- a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs +++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs @@ -25,7 +25,7 @@ fn bar() { let x: () = true; // Should not error due to the #[cfg(FALSE)] } - #[cfg_attr(not(unset_attr), cfg(FALSE))] + #[cfg_attr(not(FALSE), cfg(FALSE))] if true { let a: () = true; // Should not error due to the applied #[cfg(FALSE)] } diff --git a/tests/ui/extern/extern-const.fixed b/tests/ui/extern/extern-const.fixed index 9f695eaafd0..be3a893e669 100644 --- a/tests/ui/extern/extern-const.fixed +++ b/tests/ui/extern/extern-const.fixed @@ -6,12 +6,12 @@ //@ run-rustfix //@ compile-flags: -g -#![feature(rustc_private)] -extern crate libc; + +use std::ffi::c_int; #[link(name = "rust_test_helpers", kind = "static")] extern "C" { - static rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` + static rust_dbg_static_mut: c_int; //~ ERROR extern items cannot be `const` } fn main() { diff --git a/tests/ui/extern/extern-const.rs b/tests/ui/extern/extern-const.rs index e412dff8895..4c9e26d693f 100644 --- a/tests/ui/extern/extern-const.rs +++ b/tests/ui/extern/extern-const.rs @@ -6,12 +6,12 @@ //@ run-rustfix //@ compile-flags: -g -#![feature(rustc_private)] -extern crate libc; + +use std::ffi::c_int; #[link(name = "rust_test_helpers", kind = "static")] extern "C" { - const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` + const rust_dbg_static_mut: c_int; //~ ERROR extern items cannot be `const` } fn main() { diff --git a/tests/ui/extern/extern-const.stderr b/tests/ui/extern/extern-const.stderr index 07485cf9994..31954ca2c84 100644 --- a/tests/ui/extern/extern-const.stderr +++ b/tests/ui/extern/extern-const.stderr @@ -1,7 +1,7 @@ error: extern items cannot be `const` --> $DIR/extern-const.rs:14:11 | -LL | const rust_dbg_static_mut: libc::c_int; +LL | const rust_dbg_static_mut: c_int; | ------^^^^^^^^^^^^^^^^^^^ | | | help: try using a static value: `static` diff --git a/tests/ui/feature-gates/feature-gate-cfg_ub_checks.rs b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.rs new file mode 100644 index 00000000000..c24c0066e18 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] + +pub fn ub_checks_are_enabled() -> bool { + cfg!(ub_checks) //~ ERROR `cfg(ub_checks)` is experimental +} diff --git a/tests/ui/feature-gates/feature-gate-cfg_ub_checks.stderr b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.stderr new file mode 100644 index 00000000000..aa12ee1db6b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.stderr @@ -0,0 +1,13 @@ +error[E0658]: `cfg(ub_checks)` is experimental and subject to change + --> $DIR/feature-gate-cfg_ub_checks.rs:4:10 + | +LL | cfg!(ub_checks) + | ^^^^^^^^^ + | + = note: see issue #123499 <https://github.com/rust-lang/rust/issues/123499> for more information + = help: add `#![feature(cfg_ub_checks)]` 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-type_privacy_lints.rs b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs deleted file mode 100644 index c537fc419f6..00000000000 --- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ check-pass - -#![warn(unnameable_types)] //~ WARN unknown lint -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr deleted file mode 100644 index 72ac3792fff..00000000000 --- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: unknown lint: `unnameable_types` - --> $DIR/feature-gate-type_privacy_lints.rs:3:1 - | -LL | #![warn(unnameable_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `unnameable_types` lint is unstable - = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information - = help: add `#![feature(type_privacy_lints)]` 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: `#[warn(unknown_lints)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs index 6fe51330118..33fda822baa 100644 --- a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs +++ b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs @@ -1,7 +1,7 @@ //@ compile-flags: --edition 2021 pub fn demo() -> Option<i32> { - #[cfg(nope)] + #[cfg(FALSE)] { do yeet //~ ERROR `do yeet` expression is experimental } @@ -9,7 +9,7 @@ pub fn demo() -> Option<i32> { Some(1) } -#[cfg(nope)] +#[cfg(FALSE)] pub fn alternative() -> Result<(), String> { do yeet "hello"; //~ ERROR `do yeet` expression is experimental } diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/filter-block-view-items.rs index edb9ce38006..f582c51a3a6 100644 --- a/tests/ui/filter-block-view-items.rs +++ b/tests/ui/filter-block-view-items.rs @@ -4,5 +4,5 @@ pub fn main() { // Make sure that this view item is filtered out because otherwise it would // trigger a compilation error - #[cfg(not_present)] use bar as foo; + #[cfg(FALSE)] use bar as foo; } diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index aa377553c50..bebf575d9a7 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -8,6 +8,8 @@ LL | send(format_args!("{:?}", c)); | = 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::ArgumentType<'_>` + --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL note: required because it appears within the type `core::fmt::rt::Argument<'_>` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: required because it appears within the type `[core::fmt::rt::Argument<'_>]` @@ -30,6 +32,8 @@ LL | sync(format_args!("{:?}", c)); | = 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::ArgumentType<'_>` + --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL note: required because it appears within the type `core::fmt::rt::Argument<'_>` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: required because it appears within the type `[core::fmt::rt::Argument<'_>]` diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr index 3be630e2b23..b8ec2e3b7e7 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr @@ -10,6 +10,12 @@ LL | drop(x); LL | LL | println!("{}", y); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = f(&x, ()); +LL + let y = f(x.clone(), ()); + | error: aborting due to 1 previous error diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr index bf6d77b6269..382ab8636a2 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr @@ -27,6 +27,12 @@ LL | drop(x); | ^ move out of `x` occurs here LL | println!("{}", y); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = f(&x, ()); +LL + let y = f(x.clone(), ()); + | error: aborting due to 2 previous errors diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr index c2a8fa741ca..ce97d8527e8 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr @@ -10,6 +10,12 @@ LL | drop(x); LL | LL | println!("{}", y); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = f(&x, ()); +LL + let y = f(x.clone(), ()); + | error: aborting due to 1 previous error diff --git a/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr b/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr index 16808f29dac..d167a60dad3 100644 --- a/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr +++ b/tests/ui/functional-struct-update/functional-struct-update-noncopyable.stderr @@ -6,6 +6,11 @@ LL | let _b = A { y: Arc::new(3), ..a }; | | | cannot move out of here | move occurs because `a.x` has type `Arc<isize>`, which does not implement the `Copy` trait + | +help: clone the value from the field instead of using the functional record update syntax + | +LL | let _b = A { y: Arc::new(3), x: a.x.clone() }; + | ~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs index a3f3b1a6d4d..e06341ddf31 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs @@ -1,8 +1,7 @@ -#![warn(unused_lifetimes)] +#![warn(unused_lifetimes, redundant_lifetimes)] pub trait X { - type Y<'a: 'static>; - //~^ WARNING unnecessary lifetime parameter + type Y<'a: 'static>; //~ WARN unnecessary lifetime parameter `'a` } impl X for () { diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr index 8d21b9172c8..4f41ec025fc 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr @@ -1,18 +1,5 @@ -warning: unnecessary lifetime parameter `'a` - --> $DIR/unsatisfied-item-lifetime-bound.rs:4:12 - | -LL | type Y<'a: 'static>; - | ^^ - | - = help: you can use the `'static` lifetime directly, in place of `'a` -note: the lint level is defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:1:9 - | -LL | #![warn(unused_lifetimes)] - | ^^^^^^^^^^^^^^^^ - error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:9:18 + --> $DIR/unsatisfied-item-lifetime-bound.rs:8:18 | LL | type Y<'a: 'static>; | ------------------- definition of `Y` from trait @@ -21,7 +8,7 @@ LL | type Y<'a> = &'a (); | ^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:9:12 + --> $DIR/unsatisfied-item-lifetime-bound.rs:8:12 | LL | type Y<'a> = &'a (); | ^^ @@ -32,44 +19,57 @@ LL | type Y<'a> = &'a () where 'a: 'static; | +++++++++++++++++ error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:14:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:13:8 | LL | f: <T as X>::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:13:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:12:10 | LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:19:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:18:8 | LL | f: <T as X>::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:18:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:17:10 | LL | struct C<'a, T: X> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:24:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:23:8 | LL | f: <() as X>::Y<'a>, | ^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:23:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:22:10 | LL | struct D<'a> { | ^^ = note: but lifetime parameter must outlive the static lifetime +warning: unnecessary lifetime parameter `'a` + --> $DIR/unsatisfied-item-lifetime-bound.rs:4:12 + | +LL | type Y<'a: 'static>; + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` +note: the lint level is defined here + --> $DIR/unsatisfied-item-lifetime-bound.rs:1:27 + | +LL | #![warn(unused_lifetimes, redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ + error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs new file mode 100644 index 00000000000..2607013ec63 --- /dev/null +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -0,0 +1,19 @@ +// ICE: assertion failed: !value.has_infer() +// issue: rust-lang/rust#115806 +#![feature(associated_const_equality)] +#![allow(incomplete_features)] + +pub struct NoPin; + +impl<TA> Pins<TA> for NoPin {} + +pub trait PinA<PER> { + const A: &'static () = &(); +} + +pub trait Pins<USART> {} + +impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {} +//~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin` + +pub fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr new file mode 100644 index 00000000000..9a9baaddcba --- /dev/null +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin` + --> $DIR/assoc-const-no-infer-ice-115806.rs:16:1 + | +LL | impl<TA> Pins<TA> for NoPin {} + | --------------------------- first implementation here +... +LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` + | + = note: downstream crates may implement trait `PinA<_>` for type `NoPin` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/generic-const-items/compare-impl-item.rs b/tests/ui/generic-const-items/compare-impl-item.rs index 01e4477c698..21c958a0abe 100644 --- a/tests/ui/generic-const-items/compare-impl-item.rs +++ b/tests/ui/generic-const-items/compare-impl-item.rs @@ -6,9 +6,10 @@ trait Trait<P> { const B<const K: u64, const Q: u64>: u64; const C<T>: T; const D<const N: usize>: usize; + const E<'a>: &'a (); - const E: usize; - const F<T: PartialEq>: (); + const F: usize; + const G<T: PartialEq>: (); } impl<P> Trait<P> for () { @@ -20,11 +21,13 @@ impl<P> Trait<P> for () { //~^ ERROR const `C` has 0 type parameters but its trait declaration has 1 type parameter const D<const N: u16>: u16 = N; //~^ ERROR const `D` has an incompatible generic parameter for trait `Trait` + const E: &'static () = &(); + //~^ ERROR lifetime parameters or bounds on const `E` do not match the trait declaration - const E: usize = 1024 + const F: usize = 1024 where P: Copy; //~ ERROR impl has stricter requirements than trait - const F<T: Eq>: () = (); //~ ERROR impl has stricter requirements than trait + const G<T: Eq>: () = (); //~ ERROR impl has stricter requirements than trait } fn main() {} diff --git a/tests/ui/generic-const-items/compare-impl-item.stderr b/tests/ui/generic-const-items/compare-impl-item.stderr index 8610d8cba00..3bf28e9da60 100644 --- a/tests/ui/generic-const-items/compare-impl-item.stderr +++ b/tests/ui/generic-const-items/compare-impl-item.stderr @@ -1,5 +1,5 @@ error[E0049]: const `A` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/compare-impl-item.rs:15:13 + --> $DIR/compare-impl-item.rs:16:13 | LL | const A: (); | - expected 0 type parameters @@ -8,7 +8,7 @@ LL | const A<T>: () = (); | ^ found 1 type parameter error[E0049]: const `B` has 1 const parameter but its trait declaration has 2 const parameters - --> $DIR/compare-impl-item.rs:17:13 + --> $DIR/compare-impl-item.rs:18:13 | LL | const B<const K: u64, const Q: u64>: u64; | ------------ ------------ @@ -19,7 +19,7 @@ LL | const B<const K: u64>: u64 = 0; | ^^^^^^^^^^^^ found 1 const parameter error[E0049]: const `C` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/compare-impl-item.rs:19:13 + --> $DIR/compare-impl-item.rs:20:13 | LL | const C<T>: T; | - expected 1 type parameter @@ -28,7 +28,7 @@ LL | const C<'a>: &'a str = ""; | ^^ found 0 type parameters error[E0053]: const `D` has an incompatible generic parameter for trait `Trait` - --> $DIR/compare-impl-item.rs:21:13 + --> $DIR/compare-impl-item.rs:22:13 | LL | trait Trait<P> { | ----- @@ -42,25 +42,34 @@ LL | impl<P> Trait<P> for () { LL | const D<const N: u16>: u16 = N; | ^^^^^^^^^^^^ found const parameter of type `u16` +error[E0195]: lifetime parameters or bounds on const `E` do not match the trait declaration + --> $DIR/compare-impl-item.rs:24:12 + | +LL | const E<'a>: &'a (); + | ---- lifetimes in impl do not match this const in trait +... +LL | const E: &'static () = &(); + | ^ lifetimes do not match const in trait + error[E0276]: impl has stricter requirements than trait - --> $DIR/compare-impl-item.rs:26:12 + --> $DIR/compare-impl-item.rs:29:12 | -LL | const E: usize; - | -------------- definition of `E` from trait +LL | const F: usize; + | -------------- definition of `F` from trait ... LL | P: Copy; | ^^^^ impl has extra requirement `P: Copy` error[E0276]: impl has stricter requirements than trait - --> $DIR/compare-impl-item.rs:27:16 + --> $DIR/compare-impl-item.rs:30:16 | -LL | const F<T: PartialEq>: (); - | ------------------------- definition of `F` from trait +LL | const G<T: PartialEq>: (); + | ------------------------- definition of `G` from trait ... -LL | const F<T: Eq>: () = (); +LL | const G<T: Eq>: () = (); | ^^ impl has extra requirement `T: Eq` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0049, E0053, E0276. +Some errors have detailed explanations: E0049, E0053, E0195, E0276. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/generic-const-items/inference-failure.stderr b/tests/ui/generic-const-items/inference-failure.stderr index 10ecd83ec53..594743a47f4 100644 --- a/tests/ui/generic-const-items/inference-failure.stderr +++ b/tests/ui/generic-const-items/inference-failure.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Option<T>` +error[E0282]: type annotations needed for `Option<_>` --> $DIR/inference-failure.rs:8:9 | LL | let _ = NONE; diff --git a/tests/ui/generic-const-items/parameter-defaults.stderr b/tests/ui/generic-const-items/parameter-defaults.stderr index b8220af5d0e..13562c98f6d 100644 --- a/tests/ui/generic-const-items/parameter-defaults.stderr +++ b/tests/ui/generic-const-items/parameter-defaults.stderr @@ -4,7 +4,7 @@ error: defaults for type parameters are only allowed in `struct`, `enum`, `type` LL | const NONE<T = ()>: Option<T> = None::<T>; | ^^^^^^ -error[E0282]: type annotations needed for `Option<T>` +error[E0282]: type annotations needed for `Option<_>` --> $DIR/parameter-defaults.rs:13:9 | LL | let _ = NONE; diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr index 6832f21f25e..0d2aae689f0 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr @@ -46,10 +46,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ...$e; { todo!() } - | ++ +++++++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr index cb9e48e70e3..9ba0e09e154 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr @@ -67,10 +67,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e...; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:17 @@ -85,10 +81,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e..=; { todo!() } - | ++ +++++++++++ error: aborting due to 8 previous errors diff --git a/tests/ui/impl-trait/different_where_bounds.rs b/tests/ui/impl-trait/different_where_bounds.rs new file mode 100644 index 00000000000..87ae6db2822 --- /dev/null +++ b/tests/ui/impl-trait/different_where_bounds.rs @@ -0,0 +1,27 @@ +//! This test checks that the param env canonicalization cache +//! does not end up with inconsistent values. + +//@ check-pass + +pub fn poison1() -> impl Sized +where + (): 'static, +{ +} +pub fn poison2() -> impl Sized +where + (): 'static, +{ + define_by_query((poison2, ())); +} +pub fn poison3() -> impl Sized +where + (): 'static, +{ +} + +trait Query {} +impl<Out, F: Fn() -> Out> Query for (F, Out) {} +fn define_by_query(_: impl Query) {} + +fn main() {} diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr deleted file mode 100644 index e4c8aec3973..00000000000 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ /dev/null @@ -1,23 +0,0 @@ -note: no errors encountered even though delayed bugs were created - -note: those delayed bugs will now be shown as internal compiler errors - -error: internal compiler error: {OpaqueTypeKey { def_id: DefId(rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }) } }} - | - = - - -error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }))), bound_vars: [] } } } - --> $DIR/equality-in-canonical-query.rs:21:5 - | -LL | same_output(foo, rpit); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - - --> $DIR/equality-in-canonical-query.rs:21:5 - | -LL | same_output(foo, rpit); - | ^^^^^^^^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/impl-trait/equality-in-canonical-query.rs b/tests/ui/impl-trait/equality-in-canonical-query.rs index 6a32f4bec76..2b8f6ce1b07 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.rs +++ b/tests/ui/impl-trait/equality-in-canonical-query.rs @@ -1,15 +1,6 @@ // issue: #116877 //@ revisions: sized clone -//@[sized] check-pass -//@[clone] known-bug: #108498 -//@[clone] failure-status: 101 -//@[clone] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId(" -//@[clone] normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> "" -//@[clone] normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> "" -//@[clone] normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> "" -//@[clone] normalize-stderr-test: "(?m)note: delayed at.*$" -> "" -//@[clone] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> "" -//@[clone] normalize-stderr-test: "(?m)^ *at .*\n" -> "" +//@ check-pass #[cfg(sized)] fn rpit() -> impl Sized {} #[cfg(clone)] fn rpit() -> impl Clone {} diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs new file mode 100644 index 00000000000..994a5073947 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs @@ -0,0 +1,42 @@ +// ICE failed to resolve instance for <fn() -> impl MyFnOnce ... +// issue: rust-lang/rust#105488 +//@ build-fail +//~^^^ ERROR overflow evaluating the requirement `fn() -> impl MyFnOnce + +pub trait MyFnOnce { + type Output; + + fn call_my_fn_once(self) -> Self::Output; +} + +pub struct WrapFnOnce<F>(F); + +impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for WrapFnOnce<F> { + type Output = D::Output; + + fn call_my_fn_once(self) -> Self::Output { + D::call_my_fn_once(self.0()) + } +} + +impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for F { + type Output = D::Output; + + fn call_my_fn_once(self) -> Self::Output { + D::call_my_fn_once(self()) + } +} + +pub fn my_fn_1() -> impl MyFnOnce { + my_fn_2 +} + +pub fn my_fn_2() -> impl MyFnOnce { + WrapFnOnce(my_fn_1) +} + +fn main() { + let v = my_fn_1(); + + let _ = v.call_my_fn_once(); +} diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr new file mode 100644 index 00000000000..c2782b79d90 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `fn() -> impl MyFnOnce {my_fn_2}: MyFnOnce` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`failed_to_resolve_instance_ice_105488`) +note: required for `WrapFnOnce<fn() -> impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce` + --> $DIR/failed-to-resolve-instance-ice-105488.rs:14:37 + | +LL | impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for WrapFnOnce<F> { + | -------- ^^^^^^^^ ^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 126 redundant requirements hidden + = note: required for `WrapFnOnce<fn() -> impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs new file mode 100644 index 00000000000..977827f3b55 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs @@ -0,0 +1,20 @@ +// ICE failed to resolve instance for ... +// issue: rust-lang/rust#123145 +//@ build-fail +//~^^^ ERROR overflow evaluating the requirement `(fn() -> impl Handler + +trait Handler { + fn handle(&self) {} +} + +impl<H: Handler, F: Fn() -> H> Handler for F {} + +impl<L: Handler> Handler for (L,) {} + +fn one() -> impl Handler { + (one,) +} + +fn main() { + one.handle(); +} diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr new file mode 100644 index 00000000000..f61e8c2f8df --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `(fn() -> impl Handler {one},): Handler` + | +note: required for `fn() -> impl Handler {one}` to implement `Handler` + --> $DIR/failed-to-resolve-instance-ice-123145.rs:10:32 + | +LL | impl<H: Handler, F: Fn() -> H> Handler for F {} + | ------- ^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: 2 redundant requirements hidden + = note: required for `fn() -> impl Handler {one}` to implement `Handler` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/nested-hkl-lifetime.rs b/tests/ui/impl-trait/nested-hkl-lifetime.rs new file mode 100644 index 00000000000..089ceca6777 --- /dev/null +++ b/tests/ui/impl-trait/nested-hkl-lifetime.rs @@ -0,0 +1,32 @@ +//@ check-pass + +use std::iter::FromIterator; + +struct DynamicAlt<P>(P); + +impl<P> FromIterator<P> for DynamicAlt<P> { + fn from_iter<T: IntoIterator<Item = P>>(_iter: T) -> Self { + loop {} + } +} + +fn owned_context<I, F>(_: F) -> impl FnMut(I) -> I { + |i| i +} + +trait Parser<I> {} + +impl<T, I> Parser<I> for T where T: FnMut(I) -> I {} + +fn alt<I, P: Parser<I>>(_: DynamicAlt<P>) -> impl FnMut(I) -> I { + |i| i +} + +fn rule_to_parser<'c>() -> impl Parser<&'c str> { + move |input| { + let v: Vec<()> = vec![]; + alt(v.iter().map(|()| owned_context(rule_to_parser())).collect::<DynamicAlt<_>>())(input) + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs index a696e1710f0..9b18aceb4a7 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.rs +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -44,7 +44,7 @@ fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized // This should resolve. fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} -//~^ ERROR type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>` +//~^ ERROR the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied // This should resolve. fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 64f801ea685..2fa036f35fa 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -86,13 +86,12 @@ note: lifetime declared here LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ -error[E0283]: type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>` +error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied --> $DIR/nested-rpit-hrtb.rs:46:79 | LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()` | - = note: cannot satisfy `for<'a> &'a (): Qux<'b>` = help: the trait `Qux<'_>` is implemented for `()` = help: for that trait implementation, expected `()`, found `&'a ()` @@ -125,5 +124,5 @@ LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Si error: aborting due to 11 previous errors -Some errors have detailed explanations: E0261, E0277, E0283, E0657. +Some errors have detailed explanations: E0261, E0277, E0657. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/imports/redundant-import-extern-prelude.rs b/tests/ui/imports/redundant-import-extern-prelude.rs new file mode 100644 index 00000000000..f1de06417aa --- /dev/null +++ b/tests/ui/imports/redundant-import-extern-prelude.rs @@ -0,0 +1,16 @@ +//@ check-pass +// Check that we detect imports that are redundant due to the extern prelude +// and that we emit a reasonable diagnostic. +// issue: rust-lang/rust#121915 + +// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>. + +//@ compile-flags: --extern aux_issue_121915 --edition 2018 +//@ aux-build: aux-issue-121915.rs + +#[deny(unused_imports)] +fn main() { + use aux_issue_121915; + //FIXME(unused_imports): ~^ ERROR the item `aux_issue_121915` is imported redundantly + aux_issue_121915::item(); +} diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.rs b/tests/ui/imports/redundant-import-issue-121915-2015.rs index d41d190bb58..be3b8209ada 100644 --- a/tests/ui/imports/redundant-import-issue-121915-2015.rs +++ b/tests/ui/imports/redundant-import-issue-121915-2015.rs @@ -1,3 +1,4 @@ +//@ check-pass //@ compile-flags: --extern aux_issue_121915 --edition 2015 //@ aux-build: aux-issue-121915.rs @@ -6,6 +7,6 @@ extern crate aux_issue_121915; #[deny(unused_imports)] fn main() { use aux_issue_121915; - //~^ ERROR the item `aux_issue_121915` is imported redundantly + //FIXME(unused_imports): ~^ ERROR the item `aux_issue_121915` is imported redundantly aux_issue_121915::item(); } diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.stderr b/tests/ui/imports/redundant-import-issue-121915-2015.stderr deleted file mode 100644 index 174ed4fb96b..00000000000 --- a/tests/ui/imports/redundant-import-issue-121915-2015.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: the item `aux_issue_121915` is imported redundantly - --> $DIR/redundant-import-issue-121915-2015.rs:8:9 - | -LL | extern crate aux_issue_121915; - | ------------------------------ the item `aux_issue_121915` is already imported here -... -LL | use aux_issue_121915; - | ^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/redundant-import-issue-121915-2015.rs:6:8 - | -LL | #[deny(unused_imports)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/imports/redundant-import-issue-121915.rs b/tests/ui/imports/redundant-import-issue-121915.rs deleted file mode 100644 index 237acc4af25..00000000000 --- a/tests/ui/imports/redundant-import-issue-121915.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ compile-flags: --extern aux_issue_121915 --edition 2018 -//@ aux-build: aux-issue-121915.rs - -#[deny(unused_imports)] -fn main() { - use aux_issue_121915; - //~^ ERROR the item `aux_issue_121915` is imported redundantly - aux_issue_121915::item(); -} diff --git a/tests/ui/imports/redundant-import-issue-121915.stderr b/tests/ui/imports/redundant-import-issue-121915.stderr deleted file mode 100644 index 0047d7c3420..00000000000 --- a/tests/ui/imports/redundant-import-issue-121915.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: the item `aux_issue_121915` is imported redundantly - --> $DIR/redundant-import-issue-121915.rs:6:9 - | -LL | use aux_issue_121915; - | ^^^^^^^^^^^^^^^^ the item `aux_issue_121915` is already defined by prelude - | -note: the lint level is defined here - --> $DIR/redundant-import-issue-121915.rs:4:8 - | -LL | #[deny(unused_imports)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/imports/redundant-import-lang-prelude-attr.rs b/tests/ui/imports/redundant-import-lang-prelude-attr.rs new file mode 100644 index 00000000000..59cd570f44c --- /dev/null +++ b/tests/ui/imports/redundant-import-lang-prelude-attr.rs @@ -0,0 +1,17 @@ +//@ check-pass +// Check that we detect imports (of built-in attributes) that are redundant due to +// the language prelude and that we emit a reasonable diagnostic. + +// Note that we use the term "extern prelude" in the label even though "language prelude" +// would be more correct. However, it's not worth special-casing this. + +// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>. + +//@ edition: 2018 + +#![deny(unused_imports)] + +use allow; //FIXME(unused_imports): ~ ERROR the item `allow` is imported redundantly + +#[allow(unused)] +fn main() {} diff --git a/tests/ui/imports/redundant-import-lang-prelude.rs b/tests/ui/imports/redundant-import-lang-prelude.rs new file mode 100644 index 00000000000..53d3b709963 --- /dev/null +++ b/tests/ui/imports/redundant-import-lang-prelude.rs @@ -0,0 +1,17 @@ +//@ check-pass +// Check that we detect imports that are redundant due to the language prelude +// and that we emit a reasonable diagnostic. + +// Note that we use the term "extern prelude" in the label even though "language prelude" +// would be more correct. However, it's not worth special-casing this. + +// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>. + +#![deny(unused_imports)] + +use std::primitive::u8; +//FIXME(unused_imports): ~^ ERROR the item `u8` is imported redundantly + +const _: u8 = 0; + +fn main() {} diff --git a/tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs b/tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs new file mode 100644 index 00000000000..4a79cb2c208 --- /dev/null +++ b/tests/ui/imports/redundant-import-undetected-macro-use-prelude.rs @@ -0,0 +1,23 @@ +// This test demonstrates that we currently don't make an effort to detect +// imports made redundant by the `#[macro_use]` prelude. +// See also the discussion in <https://github.com/rust-lang/rust/pull/122954>. + +//@ check-pass +//@ aux-build:two_macros.rs +#![deny(unused_imports)] + +#[macro_use] +extern crate two_macros; + +// This import is actually redundant due to the `#[macro_use]` above. +use two_macros::n; + +// We intentionally reference two items from the `#[macro_use]`'d crate because +// if we were to reference only item `n`, we would flag the `#[macro_use]` +// attribute as redundant which would be correct of course. +// That's interesting on its own -- we prefer "blaming" the `#[macro_use]` +// over the import (here, `use two_macros::n`) when it comes to redundancy. +n!(); +m!(); + +fn main() {} diff --git a/tests/ui/imports/suggest-remove-issue-121315.rs b/tests/ui/imports/suggest-remove-issue-121315.rs index 63533480ec1..2bb82833a5b 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.rs +++ b/tests/ui/imports/suggest-remove-issue-121315.rs @@ -1,19 +1,20 @@ //@ compile-flags: --edition 2021 + #![deny(unused_imports)] #![allow(dead_code)] fn test0() { // Test remove FlatUnused use std::convert::TryFrom; - //~^ ERROR the item `TryFrom` is imported redundantly + //FIXME(unused_imports): ~^ ERROR the item `TryFrom` is imported redundantly let _ = u32::try_from(5i32); } fn test1() { // FIXME(yukang) Test remove NestedFullUnused use std::convert::{TryFrom, TryInto}; - //~^ ERROR the item `TryFrom` is imported redundantly - //~| ERROR the item `TryInto` is imported redundantly + //FIXME(unused_imports): ~^ ERROR the item `TryFrom` is imported redundantly + //FIXME(unused_imports): ~| ERROR the item `TryInto` is imported redundantly let _ = u32::try_from(5i32); let _a: i32 = u32::try_into(5u32).unwrap(); @@ -23,7 +24,7 @@ fn test2() { // FIXME(yukang): Test remove both redundant and unused use std::convert::{AsMut, Into}; //~^ ERROR unused import: `AsMut` - //~| ERROR the item `Into` is imported redundantly + //FIXME(unused_imports): ~| ERROR the item `Into` is imported redundantly let _a: u32 = (5u8).into(); } diff --git a/tests/ui/imports/suggest-remove-issue-121315.stderr b/tests/ui/imports/suggest-remove-issue-121315.stderr index dbd742f6c78..5701514e1bd 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.stderr +++ b/tests/ui/imports/suggest-remove-issue-121315.stderr @@ -1,56 +1,20 @@ -error: the item `TryFrom` is imported redundantly - --> $DIR/suggest-remove-issue-121315.rs:7:9 - | -LL | use std::convert::TryFrom; - | ^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `TryFrom` is already defined here - | -note: the lint level is defined here - --> $DIR/suggest-remove-issue-121315.rs:2:9 - | -LL | #![deny(unused_imports)] - | ^^^^^^^^^^^^^^ - -error: the item `TryFrom` is imported redundantly - --> $DIR/suggest-remove-issue-121315.rs:14:24 - | -LL | use std::convert::{TryFrom, TryInto}; - | ^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `TryFrom` is already defined here - -error: the item `TryInto` is imported redundantly - --> $DIR/suggest-remove-issue-121315.rs:14:33 - | -LL | use std::convert::{TryFrom, TryInto}; - | ^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `TryInto` is already defined here - error: unused import: `AsMut` - --> $DIR/suggest-remove-issue-121315.rs:24:24 + --> $DIR/suggest-remove-issue-121315.rs:25:24 | LL | use std::convert::{AsMut, Into}; | ^^^^^ - -error: the item `Into` is imported redundantly - --> $DIR/suggest-remove-issue-121315.rs:24:31 | -LL | use std::convert::{AsMut, Into}; - | ^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL +note: the lint level is defined here + --> $DIR/suggest-remove-issue-121315.rs:3:9 | - = note: the item `Into` is already defined here +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ error: unused import: `From` - --> $DIR/suggest-remove-issue-121315.rs:33:24 + --> $DIR/suggest-remove-issue-121315.rs:34:24 | LL | use std::convert::{From, Infallible}; | ^^^^ -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/imports/unused-import-issue-87973.rs b/tests/ui/imports/unused-import-issue-87973.rs index b04bec07d18..1b016ff814c 100644 --- a/tests/ui/imports/unused-import-issue-87973.rs +++ b/tests/ui/imports/unused-import-issue-87973.rs @@ -4,7 +4,7 @@ // Check that attributes get removed too. See #87973. #[deprecated] #[allow(unsafe_code)] -#[cfg(not(foo))] +#[cfg(not(FALSE))] use std::fs; //~^ ERROR unused import diff --git a/tests/ui/include-macros/mismatched-types.stderr b/tests/ui/include-macros/mismatched-types.stderr index 4f2880e2f5d..9bc0e64464e 100644 --- a/tests/ui/include-macros/mismatched-types.stderr +++ b/tests/ui/include-macros/mismatched-types.stderr @@ -1,8 +1,11 @@ error[E0308]: mismatched types - --> $DIR/mismatched-types.rs:2:20 + --> $DIR/file.txt:0:1 + | + | + ::: $DIR/mismatched-types.rs:2:12 | LL | let b: &[u8] = include_str!("file.txt"); - | ----- ^^^^^^^^^^^^^^^^^^^^^^^^ expected `&[u8]`, found `&str` + | ----- ------------------------ in this macro invocation | | | expected due to this | diff --git a/tests/ui/inference/cannot-infer-closure-circular.rs b/tests/ui/inference/cannot-infer-closure-circular.rs index affb481496d..1b41171e74a 100644 --- a/tests/ui/inference/cannot-infer-closure-circular.rs +++ b/tests/ui/inference/cannot-infer-closure-circular.rs @@ -4,7 +4,7 @@ fn main() { // error handles this gracefully, and in particular doesn't generate an extra // note about the `?` operator in the closure body, which isn't relevant to // the inference. - let x = |r| { //~ ERROR type annotations needed for `Result<(), E>` + let x = |r| { //~ ERROR type annotations needed for `Result<(), _>` let v = r?; Ok(v) }; diff --git a/tests/ui/inference/cannot-infer-closure-circular.stderr b/tests/ui/inference/cannot-infer-closure-circular.stderr index e3cf0cca837..a16e832f8ef 100644 --- a/tests/ui/inference/cannot-infer-closure-circular.stderr +++ b/tests/ui/inference/cannot-infer-closure-circular.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Result<(), E>` +error[E0282]: type annotations needed for `Result<(), _>` --> $DIR/cannot-infer-closure-circular.rs:7:14 | LL | let x = |r| { diff --git a/tests/ui/inference/erase-type-params-in-label.stderr b/tests/ui/inference/erase-type-params-in-label.stderr index 546e679f2d0..4e9a74c1e40 100644 --- a/tests/ui/inference/erase-type-params-in-label.stderr +++ b/tests/ui/inference/erase-type-params-in-label.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>` +error[E0283]: type annotations needed for `Foo<i32, &str, _, _>` --> $DIR/erase-type-params-in-label.rs:2:9 | LL | let foo = foo(1, ""); @@ -15,7 +15,7 @@ help: consider giving `foo` an explicit type, where the type for type parameter LL | let foo: Foo<i32, &str, W, Z> = foo(1, ""); | ++++++++++++++++++++++ -error[E0283]: type annotations needed for `Bar<i32, &str, Z>` +error[E0283]: type annotations needed for `Bar<i32, &str, _>` --> $DIR/erase-type-params-in-label.rs:5:9 | LL | let bar = bar(1, ""); diff --git a/tests/ui/inference/issue-104649.stderr b/tests/ui/inference/issue-104649.stderr index afece960914..391ed16f349 100644 --- a/tests/ui/inference/issue-104649.stderr +++ b/tests/ui/inference/issue-104649.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `A<std::result::Result<std::result::Result<(), E>, Error>>` +error[E0282]: type annotations needed for `A<std::result::Result<std::result::Result<(), _>, Error>>` --> $DIR/issue-104649.rs:24:9 | LL | let a = A(Result::Ok(Result::Ok(()))); diff --git a/tests/ui/inference/issue-72690.stderr b/tests/ui/inference/issue-72690.stderr index 6c93241ea07..6391672f861 100644 --- a/tests/ui/inference/issue-72690.stderr +++ b/tests/ui/inference/issue-72690.stderr @@ -50,7 +50,7 @@ help: try using a fully qualified path to specify the expected types LL | |x| String::from(<str as AsRef<T>>::as_ref("x")); | ++++++++++++++++++++++++++ ~ -error[E0283]: type annotations needed for `&T` +error[E0283]: type annotations needed for `&_` --> $DIR/issue-72690.rs:17:9 | LL | let _ = "x".as_ref(); diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index 523ca229b06..c772225be75 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } } +error: internal compiler error: error performing operation: fully_perform --> $DIR/issue-80409.rs:49:30 | LL | builder.state().on_entry(|_| {}); diff --git a/tests/ui/inference/issue-83606.rs b/tests/ui/inference/issue-83606.rs index c387046e910..4454b5e60f0 100644 --- a/tests/ui/inference/issue-83606.rs +++ b/tests/ui/inference/issue-83606.rs @@ -6,5 +6,5 @@ fn foo<const N: usize>(_: impl std::fmt::Display) -> [usize; N] { fn main() { let _ = foo("foo"); - //~^ ERROR: type annotations needed for `[usize; N]` + //~^ ERROR type annotations needed for `[usize; _]` } diff --git a/tests/ui/inference/issue-83606.stderr b/tests/ui/inference/issue-83606.stderr index 00de4029e42..8e6ff6d568d 100644 --- a/tests/ui/inference/issue-83606.stderr +++ b/tests/ui/inference/issue-83606.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `[usize; N]` +error[E0282]: type annotations needed for `[usize; _]` --> $DIR/issue-83606.rs:8:9 | LL | let _ = foo("foo"); diff --git a/tests/ui/inference/untyped-primitives.rs b/tests/ui/inference/untyped-primitives.rs new file mode 100644 index 00000000000..8515ca79903 --- /dev/null +++ b/tests/ui/inference/untyped-primitives.rs @@ -0,0 +1,9 @@ +//@ check-pass +// issue: rust-lang/rust#123824 +// This test is a sanity check and does not enforce any stable API, so may be +// removed at a future point. + +fn main() { + let x = f32::from(3.14); + let y = f64::from(3.14); +} diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs index 1c94169a2e5..75f406232e2 100644 --- a/tests/ui/inner-attrs-on-impl.rs +++ b/tests/ui/inner-attrs-on-impl.rs @@ -3,16 +3,16 @@ struct Foo; impl Foo { - #![cfg(cfg_that_surely_doesnt_exist)] + #![cfg(FALSE)] fn method(&self) -> bool { false } } impl Foo { - #![cfg(not(cfg_that_surely_doesnt_exist))] + #![cfg(not(FALSE))] // check that we don't eat attributes too eagerly. - #[cfg(cfg_that_surely_doesnt_exist)] + #[cfg(FALSE)] fn method(&self) -> bool { false } fn method(&self) -> bool { true } diff --git a/tests/ui/instrument-coverage/off-values.rs b/tests/ui/instrument-coverage/off-values.rs index bd13e5d7495..60222d43b23 100644 --- a/tests/ui/instrument-coverage/off-values.rs +++ b/tests/ui/instrument-coverage/off-values.rs @@ -1,9 +1,9 @@ //@ check-pass -//@ revisions: n no off false zero +//@ revisions: n no off _false zero //@ [n] compile-flags: -Cinstrument-coverage=n //@ [no] compile-flags: -Cinstrument-coverage=no //@ [off] compile-flags: -Cinstrument-coverage=off -//@ [false] compile-flags: -Cinstrument-coverage=false +//@ [_false] compile-flags: -Cinstrument-coverage=false //@ [zero] compile-flags: -Cinstrument-coverage=0 fn main() {} diff --git a/tests/ui/internal-lints/existing_doc_keyword.rs b/tests/ui/internal-lints/existing_doc_keyword.rs index 16c350287b2..8f60b931591 100644 --- a/tests/ui/internal-lints/existing_doc_keyword.rs +++ b/tests/ui/internal-lints/existing_doc_keyword.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Z unstable-options -#![feature(rustc_private)] #![feature(rustdoc_internals)] #![crate_type = "lib"] diff --git a/tests/ui/internal-lints/existing_doc_keyword.stderr b/tests/ui/internal-lints/existing_doc_keyword.stderr index 8f519fe6b5f..5573e7ce4d0 100644 --- a/tests/ui/internal-lints/existing_doc_keyword.stderr +++ b/tests/ui/internal-lints/existing_doc_keyword.stderr @@ -1,12 +1,12 @@ error: found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` - --> $DIR/existing_doc_keyword.rs:10:1 + --> $DIR/existing_doc_keyword.rs:9:1 | LL | #[doc(keyword = "tadam")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only existing keywords are allowed in core/std note: the lint level is defined here - --> $DIR/existing_doc_keyword.rs:8:9 + --> $DIR/existing_doc_keyword.rs:7:9 | LL | #![deny(rustc::existing_doc_keyword)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/intrinsics/incorrect-transmute.rs b/tests/ui/intrinsics/incorrect-transmute.rs new file mode 100644 index 00000000000..4f1d1491ec9 --- /dev/null +++ b/tests/ui/intrinsics/incorrect-transmute.rs @@ -0,0 +1,8 @@ +fn main() { + transmute(); // does not ICE +} + +extern "rust-intrinsic" fn transmute() {} +//~^ ERROR intrinsic has wrong number of type parameters: found 0, expected 2 +//~| ERROR intrinsics are subject to change +//~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block diff --git a/tests/ui/intrinsics/incorrect-transmute.stderr b/tests/ui/intrinsics/incorrect-transmute.stderr new file mode 100644 index 00000000000..20b95925b76 --- /dev/null +++ b/tests/ui/intrinsics/incorrect-transmute.stderr @@ -0,0 +1,25 @@ +error[E0658]: intrinsics are subject to change + --> $DIR/incorrect-transmute.rs:5:8 + | +LL | extern "rust-intrinsic" fn transmute() {} + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(intrinsics)]` 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[E0094]: intrinsic has wrong number of type parameters: found 0, expected 2 + --> $DIR/incorrect-transmute.rs:5:37 + | +LL | extern "rust-intrinsic" fn transmute() {} + | ^ expected 2 type parameters + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/incorrect-transmute.rs:5:40 + | +LL | extern "rust-intrinsic" fn transmute() {} + | ^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0094, E0658. +For more information about an error, try `rustc --explain E0094`. diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/issues/issue-11004.rs index 10ef1f5e3b5..09d5476dbe6 100644 --- a/tests/ui/issues/issue-11004.rs +++ b/tests/ui/issues/issue-11004.rs @@ -2,14 +2,14 @@ use std::mem; struct A { x: i32, y: f64 } -#[cfg(not(works))] +#[cfg(not(FALSE))] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = n.x; //~ no field `x` on type `*mut A` let y : f64 = n.y; //~ no field `y` on type `*mut A` (x, y) } -#[cfg(works)] +#[cfg(FALSE)] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = (*n).x; let y : f64 = (*n).y; diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/issues/issue-11085.rs index c4a9f5f69bd..300be10226c 100644 --- a/tests/ui/issues/issue-11085.rs +++ b/tests/ui/issues/issue-11085.rs @@ -5,7 +5,7 @@ //@ pretty-expanded FIXME #23616 struct Foo { - #[cfg(fail)] + #[cfg(FALSE)] bar: baz, foo: isize, } @@ -17,18 +17,18 @@ struct Foo2 { enum Bar1 { Bar1_1, - #[cfg(fail)] + #[cfg(FALSE)] Bar1_2(NotAType), } enum Bar2 { - #[cfg(fail)] + #[cfg(FALSE)] Bar2_1(NotAType), } enum Bar3 { Bar3_1 { - #[cfg(fail)] + #[cfg(FALSE)] foo: isize, bar: isize, } diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index 161fce4b031..d4a4647f6a1 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -6,15 +6,15 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: + <&'a f128 as Add<f128>> + <&'a f16 as Add<f16>> <&'a f32 as Add<f32>> <&'a f64 as Add<f64>> <&'a i128 as Add<i128>> <&'a i16 as Add<i16>> <&'a i32 as Add<i32>> <&'a i64 as Add<i64>> - <&'a i8 as Add<i8>> - <&'a isize as Add<isize>> - and 48 others + and 56 others error[E0277]: cannot add `()` to `{integer}` --> $DIR/issue-11771.rs:8:7 @@ -24,15 +24,15 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: + <&'a f128 as Add<f128>> + <&'a f16 as Add<f16>> <&'a f32 as Add<f32>> <&'a f64 as Add<f64>> <&'a i128 as Add<i128>> <&'a i16 as Add<i16>> <&'a i32 as Add<i32>> <&'a i64 as Add<i64>> - <&'a i8 as Add<i8>> - <&'a isize as Add<isize>> - and 48 others + and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-12187-1.stderr b/tests/ui/issues/issue-12187-1.stderr index 93dc1df8f63..704854fe585 100644 --- a/tests/ui/issues/issue-12187-1.stderr +++ b/tests/ui/issues/issue-12187-1.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `&T` +error[E0282]: type annotations needed for `&_` --> $DIR/issue-12187-1.rs:6:9 | LL | let &v = new(); diff --git a/tests/ui/issues/issue-12187-2.stderr b/tests/ui/issues/issue-12187-2.stderr index e9ba52ff4fd..eeef63a1d0b 100644 --- a/tests/ui/issues/issue-12187-2.stderr +++ b/tests/ui/issues/issue-12187-2.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `&T` +error[E0282]: type annotations needed for `&_` --> $DIR/issue-12187-2.rs:6:9 | LL | let &v = new(); diff --git a/tests/ui/issues/issue-13259-windows-tcb-trash.rs b/tests/ui/issues/issue-13259-windows-tcb-trash.rs index 803cda091b9..381e3f15259 100644 --- a/tests/ui/issues/issue-13259-windows-tcb-trash.rs +++ b/tests/ui/issues/issue-13259-windows-tcb-trash.rs @@ -1,7 +1,4 @@ //@ run-pass -#![feature(rustc_private)] - -extern crate libc; #[cfg(windows)] mod imp { diff --git a/tests/ui/issues/issue-16819.rs b/tests/ui/issues/issue-16819.rs index 320695118d5..e2b10909177 100644 --- a/tests/ui/issues/issue-16819.rs +++ b/tests/ui/issues/issue-16819.rs @@ -3,7 +3,7 @@ // `#[cfg]` on struct field permits empty unusable struct struct S { - #[cfg(untrue)] + #[cfg(FALSE)] a: int, } diff --git a/tests/ui/issues/issue-17385.stderr b/tests/ui/issues/issue-17385.stderr index 77aa201b335..988db0fb1fc 100644 --- a/tests/ui/issues/issue-17385.stderr +++ b/tests/ui/issues/issue-17385.stderr @@ -7,6 +7,12 @@ LL | drop(foo); | --- value moved here LL | match foo { | ^^^^^^^^^ value used here after move + | +note: if `X` implemented `Clone`, you could clone the value + --> $DIR/issue-17385.rs:1:1 + | +LL | struct X(isize); + | ^^^^^^^^ error[E0382]: use of moved value: `e` --> $DIR/issue-17385.rs:25:11 @@ -17,6 +23,12 @@ LL | drop(e); | - value moved here LL | match e { | ^ value used here after move + | +note: if `Enum` implemented `Clone`, you could clone the value + --> $DIR/issue-17385.rs:3:1 + | +LL | enum Enum { + | ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-17551.stderr b/tests/ui/issues/issue-17551.stderr index 68f54a31084..b9cb76fc298 100644 --- a/tests/ui/issues/issue-17551.stderr +++ b/tests/ui/issues/issue-17551.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `B<T>` +error[E0282]: type annotations needed for `B<_>` --> $DIR/issue-17551.rs:6:9 | LL | let foo = B(marker::PhantomData); diff --git a/tests/ui/issues/issue-21596.rs b/tests/ui/issues/issue-21596.rs deleted file mode 100644 index 79f6c91d9ac..00000000000 --- a/tests/ui/issues/issue-21596.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let x = 8u8; - let z: *const u8 = &x; - println!("{}", z.to_string()); //~ ERROR E0599 -} diff --git a/tests/ui/issues/issue-21596.stderr b/tests/ui/issues/issue-21596.stderr deleted file mode 100644 index 8a7fca5f436..00000000000 --- a/tests/ui/issues/issue-21596.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0599]: `*const u8` doesn't implement `std::fmt::Display` - --> $DIR/issue-21596.rs:4:22 - | -LL | println!("{}", z.to_string()); - | ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter - | - = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref - = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior - = note: the following trait bounds were not satisfied: - `*const u8: std::fmt::Display` - which is required by `*const u8: ToString` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/issues/issue-21763.rs b/tests/ui/issues/issue-21763.rs index a349253063c..1d0a0705cbb 100644 --- a/tests/ui/issues/issue-21763.rs +++ b/tests/ui/issues/issue-21763.rs @@ -1,6 +1,6 @@ // Regression test for HashMap only impl'ing Send/Sync if its contents do -//@ normalize-stderr-test: "\S+hashbrown-\S+" -> "$$HASHBROWN_SRC_LOCATION" +//@ normalize-stderr-test: "\S+[\\/]hashbrown\S+" -> "$$HASHBROWN_SRC_LOCATION" use std::collections::HashMap; use std::rc::Rc; diff --git a/tests/ui/issues/issue-22034.rs b/tests/ui/issues/issue-22034.rs index ed741779f68..3631c2368fe 100644 --- a/tests/ui/issues/issue-22034.rs +++ b/tests/ui/issues/issue-22034.rs @@ -1,7 +1,3 @@ -#![feature(rustc_private)] - -extern crate libc; - fn main() { let ptr: *mut () = core::ptr::null_mut(); let _: &mut dyn Fn() = unsafe { diff --git a/tests/ui/issues/issue-22034.stderr b/tests/ui/issues/issue-22034.stderr index 6d899618d7a..75ddcd47899 100644 --- a/tests/ui/issues/issue-22034.stderr +++ b/tests/ui/issues/issue-22034.stderr @@ -1,5 +1,5 @@ error[E0277]: expected a `Fn()` closure, found `()` - --> $DIR/issue-22034.rs:8:16 + --> $DIR/issue-22034.rs:4:16 | LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn()` closure, found `()` diff --git a/tests/ui/issues/issue-2214.rs b/tests/ui/issues/issue-2214.rs index 5d732cd7798..453bb58a622 100644 --- a/tests/ui/issues/issue-2214.rs +++ b/tests/ui/issues/issue-2214.rs @@ -1,11 +1,8 @@ //@ run-pass //@ ignore-wasm32 wasi-libc does not have lgamma //@ ignore-sgx no libc -#![feature(rustc_private)] -extern crate libc; - -use libc::{c_double, c_int}; +use std::ffi::{c_double, c_int}; use std::mem; fn to_c_int(v: &mut isize) -> &mut c_int { @@ -19,8 +16,7 @@ fn lgamma(n: c_double, value: &mut isize) -> c_double { } mod m { - use libc::{c_double, c_int}; - + use std::ffi::{c_double, c_int}; extern "C" { #[cfg(all(unix, not(target_os = "vxworks")))] #[link_name="lgamma_r"] diff --git a/tests/ui/issues/issue-23046.stderr b/tests/ui/issues/issue-23046.stderr index b6e23814543..f70ac0c9f38 100644 --- a/tests/ui/issues/issue-23046.stderr +++ b/tests/ui/issues/issue-23046.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Expr<'_, VAR>` +error[E0282]: type annotations needed for `Expr<'_, _>` --> $DIR/issue-23046.rs:17:15 | LL | let ex = |x| { diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/issues/issue-24357.rs index 152e69ebc87..d1a9e37251e 100644 --- a/tests/ui/issues/issue-24357.rs +++ b/tests/ui/issues/issue-24357.rs @@ -1,4 +1,4 @@ -struct NoCopy; +struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value fn main() { let x = NoCopy; //~^ NOTE move occurs because `x` has type `NoCopy` diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/issues/issue-24357.stderr index 08a5a8ac56e..6d50eea7e21 100644 --- a/tests/ui/issues/issue-24357.stderr +++ b/tests/ui/issues/issue-24357.stderr @@ -11,6 +11,12 @@ LL | let f = move || { let y = x; }; ... LL | let z = x; | ^ value used here after move + | +note: if `NoCopy` implemented `Clone`, you could clone the value + --> $DIR/issue-24357.rs:1:1 + | +LL | struct NoCopy; + | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-2590.stderr b/tests/ui/issues/issue-2590.stderr index 517b4814eae..822856652e9 100644 --- a/tests/ui/issues/issue-2590.stderr +++ b/tests/ui/issues/issue-2590.stderr @@ -3,6 +3,11 @@ error[E0507]: cannot move out of `self.tokens` which is behind a shared referenc | LL | self.tokens | ^^^^^^^^^^^ move occurs because `self.tokens` has type `Vec<isize>`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | self.tokens.clone() + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27042.stderr b/tests/ui/issues/issue-27042.stderr index 01532de999e..ba39399e46e 100644 --- a/tests/ui/issues/issue-27042.stderr +++ b/tests/ui/issues/issue-27042.stderr @@ -19,7 +19,7 @@ LL | loop { break }; | | | this loop is expected to be of type `i32` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | loop { break 42 }; | ++ diff --git a/tests/ui/issues/issue-28433.stderr b/tests/ui/issues/issue-28433.stderr index 5fb8a89621c..0fa67e35f1d 100644 --- a/tests/ui/issues/issue-28433.stderr +++ b/tests/ui/issues/issue-28433.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-28433.rs:2:5 | LL | pub Duck, - | ^^^ + | ^^^ help: remove the qualifier | = note: enum variants and their fields always share the visibility of the enum they are in @@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-28433.rs:5:5 | LL | pub(crate) Dove - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: remove the qualifier | = note: enum variants and their fields always share the visibility of the enum they are in diff --git a/tests/ui/issues/issue-3656.rs b/tests/ui/issues/issue-3656.rs index 1b65129d0c3..975695e497f 100644 --- a/tests/ui/issues/issue-3656.rs +++ b/tests/ui/issues/issue-3656.rs @@ -6,10 +6,8 @@ // the alignment of elements into account. //@ pretty-expanded FIXME #23616 -#![feature(rustc_private)] -extern crate libc; -use libc::{c_uint, c_void}; +use std::ffi::{c_uint, c_void}; pub struct KEYGEN { hash_algorithm: [c_uint; 2], diff --git a/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr b/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr index 7976d090542..d27b6e6324f 100644 --- a/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr +++ b/tests/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr @@ -8,6 +8,10 @@ help: consider borrowing here | LL | let e = &f.v[0]; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let e = f.v[0].clone(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index 1967b51128f..b765d2f087d 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -16,15 +16,15 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: + <&'a f128 as Add<f128>> + <&'a f16 as Add<f16>> <&'a f32 as Add<f32>> <&'a f64 as Add<f64>> <&'a i128 as Add<i128>> <&'a i16 as Add<i16>> <&'a i32 as Add<i32>> <&'a i64 as Add<i64>> - <&'a i8 as Add<i8>> - <&'a isize as Add<isize>> - and 48 others + and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-52262.stderr b/tests/ui/issues/issue-52262.stderr index ce8e6fe2bf8..51959f22b97 100644 --- a/tests/ui/issues/issue-52262.stderr +++ b/tests/ui/issues/issue-52262.stderr @@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference | LL | String::from_utf8(*key).unwrap() | ^^^^ move occurs because `*key` has type `Vec<u8>`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - String::from_utf8(*key).unwrap() +LL + String::from_utf8(key.clone()).unwrap() + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-98299.stderr b/tests/ui/issues/issue-98299.stderr index e99d8e5cc80..becf16d1db9 100644 --- a/tests/ui/issues/issue-98299.stderr +++ b/tests/ui/issues/issue-98299.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `SmallCString<N>` +error[E0282]: type annotations needed for `SmallCString<_>` --> $DIR/issue-98299.rs:4:36 | LL | SmallCString::try_from(p).map(|cstr| cstr); diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs new file mode 100644 index 00000000000..b1c33e15075 --- /dev/null +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs @@ -0,0 +1,17 @@ +// ICE !base.layout().is_sized() +// issue: rust-lang/rust#123078 + +struct S { + a: [u8], + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + b: (), +} + +const C: S = unsafe { std::mem::transmute(()) }; +//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types +const _: [(); { + C; + 0 +}] = []; + +pub fn main() {} diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr new file mode 100644 index 00000000000..7e0a41a4367 --- /dev/null +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr @@ -0,0 +1,31 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/base-layout-is-sized-ice-123078.rs:5:8 + | +LL | a: [u8], + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | a: &[u8], + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | a: Box<[u8]>, + | ++++ + + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/base-layout-is-sized-ice-123078.rs:10:23 + | +LL | const C: S = unsafe { std::mem::transmute(()) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `()` (0 bits) + = note: target type: `S` (this type does not have a fixed size) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0512. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs new file mode 100644 index 00000000000..96c993035ef --- /dev/null +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs @@ -0,0 +1,10 @@ +// ICE Unexpected unsized type tail: &ReStatic [u8] +// issue: rust-lang/rust#122488 +use std::ops::Deref; + +struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U); +//~^ ERROR the size for values of type `V` cannot be known at compilation time + +const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut(); + +pub fn main() {} diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr new file mode 100644 index 00000000000..f39cb29868a --- /dev/null +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr @@ -0,0 +1,27 @@ +error[E0277]: the size for values of type `V` cannot be known at compilation time + --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:5:61 + | +LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U); + | -------------------------------- ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U); +LL + struct ArenaSet<U: Deref, V = <U as Deref>::Target>(V, U); + | +help: borrowed types always have a statically known size + | +LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(&V, U); + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(Box<V>, U); + | ++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs new file mode 100644 index 00000000000..8426b0021f4 --- /dev/null +++ b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs @@ -0,0 +1,8 @@ +// https://github.com/rust-lang/rust/issues/123844 +// An uninitialized refutable let should not suggest `let else`, as it can't be used with deferred +// initialization. + +fn main() { + let Some(x); //~ ERROR refutable pattern in local binding + x = 1; +} diff --git a/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr new file mode 100644 index 00000000000..13312306c07 --- /dev/null +++ b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr @@ -0,0 +1,13 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/uninitialized-refutable-let-issue-123844.rs:6:9 + | +LL | let Some(x); + | ^^^^^^^ pattern `None` 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 `Option<i32>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs new file mode 100644 index 00000000000..caae48dfd3b --- /dev/null +++ b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.rs @@ -0,0 +1,9 @@ +//@ edition:2021 +macro_rules! a { + ( ) => { + impl<'b> c for d { + e::<f'g> //~ ERROR prefix `f` is unknown + } + }; +} +fn main() {} diff --git a/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr new file mode 100644 index 00000000000..ecce2c66504 --- /dev/null +++ b/tests/ui/lexer/dont-ice-on-invalid-lifetime-in-macro-definition.stderr @@ -0,0 +1,14 @@ +error: prefix `f` is unknown + --> $DIR/dont-ice-on-invalid-lifetime-in-macro-definition.rs:5:17 + | +LL | e::<f'g> + | ^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | e::<f 'g> + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 0ae227da5f1..52781d9c6d8 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -3,5 +3,6 @@ //@[rust2021] edition:2021 fn main() { println!('hello world'); - //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal + //~^ ERROR unterminated character literal + //[rust2021]~| ERROR prefix `world` is unknown } diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr index 06f12742667..4170560cfcb 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -1,3 +1,15 @@ +error: prefix `world` is unknown + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 + | +LL | println!('hello world'); + | ^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | @@ -9,6 +21,6 @@ help: if you meant to write a string literal, use double quotes LL | println!("hello world"); | ~ ~ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-4.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-4.rs new file mode 100644 index 00000000000..f0c7ad8f82b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-4.rs @@ -0,0 +1,9 @@ +//@edition:2021 +macro_rules! foo { + () => { + println!('hello world'); + //~^ ERROR unterminated character literal + //~| ERROR prefix `world` is unknown + } +} +fn main() {} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr new file mode 100644 index 00000000000..af42b5b7f7b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-4.stderr @@ -0,0 +1,26 @@ +error: prefix `world` is unknown + --> $DIR/lex-bad-str-literal-as-char-4.rs:4:25 + | +LL | println!('hello world'); + | ^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-4.rs:4:30 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lifetimes/temporary-lifetime-extension.rs b/tests/ui/lifetimes/temporary-lifetime-extension.rs new file mode 100644 index 00000000000..1ecef2f3d04 --- /dev/null +++ b/tests/ui/lifetimes/temporary-lifetime-extension.rs @@ -0,0 +1,33 @@ +//@ check-pass + +fn temp() -> (String, i32) { + (String::from("Hello"), 1) +} + +fn main() { + let a = &temp(); + let b = [(&temp(),)]; + let c = &temp().0; + let d = &temp().0[..]; + let e = { + let _ = 123; + &(*temp().0)[..] + }; + let f = if true { + &temp() + } else { + &temp() + }; + let g = match true { + true => &temp(), + false => { + let _ = 123; + &temp() + } + }; + let h = match temp() { + // The {} moves the value, making a new temporary. + owned_non_temporary => &{ owned_non_temporary }, + }; + println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?} {h:?}"); +} diff --git a/tests/ui/issues/auxiliary/issue-12133-dylib.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs index 8bd2b3353b8..8bd2b3353b8 100644 --- a/tests/ui/issues/auxiliary/issue-12133-dylib.rs +++ b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs diff --git a/tests/ui/issues/auxiliary/issue-12133-dylib2.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs index 42e13ad6908..42e13ad6908 100644 --- a/tests/ui/issues/auxiliary/issue-12133-dylib2.rs +++ b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs diff --git a/tests/ui/issues/auxiliary/issue-12133-rlib.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs index 1adaf2b0379..1adaf2b0379 100644 --- a/tests/ui/issues/auxiliary/issue-12133-rlib.rs +++ b/tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr index 5cb4d391437..23e017cb012 100644 --- a/tests/ui/linkage-attr/framework.omit.stderr +++ b/tests/ui/linkage-attr/framework.omit.stderr @@ -1,4 +1,4 @@ -error: linking with `cc` failed: exit status: 1 +error: linking with `LINKER` failed: exit status: 1 | ld: Undefined symbols: _CFRunLoopGetTypeID, referenced from: diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs index 662ef4c429d..824adf62206 100644 --- a/tests/ui/linkage-attr/framework.rs +++ b/tests/ui/linkage-attr/framework.rs @@ -6,8 +6,10 @@ //@ [weak]run-pass //@ [both]run-pass -// The linker's exact error output changes between Xcode versions. +// The linker's exact error output changes between Xcode versions, depends on +// linker invocation details, and the linker sometimes outputs more warnings. //@ compare-output-lines-by-subset +//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed" //@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:" //@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID," diff --git a/tests/ui/issues/issue-12133-1.rs b/tests/ui/linkage-attr/issue-12133-1.rs index dc3f7f33da1..dc3f7f33da1 100644 --- a/tests/ui/issues/issue-12133-1.rs +++ b/tests/ui/linkage-attr/issue-12133-1.rs diff --git a/tests/ui/issues/issue-12133-2.rs b/tests/ui/linkage-attr/issue-12133-2.rs index 55742a1b383..55742a1b383 100644 --- a/tests/ui/issues/issue-12133-2.rs +++ b/tests/ui/linkage-attr/issue-12133-2.rs diff --git a/tests/ui/issues/issue-12133-3.rs b/tests/ui/linkage-attr/issue-12133-3.rs index a34c075d64d..a34c075d64d 100644 --- a/tests/ui/issues/issue-12133-3.rs +++ b/tests/ui/linkage-attr/issue-12133-3.rs diff --git a/tests/ui/linkage-attr/uikit-framework.rs b/tests/ui/linkage-attr/uikit-framework.rs new file mode 100644 index 00000000000..fca0332384a --- /dev/null +++ b/tests/ui/linkage-attr/uikit-framework.rs @@ -0,0 +1,25 @@ +//! Check that linking to UIKit on platforms where that is available works. +//@ revisions: ios tvos watchos visionos +//@ [ios]only-ios +//@ [tvos]only-tvos +//@ [watchos]only-watchos +//@ [visionos]only-visionos +//@ build-pass + +use std::ffi::{c_char, c_int, c_void}; + +#[link(name = "UIKit", kind = "framework")] +extern "C" { + pub fn UIApplicationMain( + argc: c_int, + argv: *const c_char, + principalClassName: *const c_void, + delegateClassName: *const c_void, + ) -> c_int; +} + +pub fn main() { + unsafe { + UIApplicationMain(0, core::ptr::null(), core::ptr::null(), core::ptr::null()); + } +} diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/lint-ctypes-fn.rs index 14831e24718..73820c86d1a 100644 --- a/tests/ui/lint/lint-ctypes-fn.rs +++ b/tests/ui/lint/lint-ctypes-fn.rs @@ -1,12 +1,9 @@ -#![feature(rustc_private)] - #![allow(private_interfaces)] #![deny(improper_ctypes_definitions)] -extern crate libc; - use std::default::Default; use std::marker::PhantomData; +use std::ffi::{c_int, c_uint}; trait Trait {} @@ -165,10 +162,10 @@ pub extern "C" fn good17(p: TransparentCustomZst) { } pub extern "C" fn good18(_: &String) { } #[cfg(not(target_arch = "wasm32"))] -pub extern "C" fn good1(size: *const libc::c_int) { } +pub extern "C" fn good1(size: *const c_int) { } #[cfg(not(target_arch = "wasm32"))] -pub extern "C" fn good2(size: *const libc::c_uint) { } +pub extern "C" fn good2(size: *const c_uint) { } pub extern "C" fn unused_generic1<T>(size: *const Foo) { } diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/lint-ctypes-fn.stderr index a05206bf18d..a62533a4be1 100644 --- a/tests/ui/lint/lint-ctypes-fn.stderr +++ b/tests/ui/lint/lint-ctypes-fn.stderr @@ -1,5 +1,5 @@ error: `extern` fn uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:73:33 + --> $DIR/lint-ctypes-fn.rs:70:33 | LL | pub extern "C" fn slice_type(p: &[u32]) { } | ^^^^^^ not FFI-safe @@ -7,13 +7,13 @@ LL | pub extern "C" fn slice_type(p: &[u32]) { } = help: consider using a raw pointer instead = note: slices have no C equivalent note: the lint level is defined here - --> $DIR/lint-ctypes-fn.rs:4:9 + --> $DIR/lint-ctypes-fn.rs:2:9 | LL | #![deny(improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:76:31 + --> $DIR/lint-ctypes-fn.rs:73:31 | LL | pub extern "C" fn str_type(p: &str) { } | ^^^^ not FFI-safe @@ -22,7 +22,7 @@ LL | pub extern "C" fn str_type(p: &str) { } = note: string slices have no C equivalent error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:83:34 + --> $DIR/lint-ctypes-fn.rs:80:34 | LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } | ^^^^^^^^^ not FFI-safe @@ -30,7 +30,7 @@ LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box<str>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:86:35 + --> $DIR/lint-ctypes-fn.rs:83:35 | LL | pub extern "C" fn boxed_string(p: Box<str>) { } | ^^^^^^^^ not FFI-safe @@ -38,7 +38,7 @@ LL | pub extern "C" fn boxed_string(p: Box<str>) { } = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:89:34 + --> $DIR/lint-ctypes-fn.rs:86:34 | LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -46,7 +46,7 @@ LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { } = note: box cannot be represented as a single pointer error: `extern` fn uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:92:32 + --> $DIR/lint-ctypes-fn.rs:89:32 | LL | pub extern "C" fn char_type(p: char) { } | ^^^^ not FFI-safe @@ -55,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { } = note: the `char` type has no C equivalent error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:95:32 + --> $DIR/lint-ctypes-fn.rs:92:32 | LL | pub extern "C" fn i128_type(p: i128) { } | ^^^^ not FFI-safe @@ -63,7 +63,7 @@ LL | pub extern "C" fn i128_type(p: i128) { } = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:98:32 + --> $DIR/lint-ctypes-fn.rs:95:32 | LL | pub extern "C" fn u128_type(p: u128) { } | ^^^^ not FFI-safe @@ -71,7 +71,7 @@ LL | pub extern "C" fn u128_type(p: u128) { } = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:101:33 + --> $DIR/lint-ctypes-fn.rs:98:33 | LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } | ^^^^^^^^^^ not FFI-safe @@ -80,7 +80,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } = note: tuples have unspecified layout error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:104:34 + --> $DIR/lint-ctypes-fn.rs:101:34 | LL | pub extern "C" fn tuple_type2(p: I32Pair) { } | ^^^^^^^ not FFI-safe @@ -89,7 +89,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { } = note: tuples have unspecified layout error: `extern` fn uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:107:32 + --> $DIR/lint-ctypes-fn.rs:104:32 | LL | pub extern "C" fn zero_size(p: ZeroSize) { } | ^^^^^^^^ not FFI-safe @@ -97,26 +97,26 @@ LL | pub extern "C" fn zero_size(p: ZeroSize) { } = help: consider adding a member to this struct = note: this struct has no fields note: the type is defined here - --> $DIR/lint-ctypes-fn.rs:28:1 + --> $DIR/lint-ctypes-fn.rs:25:1 | LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:110:40 + --> $DIR/lint-ctypes-fn.rs:107:40 | LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { } | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: composed only of `PhantomData` note: the type is defined here - --> $DIR/lint-ctypes-fn.rs:63:1 + --> $DIR/lint-ctypes-fn.rs:60:1 | LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:113:51 + --> $DIR/lint-ctypes-fn.rs:110:51 | LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -124,7 +124,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> { = note: composed only of `PhantomData` error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:118:30 + --> $DIR/lint-ctypes-fn.rs:115:30 | LL | pub extern "C" fn fn_type(p: RustFn) { } | ^^^^^^ not FFI-safe @@ -133,7 +133,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { } = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:121:31 + --> $DIR/lint-ctypes-fn.rs:118:31 | LL | pub extern "C" fn fn_type2(p: fn()) { } | ^^^^ not FFI-safe @@ -142,7 +142,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { } = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:126:39 + --> $DIR/lint-ctypes-fn.rs:123:39 | LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } | ^^^^^^^^^^^^^^^ not FFI-safe @@ -150,7 +150,7 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:129:38 + --> $DIR/lint-ctypes-fn.rs:126:38 | LL | pub extern "C" fn transparent_str(p: TransparentStr) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +159,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { } = note: string slices have no C equivalent error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:175:43 + --> $DIR/lint-ctypes-fn.rs:172:43 | LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +167,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> { = note: composed only of `PhantomData` error: `extern` fn uses type `Vec<T>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:188:39 + --> $DIR/lint-ctypes-fn.rs:185:39 | LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { } | ^^^^^^ not FFI-safe @@ -176,7 +176,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { } = note: this struct has unspecified layout error: `extern` fn uses type `Vec<T>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:191:41 + --> $DIR/lint-ctypes-fn.rs:188:41 | LL | pub extern "C" fn used_generic5<T>() -> Vec<T> { | ^^^^^^ not FFI-safe diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs index 3dd731625f4..dae07930aba 100644 --- a/tests/ui/lint/lint-ctypes.rs +++ b/tests/ui/lint/lint-ctypes.rs @@ -3,10 +3,9 @@ #![allow(private_interfaces)] #![deny(improper_ctypes)] -extern crate libc; - use std::cell::UnsafeCell; use std::marker::PhantomData; +use std::ffi::{c_int, c_uint}; trait Bar { } trait Mirror { type It: ?Sized; } @@ -110,8 +109,8 @@ extern "C" { #[cfg(not(target_arch = "wasm32"))] extern "C" { - pub fn good1(size: *const libc::c_int); - pub fn good2(size: *const libc::c_uint); + pub fn good1(size: *const c_int); + pub fn good2(size: *const c_uint); } fn main() { diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr index 121ad0ce8fa..2c81c7b8e4b 100644 --- a/tests/ui/lint/lint-ctypes.stderr +++ b/tests/ui/lint/lint-ctypes.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `Foo`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:48:28 + --> $DIR/lint-ctypes.rs:47:28 | LL | pub fn ptr_type1(size: *const Foo); | ^^^^^^^^^^ not FFI-safe @@ -7,7 +7,7 @@ LL | pub fn ptr_type1(size: *const Foo); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes.rs:26:1 + --> $DIR/lint-ctypes.rs:25:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `Foo`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:49:28 + --> $DIR/lint-ctypes.rs:48:28 | LL | pub fn ptr_type2(size: *const Foo); | ^^^^^^^^^^ not FFI-safe @@ -26,13 +26,13 @@ LL | pub fn ptr_type2(size: *const Foo); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes.rs:26:1 + --> $DIR/lint-ctypes.rs:25:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^ error: `extern` block uses type `((),)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:51:25 + --> $DIR/lint-ctypes.rs:50:25 | LL | pub fn ptr_tuple(p: *const ((),)); | ^^^^^^^^^^^^ not FFI-safe @@ -41,7 +41,7 @@ LL | pub fn ptr_tuple(p: *const ((),)); = note: tuples have unspecified layout error: `extern` block uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:52:26 + --> $DIR/lint-ctypes.rs:51:26 | LL | pub fn slice_type(p: &[u32]); | ^^^^^^ not FFI-safe @@ -50,7 +50,7 @@ LL | pub fn slice_type(p: &[u32]); = note: slices have no C equivalent error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:53:24 + --> $DIR/lint-ctypes.rs:52:24 | LL | pub fn str_type(p: &str); | ^^^^ not FFI-safe @@ -59,7 +59,7 @@ LL | pub fn str_type(p: &str); = note: string slices have no C equivalent error: `extern` block uses type `Box<u32>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:54:24 + --> $DIR/lint-ctypes.rs:53:24 | LL | pub fn box_type(p: Box<u32>); | ^^^^^^^^ not FFI-safe @@ -68,7 +68,7 @@ LL | pub fn box_type(p: Box<u32>); = note: this struct has unspecified layout error: `extern` block uses type `Option<Box<u32>>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:55:28 + --> $DIR/lint-ctypes.rs:54:28 | LL | pub fn opt_box_type(p: Option<Box<u32>>); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -77,7 +77,7 @@ LL | pub fn opt_box_type(p: Option<Box<u32>>); = note: enum has no representation hint error: `extern` block uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:57:25 + --> $DIR/lint-ctypes.rs:56:25 | LL | pub fn char_type(p: char); | ^^^^ not FFI-safe @@ -86,7 +86,7 @@ LL | pub fn char_type(p: char); = note: the `char` type has no C equivalent error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:58:25 + --> $DIR/lint-ctypes.rs:57:25 | LL | pub fn i128_type(p: i128); | ^^^^ not FFI-safe @@ -94,7 +94,7 @@ LL | pub fn i128_type(p: i128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:59:25 + --> $DIR/lint-ctypes.rs:58:25 | LL | pub fn u128_type(p: u128); | ^^^^ not FFI-safe @@ -102,7 +102,7 @@ LL | pub fn u128_type(p: u128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `dyn Bar`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:60:26 + --> $DIR/lint-ctypes.rs:59:26 | LL | pub fn trait_type(p: &dyn Bar); | ^^^^^^^^ not FFI-safe @@ -110,7 +110,7 @@ LL | pub fn trait_type(p: &dyn Bar); = note: trait objects have no C equivalent error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:61:26 + --> $DIR/lint-ctypes.rs:60:26 | LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ not FFI-safe @@ -119,7 +119,7 @@ LL | pub fn tuple_type(p: (i32, i32)); = note: tuples have unspecified layout error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:62:27 + --> $DIR/lint-ctypes.rs:61:27 | LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ not FFI-safe @@ -128,7 +128,7 @@ LL | pub fn tuple_type2(p: I32Pair); = note: tuples have unspecified layout error: `extern` block uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:63:25 + --> $DIR/lint-ctypes.rs:62:25 | LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ not FFI-safe @@ -136,26 +136,26 @@ LL | pub fn zero_size(p: ZeroSize); = help: consider adding a member to this struct = note: this struct has no fields note: the type is defined here - --> $DIR/lint-ctypes.rs:22:1 + --> $DIR/lint-ctypes.rs:21:1 | LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:64:33 + --> $DIR/lint-ctypes.rs:63:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: composed only of `PhantomData` note: the type is defined here - --> $DIR/lint-ctypes.rs:45:1 + --> $DIR/lint-ctypes.rs:44:1 | LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:67:12 + --> $DIR/lint-ctypes.rs:66:12 | LL | -> ::std::marker::PhantomData<bool>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -163,7 +163,7 @@ LL | -> ::std::marker::PhantomData<bool>; = note: composed only of `PhantomData` error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:68:23 + --> $DIR/lint-ctypes.rs:67:23 | LL | pub fn fn_type(p: RustFn); | ^^^^^^ not FFI-safe @@ -172,7 +172,7 @@ LL | pub fn fn_type(p: RustFn); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:69:24 + --> $DIR/lint-ctypes.rs:68:24 | LL | pub fn fn_type2(p: fn()); | ^^^^ not FFI-safe @@ -181,7 +181,7 @@ LL | pub fn fn_type2(p: fn()); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `Box<u32>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:70:28 + --> $DIR/lint-ctypes.rs:69:28 | LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ not FFI-safe @@ -190,7 +190,7 @@ LL | pub fn fn_contained(p: RustBadRet); = note: this struct has unspecified layout error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:71:32 + --> $DIR/lint-ctypes.rs:70:32 | LL | pub fn transparent_i128(p: TransparentI128); | ^^^^^^^^^^^^^^^ not FFI-safe @@ -198,7 +198,7 @@ LL | pub fn transparent_i128(p: TransparentI128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:72:31 + --> $DIR/lint-ctypes.rs:71:31 | LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ not FFI-safe @@ -207,7 +207,7 @@ LL | pub fn transparent_str(p: TransparentStr); = note: string slices have no C equivalent error: `extern` block uses type `Box<u32>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:73:30 + --> $DIR/lint-ctypes.rs:72:30 | LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -216,7 +216,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn); = note: this struct has unspecified layout error: `extern` block uses type `[u8; 8]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:74:27 + --> $DIR/lint-ctypes.rs:73:27 | LL | pub fn raw_array(arr: [u8; 8]); | ^^^^^^^ not FFI-safe @@ -225,7 +225,7 @@ LL | pub fn raw_array(arr: [u8; 8]); = note: passing raw arrays by value is not FFI-safe error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:76:26 + --> $DIR/lint-ctypes.rs:75:26 | LL | pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -234,7 +234,7 @@ LL | pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>); = note: enum has no representation hint error: `extern` block uses type `Option<UnsafeCell<&i32>>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:78:26 + --> $DIR/lint-ctypes.rs:77:26 | LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -243,7 +243,7 @@ LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:81:34 + --> $DIR/lint-ctypes.rs:80:34 | LL | pub static static_u128_type: u128; | ^^^^ not FFI-safe @@ -251,7 +251,7 @@ LL | pub static static_u128_type: u128; = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:82:40 + --> $DIR/lint-ctypes.rs:81:40 | LL | pub static static_u128_array_type: [u128; 16]; | ^^^^^^^^^^ not FFI-safe diff --git a/tests/ui/lint/auxiliary/non_local_macro.rs b/tests/ui/lint/non-local-defs/auxiliary/non_local_macro.rs index 8c0ff8adda1..8c0ff8adda1 100644 --- a/tests/ui/lint/auxiliary/non_local_macro.rs +++ b/tests/ui/lint/non-local-defs/auxiliary/non_local_macro.rs diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs new file mode 100644 index 00000000000..8b8c15795d3 --- /dev/null +++ b/tests/ui/lint/non-local-defs/cargo-update.rs @@ -0,0 +1,20 @@ +//@ check-pass +//@ edition:2021 +//@ aux-build:non_local_macro.rs +// +// To suggest any Cargo specific help/note rustc wants +// the `CARGO_CRATE_NAME` env to be set, so we set it +//@ rustc-env:CARGO_CRATE_NAME=non_local_def +// +// and since we specifically want to check the presence +// of the `cargo update` suggestion we assert it here. +//@ error-pattern: `cargo update -p non_local_macro` + +extern crate non_local_macro; + +struct LocalStruct; + +non_local_macro::non_local_impl!(LocalStruct); +//~^ WARN non-local `impl` definition + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr new file mode 100644 index 00000000000..e9e33b9aa17 --- /dev/null +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -0,0 +1,16 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/cargo-update.rs:17:1 + | +LL | non_local_macro::non_local_impl!(LocalStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: `#[warn(non_local_definitions)]` on by default + = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs new file mode 100644 index 00000000000..2652447dcf5 --- /dev/null +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -0,0 +1,88 @@ +//@ check-pass +//@ edition:2021 +//@ rustc-env:CARGO_CRATE_NAME=non_local_def + +#![feature(inline_const)] + +struct Test; + +trait Uto {} +const Z: () = { + trait Uto1 {} + + impl Uto1 for Test {} // the trait is local, don't lint + + impl Uto for &Test {} + //~^ WARN non-local `impl` definition +}; + +trait Ano {} +const _: () = { + impl Ano for &Test {} // ignored since the parent is an anon-const +}; + +trait Uto2 {} +static A: u32 = { + impl Uto2 for Test {} + //~^ WARN non-local `impl` definition + + 1 +}; + +trait Uto3 {} +const B: u32 = { + impl Uto3 for Test {} + //~^ WARN non-local `impl` definition + + trait Uto4 {} + impl Uto4 for Test {} + + 1 +}; + +trait Uto5 {} +fn main() { + impl Test { + //~^ WARN non-local `impl` definition + fn foo() {} + } + + + const { + impl Test { + //~^ WARN non-local `impl` definition + fn hoo() {} + } + + 1 + }; + + const _: u32 = { + impl Test { + //~^ WARN non-local `impl` definition + fn foo2() {} + } + + 1 + }; +} + +trait Uto9 {} +trait Uto10 {} +const _: u32 = { + let _a = || { + impl Uto9 for Test {} + //~^ WARN non-local `impl` definition + + 1 + }; + + type A = [u32; { + impl Uto10 for Test {} + //~^ WARN non-local `impl` definition + + 1 + }]; + + 1 +}; diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr new file mode 100644 index 00000000000..5563ea9d93f --- /dev/null +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -0,0 +1,103 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:15:5 + | +LL | const Z: () = { + | - help: use a const-anon item to suppress this lint: `_` +... +LL | impl Uto for &Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `Z` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:26:5 + | +LL | impl Uto2 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current static `A` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:34:5 + | +LL | impl Uto3 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `B` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:45:5 + | +LL | / impl Test { +LL | | +LL | | fn foo() {} +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:52:9 + | +LL | / impl Test { +LL | | +LL | | fn hoo() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current inline constant `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:61:9 + | +LL | / impl Test { +LL | | +LL | | fn foo2() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current constant `_` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:74:9 + | +LL | impl Uto9 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:81:9 + | +LL | impl Uto10 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 8 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.rs b/tests/ui/lint/non-local-defs/exhaustive-trait.rs new file mode 100644 index 00000000000..40d2314460f --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.rs @@ -0,0 +1,48 @@ +//@ check-pass +//@ edition:2021 + +struct Dog; + +fn main() { + impl PartialEq<()> for Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &()) -> bool { + todo!() + } + } + + impl PartialEq<()> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &()) -> bool { + todo!() + } + } + + impl PartialEq<Dog> for () { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } + + impl PartialEq<&Dog> for () { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &&Dog) -> bool { + todo!() + } + } + + impl PartialEq<Dog> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } + + impl PartialEq<&Dog> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &&Dog) -> bool { + todo!() + } + } +} diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr new file mode 100644 index 00000000000..8d58d4dd27c --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr @@ -0,0 +1,99 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:7:5 + | +LL | / impl PartialEq<()> for Dog { +LL | | +LL | | fn eq(&self, _: &()) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:14:5 + | +LL | / impl PartialEq<()> for &Dog { +LL | | +LL | | fn eq(&self, _: &()) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:21:5 + | +LL | / impl PartialEq<Dog> for () { +LL | | +LL | | fn eq(&self, _: &Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:28:5 + | +LL | / impl PartialEq<&Dog> for () { +LL | | +LL | | fn eq(&self, _: &&Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:35:5 + | +LL | / impl PartialEq<Dog> for &Dog { +LL | | +LL | | fn eq(&self, _: &Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:42:5 + | +LL | / impl PartialEq<&Dog> for &Dog { +LL | | +LL | | fn eq(&self, _: &&Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 6 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/exhaustive.rs b/tests/ui/lint/non-local-defs/exhaustive.rs new file mode 100644 index 00000000000..2fb30f4344a --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive.rs @@ -0,0 +1,84 @@ +//@ check-pass +//@ edition:2021 + +use std::fmt::Display; + +trait Trait {} +struct Test; + +fn main() { + impl Test { + //~^ WARN non-local `impl` definition + fn foo() {} + } + + impl Display for Test { + //~^ WARN non-local `impl` definition + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl dyn Trait {} + //~^ WARN non-local `impl` definition + + impl<T: Trait> Trait for Vec<T> { } + //~^ WARN non-local `impl` definition + + impl Trait for &dyn Trait {} + //~^ WARN non-local `impl` definition + + impl Trait for *mut Test {} + //~^ WARN non-local `impl` definition + + impl Trait for *mut [Test] {} + //~^ WARN non-local `impl` definition + + impl Trait for [Test; 8] {} + //~^ WARN non-local `impl` definition + + impl Trait for (Test,) {} + //~^ WARN non-local `impl` definition + + impl Trait for fn(Test) -> () {} + //~^ WARN non-local `impl` definition + + impl Trait for fn() -> Test {} + //~^ WARN non-local `impl` definition + + let _a = || { + impl Trait for Test {} + //~^ WARN non-local `impl` definition + + 1 + }; + + struct InsideMain; + + impl Trait for *mut InsideMain {} + //~^ WARN non-local `impl` definition + impl Trait for *mut [InsideMain] {} + //~^ WARN non-local `impl` definition + impl Trait for [InsideMain; 8] {} + //~^ WARN non-local `impl` definition + impl Trait for (InsideMain,) {} + //~^ WARN non-local `impl` definition + impl Trait for fn(InsideMain) -> () {} + //~^ WARN non-local `impl` definition + impl Trait for fn() -> InsideMain {} + //~^ WARN non-local `impl` definition + + fn inside_inside() { + impl Display for InsideMain { + //~^ WARN non-local `impl` definition + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl InsideMain { + //~^ WARN non-local `impl` definition + fn bar() {} + } + } +} diff --git a/tests/ui/lint/non-local-defs/exhaustive.stderr b/tests/ui/lint/non-local-defs/exhaustive.stderr new file mode 100644 index 00000000000..b3697969c4f --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive.stderr @@ -0,0 +1,239 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:10:5 + | +LL | / impl Test { +LL | | +LL | | fn foo() {} +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:15:5 + | +LL | / impl Display for Test { +LL | | +LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:22:5 + | +LL | impl dyn Trait {} + | ^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:25:5 + | +LL | impl<T: Trait> Trait for Vec<T> { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:28:5 + | +LL | impl Trait for &dyn Trait {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:31:5 + | +LL | impl Trait for *mut Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:34:5 + | +LL | impl Trait for *mut [Test] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:37:5 + | +LL | impl Trait for [Test; 8] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:40:5 + | +LL | impl Trait for (Test,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:43:5 + | +LL | impl Trait for fn(Test) -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:46:5 + | +LL | impl Trait for fn() -> Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:50:9 + | +LL | impl Trait for Test {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:58:5 + | +LL | impl Trait for *mut InsideMain {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:60:5 + | +LL | impl Trait for *mut [InsideMain] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:62:5 + | +LL | impl Trait for [InsideMain; 8] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:64:5 + | +LL | impl Trait for (InsideMain,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:66:5 + | +LL | impl Trait for fn(InsideMain) -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:68:5 + | +LL | impl Trait for fn() -> InsideMain {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:72:9 + | +LL | / impl Display for InsideMain { +LL | | +LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +LL | | todo!() +LL | | } +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:79:9 + | +LL | / impl InsideMain { +LL | | +LL | | fn bar() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 20 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.rs b/tests/ui/lint/non-local-defs/from-local-for-global.rs new file mode 100644 index 00000000000..0ab3a6b1988 --- /dev/null +++ b/tests/ui/lint/non-local-defs/from-local-for-global.rs @@ -0,0 +1,103 @@ +//@ check-pass +//@ edition:2021 + +#![feature(inline_const)] + +struct Cat; +struct Wrap<T>(T); + +fn main() { + impl From<Cat> for () { + //~^ WARN non-local `impl` definition + fn from(_: Cat) -> () { + todo!() + } + } + + #[derive(Debug)] + struct Elephant; + + impl From<Wrap<Wrap<Elephant>>> for () { + //~^ WARN non-local `impl` definition + fn from(_: Wrap<Wrap<Elephant>>) -> Self { + todo!() + } + } +} + +pub trait StillNonLocal {} + +impl StillNonLocal for &str {} + +fn only_global() { + struct Foo; + impl StillNonLocal for &Foo {} + //~^ WARN non-local `impl` definition +} + +struct GlobalSameFunction; + +fn same_function() { + struct Local1(GlobalSameFunction); + impl From<Local1> for GlobalSameFunction { + //~^ WARN non-local `impl` definition + fn from(x: Local1) -> GlobalSameFunction { + x.0 + } + } + + struct Local2(GlobalSameFunction); + impl From<Local2> for GlobalSameFunction { + //~^ WARN non-local `impl` definition + fn from(x: Local2) -> GlobalSameFunction { + x.0 + } + } +} + +struct GlobalDifferentFunction; + +fn diff_function_1() { + struct Local(GlobalDifferentFunction); + + impl From<Local> for GlobalDifferentFunction { + // FIXME(Urgau): Should warn but doesn't since we currently consider + // the other impl to be "global", but that's not the case for the type-system + fn from(x: Local) -> GlobalDifferentFunction { + x.0 + } + } +} + +fn diff_function_2() { + struct Local(GlobalDifferentFunction); + + impl From<Local> for GlobalDifferentFunction { + // FIXME(Urgau): Should warn but doesn't since we currently consider + // the other impl to be "global", but that's not the case for the type-system + fn from(x: Local) -> GlobalDifferentFunction { + x.0 + } + } +} + +// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 +fn commonly_reported() { + struct Local(u8); + impl From<Local> for u8 { + fn from(x: Local) -> u8 { + x.0 + } + } +} + +// https://github.com/rust-lang/rust/issues/121621#issue-2153187542 +pub trait Serde {} + +impl Serde for &[u8] {} +impl Serde for &str {} + +fn serde() { + struct Thing; + impl Serde for &Thing {} +} diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr new file mode 100644 index 00000000000..bd592a72157 --- /dev/null +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -0,0 +1,78 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:10:5 + | +LL | / impl From<Cat> for () { +LL | | +LL | | fn from(_: Cat) -> () { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:20:5 + | +LL | / impl From<Wrap<Wrap<Elephant>>> for () { +LL | | +LL | | fn from(_: Wrap<Wrap<Elephant>>) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:34:5 + | +LL | impl StillNonLocal for &Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `only_global` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:42:5 + | +LL | / impl From<Local1> for GlobalSameFunction { +LL | | +LL | | fn from(x: Local1) -> GlobalSameFunction { +LL | | x.0 +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `same_function` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:50:5 + | +LL | / impl From<Local2> for GlobalSameFunction { +LL | | +LL | | fn from(x: Local2) -> GlobalSameFunction { +LL | | x.0 +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `same_function` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 5 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/generics.rs b/tests/ui/lint/non-local-defs/generics.rs new file mode 100644 index 00000000000..0f526526dba --- /dev/null +++ b/tests/ui/lint/non-local-defs/generics.rs @@ -0,0 +1,88 @@ +//@ check-pass +//@ edition:2021 + +trait Global {} + +fn main() { + trait Local {}; + + impl<T: Local> Global for Vec<T> { } + //~^ WARN non-local `impl` definition +} + +trait Uto7 {} +trait Uto8 {} + +struct Test; + +fn bad() { + struct Local; + impl Uto7 for Test where Local: std::any::Any {} + //~^ WARN non-local `impl` definition + + impl<T> Uto8 for T {} + //~^ WARN non-local `impl` definition +} + +struct UwU<T>(T); + +fn fun() { + #[derive(Debug)] + struct OwO; + impl Default for UwU<OwO> { + //~^ WARN non-local `impl` definition + fn default() -> Self { + UwU(OwO) + } + } +} + +fn meow() { + #[derive(Debug)] + struct Cat; + impl AsRef<Cat> for () { + //~^ WARN non-local `impl` definition + fn as_ref(&self) -> &Cat { &Cat } + } +} + +struct G; + +fn fun2() { + #[derive(Debug, Default)] + struct B; + impl PartialEq<B> for G { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &B) -> bool { + true + } + } +} + +struct Wrap<T>(T); + +impl Wrap<Wrap<Wrap<()>>> {} + +fn rawr() { + struct Lion; + + impl From<Wrap<Wrap<Lion>>> for () { + //~^ WARN non-local `impl` definition + fn from(_: Wrap<Wrap<Lion>>) -> Self { + todo!() + } + } + + impl From<()> for Wrap<Lion> { + //~^ WARN non-local `impl` definition + fn from(_: ()) -> Self { + todo!() + } + } +} + +fn side_effects() { + dbg!(().as_ref()); // prints `Cat` + dbg!(UwU::default().0); + let _ = G::eq(&G, dbg!(&<_>::default())); +} diff --git a/tests/ui/lint/non-local-defs/generics.stderr b/tests/ui/lint/non-local-defs/generics.stderr new file mode 100644 index 00000000000..681d9e45e7a --- /dev/null +++ b/tests/ui/lint/non-local-defs/generics.stderr @@ -0,0 +1,114 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:9:5 + | +LL | impl<T: Local> Global for Vec<T> { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:20:5 + | +LL | impl Uto7 for Test where Local: std::any::Any {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `bad` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:23:5 + | +LL | impl<T> Uto8 for T {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `bad` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:32:5 + | +LL | / impl Default for UwU<OwO> { +LL | | +LL | | fn default() -> Self { +LL | | UwU(OwO) +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `fun` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:43:5 + | +LL | / impl AsRef<Cat> for () { +LL | | +LL | | fn as_ref(&self) -> &Cat { &Cat } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `meow` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:54:5 + | +LL | / impl PartialEq<B> for G { +LL | | +LL | | fn eq(&self, _: &B) -> bool { +LL | | true +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `fun2` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:69:5 + | +LL | / impl From<Wrap<Wrap<Lion>>> for () { +LL | | +LL | | fn from(_: Wrap<Wrap<Lion>>) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:76:5 + | +LL | / impl From<()> for Wrap<Lion> { +LL | | +LL | | fn from(_: ()) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 8 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.rs b/tests/ui/lint/non-local-defs/inside-macro_rules.rs new file mode 100644 index 00000000000..9f21cc89852 --- /dev/null +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ edition:2021 + +macro_rules! m { + () => { + trait MacroTrait {} + struct OutsideStruct; + fn my_func() { + impl MacroTrait for OutsideStruct {} + //~^ WARN non-local `impl` definition + } + } +} + +m!(); + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr new file mode 100644 index 00000000000..319682b973d --- /dev/null +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -0,0 +1,18 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/inside-macro_rules.rs:9:13 + | +LL | impl MacroTrait for OutsideStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: move this `impl` block outside the of the current function `my_func` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/lint/non-local-defs/local.rs b/tests/ui/lint/non-local-defs/local.rs new file mode 100644 index 00000000000..166ee88c021 --- /dev/null +++ b/tests/ui/lint/non-local-defs/local.rs @@ -0,0 +1,53 @@ +//@ check-pass +//@ edition:2021 + +use std::fmt::Debug; + +trait GlobalTrait {} + +fn main() { + struct InsideMain; + + impl InsideMain { + fn foo() {} + } + + impl GlobalTrait for InsideMain {} + + impl Debug for InsideMain { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl PartialEq<()> for InsideMain { + fn eq(&self, _: &()) -> bool { + todo!() + } + } +} + +fn dyn_weirdness() { + trait LocalTrait {} + impl dyn LocalTrait {} + impl GlobalTrait for dyn LocalTrait {} +} + +struct Test; +mod do_not_lint_mod { + pub trait Tait {} + + impl super::Test { + fn hugo() {} + } + + impl Tait for super::Test {} +} + +fn bitflags() { + struct Flags; + + const _: () = { + impl Flags {} + }; +} diff --git a/tests/ui/lint/non-local-defs/macro_rules.rs b/tests/ui/lint/non-local-defs/macro_rules.rs new file mode 100644 index 00000000000..ed30a24903d --- /dev/null +++ b/tests/ui/lint/non-local-defs/macro_rules.rs @@ -0,0 +1,33 @@ +//@ check-pass +//@ edition:2021 +//@ aux-build:non_local_macro.rs +//@ rustc-env:CARGO_CRATE_NAME=non_local_def + +extern crate non_local_macro; + +const B: u32 = { + #[macro_export] + macro_rules! m0 { () => { } }; + //~^ WARN non-local `macro_rules!` definition + + 1 +}; + +non_local_macro::non_local_macro_rules!(my_macro); +//~^ WARN non-local `macro_rules!` definition + +fn main() { + #[macro_export] + macro_rules! m { () => { } }; + //~^ WARN non-local `macro_rules!` definition + + struct InsideMain; + + impl InsideMain { + fn bar() { + #[macro_export] + macro_rules! m2 { () => { } }; + //~^ WARN non-local `macro_rules!` definition + } + } +} diff --git a/tests/ui/lint/non-local-defs/macro_rules.stderr b/tests/ui/lint/non-local-defs/macro_rules.stderr new file mode 100644 index 00000000000..125d8e97d87 --- /dev/null +++ b/tests/ui/lint/non-local-defs/macro_rules.stderr @@ -0,0 +1,49 @@ +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:10:5 + | +LL | macro_rules! m0 { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:16:1 + | +LL | non_local_macro::non_local_macro_rules!(my_macro); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:21:5 + | +LL | macro_rules! m { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:29:13 + | +LL | macro_rules! m2 { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 2 bodies + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 4 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/weird-exprs.rs b/tests/ui/lint/non-local-defs/weird-exprs.rs new file mode 100644 index 00000000000..1d9cecea0c9 --- /dev/null +++ b/tests/ui/lint/non-local-defs/weird-exprs.rs @@ -0,0 +1,53 @@ +//@ check-pass +//@ edition:2021 + +trait Uto {} +struct Test; + +type A = [u32; { + impl Uto for *mut Test {} + //~^ WARN non-local `impl` definition + + 1 +}]; + +enum Enum { + Discr = { + impl Uto for Test {} + //~^ WARN non-local `impl` definition + + 1 + } +} + +fn main() { + let _array = [0i32; { + impl Test { + //~^ WARN non-local `impl` definition + fn bar() {} + } + + 1 + }]; + + type A = [u32; { + impl Uto for &Test {} + //~^ WARN non-local `impl` definition + + 1 + }]; + + fn a(_: [u32; { + impl Uto for &(Test,) {} + //~^ WARN non-local `impl` definition + + 1 + }]) {} + + fn b() -> [u32; { + impl Uto for &(Test,Test) {} + //~^ WARN non-local `impl` definition + + 1 + }] { todo!() } +} diff --git a/tests/ui/lint/non-local-defs/weird-exprs.stderr b/tests/ui/lint/non-local-defs/weird-exprs.stderr new file mode 100644 index 00000000000..015a0cce43b --- /dev/null +++ b/tests/ui/lint/non-local-defs/weird-exprs.stderr @@ -0,0 +1,72 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:8:5 + | +LL | impl Uto for *mut Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:16:9 + | +LL | impl Uto for Test {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:25:9 + | +LL | / impl Test { +LL | | +LL | | fn bar() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:34:9 + | +LL | impl Uto for &Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:41:9 + | +LL | impl Uto for &(Test,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:48:9 + | +LL | impl Uto for &(Test,Test) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> + +warning: 6 warnings emitted + diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs deleted file mode 100644 index 0b43e19d1e9..00000000000 --- a/tests/ui/lint/non_local_definitions.rs +++ /dev/null @@ -1,491 +0,0 @@ -//@ check-pass -//@ edition:2021 -//@ aux-build:non_local_macro.rs -//@ rustc-env:CARGO_CRATE_NAME=non_local_def - -#![feature(inline_const)] - -extern crate non_local_macro; - -use std::fmt::{Debug, Display}; - -struct Test; - -impl Debug for Test { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } -} - -mod do_not_lint_mod { - pub trait Tait {} - - impl super::Test { - fn hugo() {} - } - - impl Tait for super::Test {} -} - -trait Uto {} -const Z: () = { - trait Uto1 {} - - impl Uto1 for Test {} // the trait is local, don't lint - - impl Uto for &Test {} - //~^ WARN non-local `impl` definition -}; - -trait Ano {} -const _: () = { - impl Ano for &Test {} // ignored since the parent is an anon-const -}; - -type A = [u32; { - impl Uto for *mut Test {} - //~^ WARN non-local `impl` definition - - 1 -}]; - -enum Enum { - Discr = { - impl Uto for Test {} - //~^ WARN non-local `impl` definition - - 1 - } -} - -trait Uto2 {} -static A: u32 = { - impl Uto2 for Test {} - //~^ WARN non-local `impl` definition - - 1 -}; - -trait Uto3 {} -const B: u32 = { - impl Uto3 for Test {} - //~^ WARN non-local `impl` definition - - #[macro_export] - macro_rules! m0 { () => { } }; - //~^ WARN non-local `macro_rules!` definition - - trait Uto4 {} - impl Uto4 for Test {} - - 1 -}; - -trait Uto5 {} -fn main() { - #[macro_export] - macro_rules! m { () => { } }; - //~^ WARN non-local `macro_rules!` definition - - impl Test { - //~^ WARN non-local `impl` definition - fn foo() {} - } - - let _array = [0i32; { - impl Test { - //~^ WARN non-local `impl` definition - fn bar() {} - } - - 1 - }]; - - const { - impl Test { - //~^ WARN non-local `impl` definition - fn hoo() {} - } - - 1 - }; - - const _: u32 = { - impl Test { - //~^ WARN non-local `impl` definition - fn foo2() {} - } - - 1 - }; - - impl Display for Test { - //~^ WARN non-local `impl` definition - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl dyn Uto5 {} - //~^ WARN non-local `impl` definition - - impl<T: Uto5> Uto5 for Vec<T> { } - //~^ WARN non-local `impl` definition - - impl Uto5 for &dyn Uto5 {} - //~^ WARN non-local `impl` definition - - impl Uto5 for *mut Test {} - //~^ WARN non-local `impl` definition - - impl Uto5 for *mut [Test] {} - //~^ WARN non-local `impl` definition - - impl Uto5 for [Test; 8] {} - //~^ WARN non-local `impl` definition - - impl Uto5 for (Test,) {} - //~^ WARN non-local `impl` definition - - impl Uto5 for fn(Test) -> () {} - //~^ WARN non-local `impl` definition - - impl Uto5 for fn() -> Test {} - //~^ WARN non-local `impl` definition - - let _a = || { - impl Uto5 for Test {} - //~^ WARN non-local `impl` definition - - 1 - }; - - type A = [u32; { - impl Uto5 for &Test {} - //~^ WARN non-local `impl` definition - - 1 - }]; - - fn a(_: [u32; { - impl Uto5 for &(Test,) {} - //~^ WARN non-local `impl` definition - - 1 - }]) {} - - fn b() -> [u32; { - impl Uto5 for &(Test,Test) {} - //~^ WARN non-local `impl` definition - - 1 - }] { todo!() } - - struct InsideMain; - - impl Uto5 for *mut InsideMain {} - //~^ WARN non-local `impl` definition - impl Uto5 for *mut [InsideMain] {} - //~^ WARN non-local `impl` definition - impl Uto5 for [InsideMain; 8] {} - //~^ WARN non-local `impl` definition - impl Uto5 for (InsideMain,) {} - //~^ WARN non-local `impl` definition - impl Uto5 for fn(InsideMain) -> () {} - //~^ WARN non-local `impl` definition - impl Uto5 for fn() -> InsideMain {} - //~^ WARN non-local `impl` definition - - impl Debug for InsideMain { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl InsideMain { - fn foo() {} - } - - fn inside_inside() { - impl Display for InsideMain { - //~^ WARN non-local `impl` definition - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl InsideMain { - //~^ WARN non-local `impl` definition - fn bar() { - #[macro_export] - macro_rules! m2 { () => { } }; - //~^ WARN non-local `macro_rules!` definition - } - } - } - - trait Uto6 {} - impl dyn Uto6 {} - impl Uto5 for dyn Uto6 {} - - impl<T: Uto6> Uto3 for Vec<T> { } - //~^ WARN non-local `impl` definition -} - -trait Uto7 {} -trait Uto8 {} - -fn bad() { - struct Local; - impl Uto7 for Test where Local: std::any::Any {} - //~^ WARN non-local `impl` definition - - impl<T> Uto8 for T {} - //~^ WARN non-local `impl` definition -} - -trait Uto9 {} -trait Uto10 {} -const _: u32 = { - let _a = || { - impl Uto9 for Test {} - //~^ WARN non-local `impl` definition - - 1 - }; - - type A = [u32; { - impl Uto10 for Test {} - //~^ WARN non-local `impl` definition - - 1 - }]; - - 1 -}; - -struct UwU<T>(T); - -fn fun() { - #[derive(Debug)] - struct OwO; - impl Default for UwU<OwO> { - //~^ WARN non-local `impl` definition - fn default() -> Self { - UwU(OwO) - } - } -} - -struct Cat; - -fn meow() { - impl From<Cat> for () { - fn from(_: Cat) -> () { - todo!() - } - } - - #[derive(Debug)] - struct Cat; - impl AsRef<Cat> for () { - //~^ WARN non-local `impl` definition - fn as_ref(&self) -> &Cat { &Cat } - } -} - -struct G; - -fn fun2() { - #[derive(Debug, Default)] - struct B; - impl PartialEq<B> for G { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &B) -> bool { - true - } - } -} - -fn side_effects() { - dbg!(().as_ref()); // prints `Cat` - dbg!(UwU::default().0); - let _ = G::eq(&G, dbg!(&<_>::default())); -} - -struct Dog; - -fn woof() { - impl PartialEq<Dog> for &Dog { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &Dog) -> bool { - todo!() - } - } - - impl PartialEq<()> for Dog { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &()) -> bool { - todo!() - } - } - - impl PartialEq<()> for &Dog { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &()) -> bool { - todo!() - } - } - - impl PartialEq<Dog> for () { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &Dog) -> bool { - todo!() - } - } - - struct Test; - impl PartialEq<Dog> for Test { - fn eq(&self, _: &Dog) -> bool { - todo!() - } - } -} - -struct Wrap<T>(T); - -impl Wrap<Wrap<Wrap<()>>> {} - -fn rawr() { - struct Lion; - - impl From<Wrap<Wrap<Lion>>> for () { - //~^ WARN non-local `impl` definition - fn from(_: Wrap<Wrap<Lion>>) -> Self { - todo!() - } - } - - impl From<()> for Wrap<Lion> { - //~^ WARN non-local `impl` definition - fn from(_: ()) -> Self { - todo!() - } - } - - #[derive(Debug)] - struct Elephant; - - impl From<Wrap<Wrap<Elephant>>> for () { - //~^ WARN non-local `impl` definition - fn from(_: Wrap<Wrap<Elephant>>) -> Self { - todo!() - } - } -} - -pub trait StillNonLocal {} - -impl StillNonLocal for &str {} - -fn only_global() { - struct Foo; - impl StillNonLocal for &Foo {} - //~^ WARN non-local `impl` definition -} - -struct GlobalSameFunction; - -fn same_function() { - struct Local1(GlobalSameFunction); - impl From<Local1> for GlobalSameFunction { - //~^ WARN non-local `impl` definition - fn from(x: Local1) -> GlobalSameFunction { - x.0 - } - } - - struct Local2(GlobalSameFunction); - impl From<Local2> for GlobalSameFunction { - //~^ WARN non-local `impl` definition - fn from(x: Local2) -> GlobalSameFunction { - x.0 - } - } -} - -struct GlobalDifferentFunction; - -fn diff_foo() { - struct Local(GlobalDifferentFunction); - - impl From<Local> for GlobalDifferentFunction { - // FIXME(Urgau): Should warn but doesn't since we currently consider - // the other impl to be "global", but that's not the case for the type-system - fn from(x: Local) -> GlobalDifferentFunction { - x.0 - } - } -} - -fn diff_bar() { - struct Local(GlobalDifferentFunction); - - impl From<Local> for GlobalDifferentFunction { - // FIXME(Urgau): Should warn but doesn't since we currently consider - // the other impl to be "global", but that's not the case for the type-system - fn from(x: Local) -> GlobalDifferentFunction { - x.0 - } - } -} - -macro_rules! m { - () => { - trait MacroTrait {} - struct OutsideStruct; - fn my_func() { - impl MacroTrait for OutsideStruct {} - //~^ WARN non-local `impl` definition - } - } -} - -m!(); - -struct CargoUpdate; - -non_local_macro::non_local_impl!(CargoUpdate); -//~^ WARN non-local `impl` definition - -non_local_macro::non_local_macro_rules!(my_macro); -//~^ WARN non-local `macro_rules!` definition - -fn bitflags() { - struct Flags; - - const _: () = { - impl Flags {} - }; -} - -// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 -fn commonly_reported() { - struct Local(u8); - impl From<Local> for u8 { - fn from(x: Local) -> u8 { - x.0 - } - } -} - -// https://github.com/rust-lang/rust/issues/121621#issue-2153187542 -pub trait Serde {} - -impl Serde for &[u8] {} -impl Serde for &str {} - -fn serde() { - struct Thing; - impl Serde for &Thing {} -} diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr deleted file mode 100644 index 8ae04f2c2e8..00000000000 --- a/tests/ui/lint/non_local_definitions.stderr +++ /dev/null @@ -1,705 +0,0 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:36:5 - | -LL | const Z: () = { - | - help: use a const-anon item to suppress this lint: `_` -... -LL | impl Uto for &Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant `Z` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: `#[warn(non_local_definitions)]` on by default - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:46:5 - | -LL | impl Uto for *mut Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:54:9 - | -LL | impl Uto for Test {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:63:5 - | -LL | impl Uto2 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current static `A` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:71:5 - | -LL | impl Uto3 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant `B` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:75:5 - | -LL | macro_rules! m0 { () => { } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:87:5 - | -LL | macro_rules! m { () => { } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:90:5 - | -LL | / impl Test { -LL | | -LL | | fn foo() {} -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:96:9 - | -LL | / impl Test { -LL | | -LL | | fn bar() {} -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:105:9 - | -LL | / impl Test { -LL | | -LL | | fn hoo() {} -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current inline constant `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:114:9 - | -LL | / impl Test { -LL | | -LL | | fn foo2() {} -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current constant `_` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:122:5 - | -LL | / impl Display for Test { -LL | | -LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:129:5 - | -LL | impl dyn Uto5 {} - | ^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:132:5 - | -LL | impl<T: Uto5> Uto5 for Vec<T> { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:135:5 - | -LL | impl Uto5 for &dyn Uto5 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:138:5 - | -LL | impl Uto5 for *mut Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:141:5 - | -LL | impl Uto5 for *mut [Test] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:144:5 - | -LL | impl Uto5 for [Test; 8] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:147:5 - | -LL | impl Uto5 for (Test,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:150:5 - | -LL | impl Uto5 for fn(Test) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:153:5 - | -LL | impl Uto5 for fn() -> Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:157:9 - | -LL | impl Uto5 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:164:9 - | -LL | impl Uto5 for &Test {} - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:171:9 - | -LL | impl Uto5 for &(Test,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:178:9 - | -LL | impl Uto5 for &(Test,Test) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:186:5 - | -LL | impl Uto5 for *mut InsideMain {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:188:5 - | -LL | impl Uto5 for *mut [InsideMain] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:190:5 - | -LL | impl Uto5 for [InsideMain; 8] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:192:5 - | -LL | impl Uto5 for (InsideMain,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:194:5 - | -LL | impl Uto5 for fn(InsideMain) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:196:5 - | -LL | impl Uto5 for fn() -> InsideMain {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:210:9 - | -LL | / impl Display for InsideMain { -LL | | -LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -LL | | todo!() -LL | | } -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:217:9 - | -LL | / impl InsideMain { -LL | | -LL | | fn bar() { -LL | | #[macro_export] -... | -LL | | } -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:221:17 - | -LL | macro_rules! m2 { () => { } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 3 bodies - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:231:5 - | -LL | impl<T: Uto6> Uto3 for Vec<T> { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:240:5 - | -LL | impl Uto7 for Test where Local: std::any::Any {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:243:5 - | -LL | impl<T> Uto8 for T {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:251:9 - | -LL | impl Uto9 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:258:9 - | -LL | impl Uto10 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:272:5 - | -LL | / impl Default for UwU<OwO> { -LL | | -LL | | fn default() -> Self { -LL | | UwU(OwO) -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `fun` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:291:5 - | -LL | / impl AsRef<Cat> for () { -LL | | -LL | | fn as_ref(&self) -> &Cat { &Cat } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `meow` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:302:5 - | -LL | / impl PartialEq<B> for G { -LL | | -LL | | fn eq(&self, _: &B) -> bool { -LL | | true -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `fun2` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:319:5 - | -LL | / impl PartialEq<Dog> for &Dog { -LL | | -LL | | fn eq(&self, _: &Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:326:5 - | -LL | / impl PartialEq<()> for Dog { -LL | | -LL | | fn eq(&self, _: &()) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:333:5 - | -LL | / impl PartialEq<()> for &Dog { -LL | | -LL | | fn eq(&self, _: &()) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:340:5 - | -LL | / impl PartialEq<Dog> for () { -LL | | -LL | | fn eq(&self, _: &Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:362:5 - | -LL | / impl From<Wrap<Wrap<Lion>>> for () { -LL | | -LL | | fn from(_: Wrap<Wrap<Lion>>) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:369:5 - | -LL | / impl From<()> for Wrap<Lion> { -LL | | -LL | | fn from(_: ()) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:379:5 - | -LL | / impl From<Wrap<Wrap<Elephant>>> for () { -LL | | -LL | | fn from(_: Wrap<Wrap<Elephant>>) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:393:5 - | -LL | impl StillNonLocal for &Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `only_global` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:401:5 - | -LL | / impl From<Local1> for GlobalSameFunction { -LL | | -LL | | fn from(x: Local1) -> GlobalSameFunction { -LL | | x.0 -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `same_function` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:409:5 - | -LL | / impl From<Local2> for GlobalSameFunction { -LL | | -LL | | fn from(x: Local2) -> GlobalSameFunction { -LL | | x.0 -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `same_function` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:448:13 - | -LL | impl MacroTrait for OutsideStruct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | m!(); - | ---- in this macro invocation - | - = help: move this `impl` block outside the of the current function `my_func` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:458:1 - | -LL | non_local_macro::non_local_impl!(CargoUpdate); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` - = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:461:1 - | -LL | non_local_macro::non_local_macro_rules!(my_macro); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` - = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: 55 warnings emitted - diff --git a/tests/ui/lint/unused/issue-59896.rs b/tests/ui/lint/unused/issue-59896.rs index ff9f19acf84..a98017524f5 100644 --- a/tests/ui/lint/unused/issue-59896.rs +++ b/tests/ui/lint/unused/issue-59896.rs @@ -1,9 +1,10 @@ +//@ check-pass #![deny(unused_imports)] struct S; fn main() { - use S; //~ ERROR the item `S` is imported redundantly + use S; //FIXME(unused_imports): ~ ERROR the item `S` is imported redundantly let _s = S; } diff --git a/tests/ui/lint/unused/issue-59896.stderr b/tests/ui/lint/unused/issue-59896.stderr deleted file mode 100644 index 3e8298c6b72..00000000000 --- a/tests/ui/lint/unused/issue-59896.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: the item `S` is imported redundantly - --> $DIR/issue-59896.rs:6:9 - | -LL | struct S; - | --------- the item `S` is already defined here -... -LL | use S; - | ^ - | -note: the lint level is defined here - --> $DIR/issue-59896.rs:1:9 - | -LL | #![deny(unused_imports)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs new file mode 100644 index 00000000000..59bb65a357b --- /dev/null +++ b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.rs @@ -0,0 +1,39 @@ +//@ run-pass + +#![warn(unused_parens)] +#![allow(dead_code)] + +trait Foo { + fn bar(); + fn tar(); +} + +macro_rules! unused_parens { + ($ty:ident) => { + impl<$ty: Foo> Foo for ($ty,) { + fn bar() { <$ty>::bar() } + fn tar() {} + } + }; + + ($ty:ident $(, $rest:ident)*) => { + impl<$ty: Foo, $($rest: Foo),*> Foo for ($ty, $($rest),*) { + fn bar() { + <$ty>::bar(); + <($($rest),*)>::bar() //~WARN unnecessary parentheses around type + } + fn tar() { + let (_t) = 1; //~WARN unnecessary parentheses around pattern + //~| WARN unnecessary parentheses around pattern + let (_t1,) = (1,); + let (_t2, _t3) = (1, 2); + } + } + + unused_parens!($($rest),*); + } +} + +unused_parens!(T1, T2, T3); + +fn main() {} diff --git a/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr new file mode 100644 index 00000000000..b1390debec7 --- /dev/null +++ b/tests/ui/lint/unused/unused_parens/unused-parens-in-macro-issue-120642.stderr @@ -0,0 +1,40 @@ +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-in-macro-issue-120642.rs:26:19 + | +LL | let (_t) = 1; + | ^^^^ +... +LL | unused_parens!(T1, T2, T3); + | -------------------------- in this macro invocation + | +note: the lint level is defined here + --> $DIR/unused-parens-in-macro-issue-120642.rs:3:9 + | +LL | #![warn(unused_parens)] + | ^^^^^^^^^^^^^ + = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-in-macro-issue-120642.rs:23:18 + | +LL | <($($rest),*)>::bar() + | ^^^^^^^^^^^^ +... +LL | unused_parens!(T1, T2, T3); + | -------------------------- in this macro invocation + | + = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-in-macro-issue-120642.rs:26:19 + | +LL | let (_t) = 1; + | ^^^^ +... +LL | unused_parens!(T1, T2, T3); + | -------------------------- in this macro invocation + | + = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 3 warnings emitted + diff --git a/tests/ui/lint/unused_braces_macro.rs b/tests/ui/lint/unused_braces_macro.rs index d0b42a12ff5..f9da4ed4e49 100644 --- a/tests/ui/lint/unused_braces_macro.rs +++ b/tests/ui/lint/unused_braces_macro.rs @@ -2,5 +2,5 @@ pub fn foo<const BAR: bool> () {} fn main() { - foo::<{cfg!(feature = "foo")}>(); + foo::<{cfg!(FALSE)}>(); } diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs index 28d1fea98b5..797e57f48e9 100644 --- a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs +++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs @@ -9,7 +9,7 @@ pub mod bar { use bar::*; pub fn warning() -> Foo { - use bar::Foo; //~ WARNING imported redundantly + use bar::Foo; //FIXME(unused_imports): ~ WARNING imported redundantly Foo(Bar('a')) } diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr deleted file mode 100644 index 2c3b3345270..00000000000 --- a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the item `Foo` is imported redundantly - --> $DIR/use-redundant-glob-parent.rs:12:9 - | -LL | use bar::*; - | ------ the item `Foo` is already imported here -... -LL | use bar::Foo; - | ^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/use-redundant-glob-parent.rs:2:9 - | -LL | #![warn(unused_imports)] - | ^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.rs b/tests/ui/lint/use-redundant/use-redundant-glob.rs index 3d3fe2579b5..e5835be89d8 100644 --- a/tests/ui/lint/use-redundant/use-redundant-glob.rs +++ b/tests/ui/lint/use-redundant/use-redundant-glob.rs @@ -8,7 +8,7 @@ pub mod bar { pub fn warning() -> bar::Foo { use bar::*; - use bar::Foo; //~ WARNING imported redundantly + use bar::Foo; //FIXME(unused_imports): ~ WARNING imported redundantly Foo(Bar('a')) } diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.stderr b/tests/ui/lint/use-redundant/use-redundant-glob.stderr deleted file mode 100644 index d3b406d82b6..00000000000 --- a/tests/ui/lint/use-redundant/use-redundant-glob.stderr +++ /dev/null @@ -1,16 +0,0 @@ -warning: the item `Foo` is imported redundantly - --> $DIR/use-redundant-glob.rs:11:9 - | -LL | use bar::*; - | ------ the item `Foo` is already imported here -LL | use bar::Foo; - | ^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/use-redundant-glob.rs:2:9 - | -LL | #![warn(unused_imports)] - | ^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs index d0fb3454d3f..2db3435d46d 100644 --- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs @@ -23,7 +23,8 @@ mod foo { fn main() { { - use std::string::String; //~ WARNING the item `String` is imported redundantly + use std::string::String; + //FIXME(unused_imports): ~^ WARNING the item `String` is imported redundantly // 'String' from 'std::string::String'. let s = String::new(); println!("{}", s); diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr deleted file mode 100644 index b8832a31783..00000000000 --- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the item `String` is imported redundantly - --> $DIR/use-redundant-issue-71450.rs:26:13 - | -LL | use std::string::String; - | ^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `String` is already defined here - | -note: the lint level is defined here - --> $DIR/use-redundant-issue-71450.rs:3:9 - | -LL | #![warn(unused_imports)] - | ^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs index ae5118b2729..62f50c8a0df 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs @@ -2,11 +2,15 @@ #![warn(unused_imports)] -use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly -use std::option::Option::None; //~ WARNING the item `None` is imported redundantly +use std::option::Option::Some; +//FIXME(unused_imports): ~^ WARNING the item `Some` is imported redundantly +use std::option::Option::None; +//FIXME(unused_imports): ~ WARNING the item `None` is imported redundantly -use std::result::Result::Ok;//~ WARNING the item `Ok` is imported redundantly -use std::result::Result::Err;//~ WARNING the item `Err` is imported redundantly +use std::result::Result::Ok; +//FIXME(unused_imports): ~^ WARNING the item `Ok` is imported redundantly +use std::result::Result::Err; +//FIXME(unused_imports): ~^ WARNING the item `Err` is imported redundantly use std::convert::{TryFrom, TryInto}; fn main() { diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr deleted file mode 100644 index 1b09df911eb..00000000000 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr +++ /dev/null @@ -1,44 +0,0 @@ -warning: the item `Some` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:5:5 - | -LL | use std::option::Option::Some; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `Some` is already defined here - | -note: the lint level is defined here - --> $DIR/use-redundant-prelude-rust-2015.rs:2:9 - | -LL | #![warn(unused_imports)] - | ^^^^^^^^^^^^^^ - -warning: the item `None` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:6:5 - | -LL | use std::option::Option::None; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `None` is already defined here - -warning: the item `Ok` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:8:5 - | -LL | use std::result::Result::Ok; - | ^^^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `Ok` is already defined here - -warning: the item `Err` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:9:5 - | -LL | use std::result::Result::Err; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `Err` is already defined here - -warning: 4 warnings emitted - diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs index cb4dcb6c0bd..1baa1ac1b8c 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs @@ -2,8 +2,10 @@ //@ edition:2021 #![warn(unused_imports)] -use std::convert::TryFrom;//~ WARNING the item `TryFrom` is imported redundantly -use std::convert::TryInto;//~ WARNING the item `TryInto` is imported redundantly +use std::convert::TryFrom; +//FIXME(unused_imports): ~^ WARNING the item `TryFrom` is imported redundantly +use std::convert::TryInto; +//FIXME(unused_imports): ~^ WARNING the item `TryInto` is imported redundantly fn main() { let _e: Result<i32, _> = 8u8.try_into(); diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr deleted file mode 100644 index 542356dc996..00000000000 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr +++ /dev/null @@ -1,26 +0,0 @@ -warning: the item `TryFrom` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2021.rs:5:5 - | -LL | use std::convert::TryFrom; - | ^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `TryFrom` is already defined here - | -note: the lint level is defined here - --> $DIR/use-redundant-prelude-rust-2021.rs:3:9 - | -LL | #![warn(unused_imports)] - | ^^^^^^^^^^^^^^ - -warning: the item `TryInto` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2021.rs:6:5 - | -LL | use std::convert::TryInto; - | ^^^^^^^^^^^^^^^^^^^^^ - --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL - | - = note: the item `TryInto` is already defined here - -warning: 2 warnings emitted - diff --git a/tests/ui/lint/use-redundant/use-redundant.rs b/tests/ui/lint/use-redundant/use-redundant.rs index 88d3ee75a3f..9e4902af34b 100644 --- a/tests/ui/lint/use-redundant/use-redundant.rs +++ b/tests/ui/lint/use-redundant/use-redundant.rs @@ -18,7 +18,7 @@ use m1::*; //~ WARNING unused import use m2::*; //~ WARNING unused import fn main() { - use crate::foo::Bar; //~ WARNING imported redundantly + use crate::foo::Bar; //FIXME(unused_imports): ~ WARNING imported redundantly let _a: Bar = 3; baz(); diff --git a/tests/ui/lint/use-redundant/use-redundant.stderr b/tests/ui/lint/use-redundant/use-redundant.stderr index c861a1956e1..224e8411237 100644 --- a/tests/ui/lint/use-redundant/use-redundant.stderr +++ b/tests/ui/lint/use-redundant/use-redundant.stderr @@ -16,14 +16,5 @@ warning: unused import: `m2::*` LL | use m2::*; | ^^^^^ -warning: the item `Bar` is imported redundantly - --> $DIR/use-redundant.rs:21:9 - | -LL | use crate::foo::Bar; - | --------------- the item `Bar` is already imported here -... -LL | use crate::foo::Bar; - | ^^^^^^^^^^^^^^^ - -warning: 3 warnings emitted +warning: 2 warnings emitted diff --git a/tests/ui/loops/loop-break-value.rs b/tests/ui/loops/loop-break-value.rs index c35200520cb..d509fc16570 100644 --- a/tests/ui/loops/loop-break-value.rs +++ b/tests/ui/loops/loop-break-value.rs @@ -23,6 +23,10 @@ fn main() { }; }; + let _: Option<String> = loop { + break; //~ ERROR mismatched types + }; + 'while_loop: while true { //~ WARN denote infinite loops with break; break (); //~ ERROR `break` with value from a `while` loop diff --git a/tests/ui/loops/loop-break-value.stderr b/tests/ui/loops/loop-break-value.stderr index a691960f962..0093182422e 100644 --- a/tests/ui/loops/loop-break-value.stderr +++ b/tests/ui/loops/loop-break-value.stderr @@ -1,5 +1,5 @@ warning: label name `'a` shadows a label name that is already in scope - --> $DIR/loop-break-value.rs:136:17 + --> $DIR/loop-break-value.rs:140:17 | LL | 'a: loop { | -- first declared here @@ -8,7 +8,7 @@ LL | let _ = 'a: loop { | ^^ label `'a` already in scope warning: label name `'a` shadows a label name that is already in scope - --> $DIR/loop-break-value.rs:148:17 + --> $DIR/loop-break-value.rs:152:17 | LL | 'a: loop { | -- first declared here @@ -17,7 +17,7 @@ LL | let _ = 'a: loop { | ^^ label `'a` already in scope error[E0425]: cannot find value `LOOP` in this scope - --> $DIR/loop-break-value.rs:95:15 + --> $DIR/loop-break-value.rs:99:15 | LL | 'LOOP: for _ in 0 .. 9 { | ----- a label with a similar name exists @@ -28,7 +28,7 @@ LL | break LOOP; | help: use the similarly named label: `'LOOP` warning: denote infinite loops with `loop { ... }` - --> $DIR/loop-break-value.rs:26:5 + --> $DIR/loop-break-value.rs:30:5 | LL | 'while_loop: while true { | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` @@ -36,7 +36,7 @@ LL | 'while_loop: while true { = note: `#[warn(while_true)]` on by default error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:28:9 + --> $DIR/loop-break-value.rs:32:9 | LL | 'while_loop: while true { | ----------------------- you can't `break` with a value in a `while` loop @@ -54,7 +54,7 @@ LL | break 'while_loop; | ~~~~~~~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:30:13 + --> $DIR/loop-break-value.rs:34:13 | LL | 'while_loop: while true { | ----------------------- you can't `break` with a value in a `while` loop @@ -68,7 +68,7 @@ LL | break 'while_loop; | ~~~~~~~~~~~~~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:38:12 + --> $DIR/loop-break-value.rs:42:12 | LL | while let Some(_) = Some(()) { | ---------------------------- you can't `break` with a value in a `while` loop @@ -81,7 +81,7 @@ LL | if break { | ~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:43:9 + --> $DIR/loop-break-value.rs:47:9 | LL | while let Some(_) = Some(()) { | ---------------------------- you can't `break` with a value in a `while` loop @@ -94,7 +94,7 @@ LL | break; | ~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:49:13 + --> $DIR/loop-break-value.rs:53:13 | LL | 'while_let_loop: while let Some(_) = Some(()) { | --------------------------------------------- you can't `break` with a value in a `while` loop @@ -108,7 +108,7 @@ LL | break 'while_let_loop; | ~~~~~~~~~~~~~~~~~~~~~ error[E0571]: `break` with value from a `for` loop - --> $DIR/loop-break-value.rs:56:9 + --> $DIR/loop-break-value.rs:60:9 | LL | for _ in &[1,2,3] { | ----------------- you can't `break` with a value in a `for` loop @@ -121,7 +121,7 @@ LL | break; | ~~~~~ error[E0571]: `break` with value from a `for` loop - --> $DIR/loop-break-value.rs:57:9 + --> $DIR/loop-break-value.rs:61:9 | LL | for _ in &[1,2,3] { | ----------------- you can't `break` with a value in a `for` loop @@ -135,7 +135,7 @@ LL | break; | ~~~~~ error[E0571]: `break` with value from a `for` loop - --> $DIR/loop-break-value.rs:64:13 + --> $DIR/loop-break-value.rs:68:13 | LL | 'for_loop: for _ in &[1,2,3] { | ---------------------------- you can't `break` with a value in a `for` loop @@ -191,7 +191,24 @@ LL | break 'outer_loop "nope"; | ^^^^^^ expected `i32`, found `&str` error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:73:26 + --> $DIR/loop-break-value.rs:27:9 + | +LL | let _: Option<String> = loop { + | - ---- this loop is expected to be of type `Option<String>` + | | + | expected because of this assignment +LL | break; + | ^^^^^ expected `Option<String>`, found `()` + | + = note: expected enum `Option<String>` + found unit type `()` +help: give the `break` a value of the expected type + | +LL | break None; + | ++++ + +error[E0308]: mismatched types + --> $DIR/loop-break-value.rs:77:26 | LL | break; | ----- expected because of this `break` @@ -199,7 +216,7 @@ LL | break 'c 123; | ^^^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:80:15 + --> $DIR/loop-break-value.rs:84:15 | LL | break (break, break); | ^-----^^-----^ @@ -212,7 +229,7 @@ LL | break (break, break); found tuple `(!, !)` error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:85:15 + --> $DIR/loop-break-value.rs:89:15 | LL | break; | ----- expected because of this `break` @@ -220,20 +237,20 @@ LL | break 2; | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:90:9 + --> $DIR/loop-break-value.rs:94:9 | LL | break 2; | ------- expected because of this `break` LL | break; | ^^^^^ expected integer, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | break value; | +++++ error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:108:9 + --> $DIR/loop-break-value.rs:112:9 | LL | break 'a 1; | ---------- expected because of this `break` @@ -241,13 +258,13 @@ LL | break 'a 1; LL | break; | ^^^^^ expected integer, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | break value; | +++++ error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:120:9 + --> $DIR/loop-break-value.rs:124:9 | LL | break 'a 1; | ---------- expected because of this `break` @@ -255,13 +272,13 @@ LL | break 'a 1; LL | break 'a; | ^^^^^^^^ expected integer, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | break 'a value; | +++++ error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:131:15 + --> $DIR/loop-break-value.rs:135:15 | LL | break; | ----- expected because of this `break` @@ -270,7 +287,7 @@ LL | break 2; | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:140:17 + --> $DIR/loop-break-value.rs:144:17 | LL | break 2; | ------- expected because of this `break` @@ -278,13 +295,13 @@ LL | loop { LL | break 'a; | ^^^^^^^^ expected integer, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | break 'a value; | +++++ error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:143:15 + --> $DIR/loop-break-value.rs:147:15 | LL | break; | ----- expected because of this `break` @@ -293,7 +310,7 @@ LL | break 2; | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:152:17 + --> $DIR/loop-break-value.rs:156:17 | LL | break 'a 2; | ---------- expected because of this `break` @@ -301,13 +318,13 @@ LL | loop { LL | break 'a; | ^^^^^^^^ expected integer, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | break 'a value; | +++++ error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:155:15 + --> $DIR/loop-break-value.rs:159:15 | LL | break; | ----- expected because of this `break` @@ -316,7 +333,7 @@ LL | break 2; | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:159:15 + --> $DIR/loop-break-value.rs:163:15 | LL | fn main() { | - expected `()` because of this return type @@ -326,7 +343,7 @@ LL | loop { // point at the return type LL | break 2; | ^ expected `()`, found integer -error: aborting due to 25 previous errors; 3 warnings emitted +error: aborting due to 26 previous errors; 3 warnings emitted Some errors have detailed explanations: E0308, E0425, E0571. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/loops/loop-labeled-break-value.stderr b/tests/ui/loops/loop-labeled-break-value.stderr index 694d6c306f6..3be62316e34 100644 --- a/tests/ui/loops/loop-labeled-break-value.stderr +++ b/tests/ui/loops/loop-labeled-break-value.stderr @@ -7,7 +7,7 @@ LL | let _: i32 = loop { break }; | | this loop is expected to be of type `i32` | expected because of this assignment | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | let _: i32 = loop { break 42 }; | ++ @@ -21,7 +21,7 @@ LL | let _: i32 = 'inner: loop { break 'inner }; | | this loop is expected to be of type `i32` | expected because of this assignment | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | let _: i32 = 'inner: loop { break 'inner 42 }; | ++ @@ -35,7 +35,7 @@ LL | let _: i32 = 'inner2: loop { loop { break 'inner2 } }; | | this loop is expected to be of type `i32` | expected because of this assignment | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | let _: i32 = 'inner2: loop { loop { break 'inner2 42 } }; | ++ diff --git a/tests/ui/loops/loop-proper-liveness.stderr b/tests/ui/loops/loop-proper-liveness.stderr index bcd6eb353e5..cd4c064bcd1 100644 --- a/tests/ui/loops/loop-proper-liveness.stderr +++ b/tests/ui/loops/loop-proper-liveness.stderr @@ -10,8 +10,8 @@ LL | println!("{:?}", x); = 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) help: consider assigning a value | -LL | let x: i32 = 0; - | +++ +LL | let x: i32 = 42; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/loops/loop-properly-diverging-2.stderr b/tests/ui/loops/loop-properly-diverging-2.stderr index c9f27a6a672..ba615f9ae4f 100644 --- a/tests/ui/loops/loop-properly-diverging-2.stderr +++ b/tests/ui/loops/loop-properly-diverging-2.stderr @@ -7,7 +7,7 @@ LL | let x: i32 = loop { break }; | | this loop is expected to be of type `i32` | expected because of this assignment | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | let x: i32 = loop { break 42 }; | ++ diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs index 57ba0d3bf56..83290790766 100644 --- a/tests/ui/macros/macro-attributes.rs +++ b/tests/ui/macros/macro-attributes.rs @@ -9,7 +9,7 @@ macro_rules! compiles_fine { // check that the attributes are recognised by requiring this // to be removed to avoid a compile error - #[cfg(always_remove)] + #[cfg(FALSE)] static MISTYPED: () = "foo"; } } diff --git a/tests/ui/macros/macro-error.rs b/tests/ui/macros/macro-error.rs index 59ed79e91f0..4984b92911e 100644 --- a/tests/ui/macros/macro-error.rs +++ b/tests/ui/macros/macro-error.rs @@ -5,5 +5,5 @@ macro_rules! foo { fn main() { foo!(0); // Check that we report errors at macro definition, not expansion. - let _: cfg!(foo) = (); //~ ERROR non-type macro in type position + let _: cfg!(FALSE) = (); //~ ERROR non-type macro in type position } diff --git a/tests/ui/macros/macro-error.stderr b/tests/ui/macros/macro-error.stderr index 2539a6d5156..fcf8d922d65 100644 --- a/tests/ui/macros/macro-error.stderr +++ b/tests/ui/macros/macro-error.stderr @@ -7,8 +7,8 @@ LL | ($a:expr) => a; error: non-type macro in type position: cfg --> $DIR/macro-error.rs:8:12 | -LL | let _: cfg!(foo) = (); - | ^^^^^^^^^ +LL | let _: cfg!(FALSE) = (); + | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs index a8cda23075b..6dbfce21359 100644 --- a/tests/ui/macros/macro-inner-attributes.rs +++ b/tests/ui/macros/macro-inner-attributes.rs @@ -5,11 +5,11 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #![$a] $i }); } test!(a, - #[cfg(qux)], + #[cfg(FALSE)], pub fn bar() { }); test!(b, - #[cfg(not(qux))], + #[cfg(not(FALSE))], pub fn bar() { }); #[rustc_dummy] diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs index 0752f7e3153..8c79683f49a 100644 --- a/tests/ui/macros/macro-outer-attributes.rs +++ b/tests/ui/macros/macro-outer-attributes.rs @@ -5,11 +5,11 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #[$a] $i }); } test!(a, - #[cfg(qux)], + #[cfg(FALSE)], pub fn bar() { }); test!(b, - #[cfg(not(qux))], + #[cfg(not(FALSE))], pub fn bar() { }); // test1!(#[bar]) diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs index 3ff26025206..37188e45ad3 100644 --- a/tests/ui/macros/macro-with-attrs2.rs +++ b/tests/ui/macros/macro-with-attrs2.rs @@ -1,9 +1,9 @@ //@ run-pass -#[cfg(foo)] +#[cfg(FALSE)] macro_rules! foo { () => (1) } -#[cfg(not(foo))] +#[cfg(not(FALSE))] macro_rules! foo { () => (2) } pub fn main() { diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs index 1643b6bfa18..a144e855ae3 100644 --- a/tests/ui/methods/call_method_unknown_pointee.rs +++ b/tests/ui/methods/call_method_unknown_pointee.rs @@ -8,10 +8,10 @@ fn main() { let ptr = &val as *const u32; unsafe { let _a: i32 = (ptr as *const _).read(); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + //~^ ERROR type annotations needed let b = ptr as *const _; + //~^ ERROR type annotations needed let _b: u8 = b.read(); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] let _c = (ptr as *const u8).read(); // we know the type here } @@ -19,10 +19,10 @@ fn main() { let ptr = &mut val as *mut u32; unsafe { let _a: i32 = (ptr as *mut _).read(); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + //~^ ERROR type annotations needed let b = ptr as *mut _; + //~^ ERROR type annotations needed b.write(10); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] (ptr as *mut i32).write(1000); // we know the type here } } diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr index 84ecf046e7a..9d0f38cf6b5 100644 --- a/tests/ui/methods/call_method_unknown_pointee.stderr +++ b/tests/ui/methods/call_method_unknown_pointee.stderr @@ -1,27 +1,49 @@ -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type +error[E0282]: type annotations needed --> $DIR/call_method_unknown_pointee.rs:10:41 | LL | let _a: i32 = (ptr as *const _).read(); | ^^^^ + | | + | cannot infer type + | cannot call a method on a raw pointer with an unknown pointee type -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type - --> $DIR/call_method_unknown_pointee.rs:13:24 +error[E0282]: type annotations needed for `*const _` + --> $DIR/call_method_unknown_pointee.rs:12:13 | +LL | let b = ptr as *const _; + | ^ +LL | LL | let _b: u8 = b.read(); - | ^^^^ + | ---- cannot call a method on a raw pointer with an unknown pointee type + | +help: consider giving `b` an explicit type, where the placeholders `_` are specified + | +LL | let b: *const _ = ptr as *const _; + | ++++++++++ -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type +error[E0282]: type annotations needed --> $DIR/call_method_unknown_pointee.rs:21:39 | LL | let _a: i32 = (ptr as *mut _).read(); | ^^^^ + | | + | cannot infer type + | cannot call a method on a raw pointer with an unknown pointee type -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type - --> $DIR/call_method_unknown_pointee.rs:24:11 +error[E0282]: type annotations needed for `*mut _` + --> $DIR/call_method_unknown_pointee.rs:23:13 | +LL | let b = ptr as *mut _; + | ^ +LL | LL | b.write(10); - | ^^^^^ + | ----- cannot call a method on a raw pointer with an unknown pointee type + | +help: consider giving `b` an explicit type, where the placeholders `_` are specified + | +LL | let b: *mut _ = ptr as *mut _; + | ++++++++ error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0699`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 0a022dc3984..b2d2d039ff6 100644 --- a/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Vec<T>` +error[E0282]: type annotations needed for `Vec<_>` --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9 | LL | let mut x = Vec::new(); diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.rs b/tests/ui/methods/suggest-convert-ptr-to-ref.rs new file mode 100644 index 00000000000..ccce3c65470 --- /dev/null +++ b/tests/ui/methods/suggest-convert-ptr-to-ref.rs @@ -0,0 +1,17 @@ +fn main() { + let mut x = 8u8; + let z: *const u8 = &x; + // issue #21596 + println!("{}", z.to_string()); //~ ERROR E0599 + + let t: *mut u8 = &mut x; + println!("{}", t.to_string()); //~ ERROR E0599 + t.make_ascii_lowercase(); //~ ERROR E0599 + + // suggest `as_mut` simply because the name is similar + let _ = t.as_mut_ref(); //~ ERROR E0599 + let _ = t.as_ref_mut(); //~ ERROR E0599 + + // no ptr-to-ref suggestion + z.make_ascii_lowercase(); //~ ERROR E0599 +} diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr new file mode 100644 index 00000000000..69b20d57be8 --- /dev/null +++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr @@ -0,0 +1,70 @@ +error[E0599]: `*const u8` doesn't implement `std::fmt::Display` + --> $DIR/suggest-convert-ptr-to-ref.rs:5:22 + | +LL | println!("{}", z.to_string()); + | ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter + | +note: the method `to_string` exists on the type `&u8` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + = note: you might want to use the unsafe method `<*const T>::as_ref` to get an optional reference to the value behind the pointer + = note: read the documentation for `<*const T>::as_ref` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref + = note: the following trait bounds were not satisfied: + `*const u8: std::fmt::Display` + which is required by `*const u8: ToString` + +error[E0599]: `*mut u8` doesn't implement `std::fmt::Display` + --> $DIR/suggest-convert-ptr-to-ref.rs:8:22 + | +LL | println!("{}", t.to_string()); + | ^^^^^^^^^ `*mut u8` cannot be formatted with the default formatter + | +note: the method `to_string` exists on the type `&&mut u8` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + = note: you might want to use the unsafe method `<*mut T>::as_ref` to get an optional reference to the value behind the pointer + = note: read the documentation for `<*mut T>::as_ref` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref-1 + = note: the following trait bounds were not satisfied: + `*mut u8: std::fmt::Display` + which is required by `*mut u8: ToString` + +error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope + --> $DIR/suggest-convert-ptr-to-ref.rs:9:7 + | +LL | t.make_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^ method not found in `*mut u8` + | +note: the method `make_ascii_lowercase` exists on the type `&mut u8` + --> $SRC_DIR/core/src/num/mod.rs:LL:COL + = note: you might want to use the unsafe method `<*mut T>::as_mut` to get an optional reference to the value behind the pointer + = note: read the documentation for `<*mut T>::as_mut` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_mut + +error[E0599]: no method named `as_mut_ref` found for raw pointer `*mut u8` in the current scope + --> $DIR/suggest-convert-ptr-to-ref.rs:12:15 + | +LL | let _ = t.as_mut_ref(); + | ^^^^^^^^^^ + | +help: there is a method `as_mut` with a similar name + | +LL | let _ = t.as_mut(); + | ~~~~~~ + +error[E0599]: no method named `as_ref_mut` found for raw pointer `*mut u8` in the current scope + --> $DIR/suggest-convert-ptr-to-ref.rs:13:15 + | +LL | let _ = t.as_ref_mut(); + | ^^^^^^^^^^ + | +help: there is a method `as_mut` with a similar name + | +LL | let _ = t.as_mut(); + | ~~~~~~ + +error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*const u8` in the current scope + --> $DIR/suggest-convert-ptr-to-ref.rs:16:7 + | +LL | z.make_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^ method not found in `*const u8` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/mir/issue-102389.stderr b/tests/ui/mir/issue-102389.stderr index 1f04d119b56..838eaffb5a0 100644 --- a/tests/ui/mir/issue-102389.stderr +++ b/tests/ui/mir/issue-102389.stderr @@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*inbounds` which is behind a shared reference | LL | array[*inbounds as usize] | ^^^^^^^^^ move occurs because `*inbounds` has type `Enum`, which does not implement the `Copy` trait + | +note: if `Enum` implemented `Clone`, you could clone the value + --> $DIR/issue-102389.rs:1:1 + | +LL | enum Enum { A, B, C } + | ^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index f8047c8e2d4..099c580a056 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -6,15 +6,15 @@ LL | 1 + Some(1); | = help: the trait `Add<Option<{integer}>>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: + <&'a f128 as Add<f128>> + <&'a f16 as Add<f16>> <&'a f32 as Add<f32>> <&'a f64 as Add<f64>> <&'a i128 as Add<i128>> <&'a i16 as Add<i16>> <&'a i32 as Add<i32>> <&'a i64 as Add<i64>> - <&'a i8 as Add<i8>> - <&'a isize as Add<isize>> - and 48 others + and 56 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` --> $DIR/binops.rs:3:16 @@ -37,15 +37,15 @@ LL | 3 * (); | = help: the trait `Mul<()>` is not implemented for `{integer}` = help: the following other types implement trait `Mul<Rhs>`: + <&'a f128 as Mul<f128>> + <&'a f16 as Mul<f16>> <&'a f32 as Mul<f32>> <&'a f64 as Mul<f64>> <&'a i128 as Mul<i128>> <&'a i16 as Mul<i16>> <&'a i32 as Mul<i32>> <&'a i64 as Mul<i64>> - <&'a i8 as Mul<i8>> - <&'a isize as Mul<isize>> - and 49 others + and 57 others error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:5:7 @@ -55,15 +55,15 @@ LL | 4 / ""; | = help: the trait `Div<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Div<Rhs>`: + <&'a f128 as Div<f128>> + <&'a f16 as Div<f16>> <&'a f32 as Div<f32>> <&'a f64 as Div<f64>> <&'a i128 as Div<i128>> <&'a i16 as Div<i16>> <&'a i32 as Div<i32>> <&'a i64 as Div<i64>> - <&'a i8 as Div<i8>> - <&'a isize as Div<isize>> - and 54 others + and 62 others error[E0277]: can't compare `{integer}` with `String` --> $DIR/binops.rs:6:7 diff --git a/tests/ui/issues/auxiliary/issue-13872-1.rs b/tests/ui/modules/auxiliary/issue-13872-1.rs index fa9258834c7..fa9258834c7 100644 --- a/tests/ui/issues/auxiliary/issue-13872-1.rs +++ b/tests/ui/modules/auxiliary/issue-13872-1.rs diff --git a/tests/ui/issues/auxiliary/issue-13872-2.rs b/tests/ui/modules/auxiliary/issue-13872-2.rs index 8c64f16e3f9..8c64f16e3f9 100644 --- a/tests/ui/issues/auxiliary/issue-13872-2.rs +++ b/tests/ui/modules/auxiliary/issue-13872-2.rs diff --git a/tests/ui/issues/auxiliary/issue-13872-3.rs b/tests/ui/modules/auxiliary/issue-13872-3.rs index d31d52eb847..d31d52eb847 100644 --- a/tests/ui/issues/auxiliary/issue-13872-3.rs +++ b/tests/ui/modules/auxiliary/issue-13872-3.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs b/tests/ui/modules/auxiliary/issue-1920.rs index 1548cb99563..1548cb99563 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs +++ b/tests/ui/modules/auxiliary/issue-1920.rs diff --git a/tests/ui/issues/issue-13872.rs b/tests/ui/modules/issue-13872.rs index 5589d2d4f68..5589d2d4f68 100644 --- a/tests/ui/issues/issue-13872.rs +++ b/tests/ui/modules/issue-13872.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs b/tests/ui/modules/issue-1920-1.rs index 763d07db2cd..763d07db2cd 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs +++ b/tests/ui/modules/issue-1920-1.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr b/tests/ui/modules/issue-1920-1.stderr index b7c7da00672..b7c7da00672 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr +++ b/tests/ui/modules/issue-1920-1.stderr diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs b/tests/ui/modules/issue-1920-2.rs index b5a90b2c8e8..b5a90b2c8e8 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs +++ b/tests/ui/modules/issue-1920-2.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr b/tests/ui/modules/issue-1920-2.stderr index 844cb0ff199..844cb0ff199 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr +++ b/tests/ui/modules/issue-1920-2.stderr diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs b/tests/ui/modules/issue-1920-3.rs index 372c8b1511c..372c8b1511c 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs +++ b/tests/ui/modules/issue-1920-3.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr b/tests/ui/modules/issue-1920-3.stderr index 525ca4685bb..525ca4685bb 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr +++ b/tests/ui/modules/issue-1920-3.stderr diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.rs b/tests/ui/moves/issue-72649-uninit-in-loop.rs index 56c225bab8c..86f389cb3af 100644 --- a/tests/ui/moves/issue-72649-uninit-in-loop.rs +++ b/tests/ui/moves/issue-72649-uninit-in-loop.rs @@ -3,6 +3,10 @@ // 'value moved in previous iteration of loop' message struct NonCopy; +//~^ NOTE if `NonCopy` implemented `Clone` +//~| NOTE if `NonCopy` implemented `Clone` +//~| NOTE if `NonCopy` implemented `Clone` +//~| NOTE if `NonCopy` implemented `Clone` fn good() { loop { diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr index 7e119fe8cda..35216f8a66f 100644 --- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr +++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:20:22 + --> $DIR/issue-72649-uninit-in-loop.rs:24:22 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -9,9 +9,15 @@ LL | let _used = value; LL | LL | let _used2 = value; | ^^^^^ value used here after move + | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/issue-72649-uninit-in-loop.rs:5:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:32:26 + --> $DIR/issue-72649-uninit-in-loop.rs:36:26 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -23,9 +29,15 @@ LL | let _used = value; ... LL | let _used2 = value; | ^^^^^ value used here after move + | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/issue-72649-uninit-in-loop.rs:5:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:42:21 + --> $DIR/issue-72649-uninit-in-loop.rs:46:21 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -34,9 +46,15 @@ LL | loop { | ---- inside of this loop LL | let _used = value; | ^^^^^ value moved here, in previous iteration of loop + | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/issue-72649-uninit-in-loop.rs:5:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:53:22 + --> $DIR/issue-72649-uninit-in-loop.rs:57:22 | LL | let mut value = NonCopy{}; | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -45,9 +63,15 @@ LL | loop { | ---- inside of this loop LL | let _used2 = value; | ^^^^^ value moved here, in previous iteration of loop + | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/issue-72649-uninit-in-loop.rs:5:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ error[E0381]: used binding `value` isn't initialized - --> $DIR/issue-72649-uninit-in-loop.rs:61:21 + --> $DIR/issue-72649-uninit-in-loop.rs:65:21 | LL | let value: NonCopy; | ----- binding declared here but left uninitialized @@ -56,11 +80,11 @@ LL | let _used = value; | help: consider assigning a value | -LL | let value: NonCopy = todo!(); - | +++++++++ +LL | let value: NonCopy = value; + | +++++++ error[E0381]: used binding `value` isn't initialized - --> $DIR/issue-72649-uninit-in-loop.rs:69:21 + --> $DIR/issue-72649-uninit-in-loop.rs:73:21 | LL | let mut value: NonCopy; | --------- binding declared here but left uninitialized @@ -70,8 +94,8 @@ LL | let _used = value; | help: consider assigning a value | -LL | let mut value: NonCopy = todo!(); - | +++++++++ +LL | let mut value: NonCopy = value; + | +++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/moves/issue-75904-move-closure-loop.stderr b/tests/ui/moves/issue-75904-move-closure-loop.stderr index 6f04105a35e..b6ad906bbdb 100644 --- a/tests/ui/moves/issue-75904-move-closure-loop.stderr +++ b/tests/ui/moves/issue-75904-move-closure-loop.stderr @@ -4,11 +4,18 @@ error[E0382]: use of moved value: `a` LL | let mut a = NotCopy; | ----- move occurs because `a` has type `NotCopy`, which does not implement the `Copy` trait LL | loop { + | ---- inside of this loop LL | || { | ^^ value moved into closure here, in previous iteration of loop LL | &mut a; LL | a; | - use occurs due to use in closure + | +note: if `NotCopy` implemented `Clone`, you could clone the value + --> $DIR/issue-75904-move-closure-loop.rs:5:1 + | +LL | struct NotCopy; + | ^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr index 17f48f5f7bf..e6bf52276ac 100644 --- a/tests/ui/moves/move-fn-self-receiver.stderr +++ b/tests/ui/moves/move-fn-self-receiver.stderr @@ -101,6 +101,12 @@ LL | mut_foo; | ^^^^^^^ move out of `mut_foo` occurs here LL | ret; | --- borrow later used here + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/move-fn-self-receiver.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ error[E0382]: use of moved value: `rc_foo` --> $DIR/move-fn-self-receiver.rs:55:5 @@ -132,6 +138,11 @@ LL | foo_add + Foo; LL | foo_add; | ^^^^^^^ value used here after move | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/move-fn-self-receiver.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL diff --git a/tests/ui/moves/move-into-dead-array-1.stderr b/tests/ui/moves/move-into-dead-array-1.stderr index 83779fb16ed..d9b719730d6 100644 --- a/tests/ui/moves/move-into-dead-array-1.stderr +++ b/tests/ui/moves/move-into-dead-array-1.stderr @@ -8,8 +8,8 @@ LL | a[i] = d(); | help: consider assigning a value | -LL | let mut a: [D; 4] = todo!(); - | +++++++++ +LL | let mut a: [D; 4] = [value; 4]; + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/moves/move-of-addr-of-mut.stderr b/tests/ui/moves/move-of-addr-of-mut.stderr index 706b52d3402..46f7d39a61a 100644 --- a/tests/ui/moves/move-of-addr-of-mut.stderr +++ b/tests/ui/moves/move-of-addr-of-mut.stderr @@ -9,8 +9,8 @@ LL | std::ptr::addr_of_mut!(x); = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | -LL | let mut x: S = todo!(); - | +++++++++ +LL | let mut x: S = value; + | +++++++ error: aborting due to 1 previous error diff --git a/tests/ui/moves/move-out-of-array-1.stderr b/tests/ui/moves/move-out-of-array-1.stderr index aa0251dbd85..9e4a08e0cef 100644 --- a/tests/ui/moves/move-out-of-array-1.stderr +++ b/tests/ui/moves/move-out-of-array-1.stderr @@ -6,6 +6,12 @@ LL | a[i] | | | cannot move out of here | move occurs because `a[_]` has type `D`, which does not implement the `Copy` trait + | +note: if `D` implemented `Clone`, you could clone the value + --> $DIR/move-out-of-array-1.rs:5:1 + | +LL | struct D { _x: u8 } + | ^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs b/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs index b2f68352f89..9d7277c1c24 100644 --- a/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs +++ b/tests/ui/moves/moves-based-on-type-capture-clause-bad.rs @@ -2,7 +2,7 @@ use std::thread; fn main() { let x = "Hello world!".to_string(); - thread::spawn(move|| { + thread::spawn(move || { println!("{}", x); }); println!("{}", x); //~ ERROR borrow of moved value diff --git a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr index 5e527bf445e..c2b9aeab237 100644 --- a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr +++ b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -3,8 +3,8 @@ error[E0382]: borrow of moved value: `x` | LL | let x = "Hello world!".to_string(); | - move occurs because `x` has type `String`, which does not implement the `Copy` trait -LL | thread::spawn(move|| { - | ------ value moved into closure here +LL | thread::spawn(move || { + | ------- value moved into closure here LL | println!("{}", x); | - variable moved due to use in closure LL | }); diff --git a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index 513631b2060..523134a9425 100644 --- a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -7,6 +7,11 @@ LL | let _f = to_fn(|| test(i)); | -- ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait | | | captured by this `Fn` closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _f = to_fn(|| test(i.clone())); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/moves/needs-clone-through-deref.fixed b/tests/ui/moves/needs-clone-through-deref.fixed index 43ea15d1b63..8b201c4720d 100644 --- a/tests/ui/moves/needs-clone-through-deref.fixed +++ b/tests/ui/moves/needs-clone-through-deref.fixed @@ -12,7 +12,7 @@ impl Deref for S { impl S { fn foo(&self) { // `self.clone()` returns `&S`, not `Vec` - for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} //~ ERROR cannot move out of dereference of `S` + for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {} //~ ERROR cannot move out of dereference of `S` } } fn main() {} diff --git a/tests/ui/moves/needs-clone-through-deref.stderr b/tests/ui/moves/needs-clone-through-deref.stderr index ff92f32e8d2..1f9aefeb4dd 100644 --- a/tests/ui/moves/needs-clone-through-deref.stderr +++ b/tests/ui/moves/needs-clone-through-deref.stderr @@ -10,8 +10,8 @@ note: `into_iter` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} - | ++++++++++++++++++++++++++++++ + +LL | for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {} + | ++++++++++++++++++++++++++++++ ~ error: aborting due to 1 previous error diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed index b3eae0b22b6..cdc86f61d24 100644 --- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed @@ -18,7 +18,7 @@ pub fn hashmap_copy<T, U>( map: &HashMap<T, U, Hash128_1>, ) where T: Hash + Clone, U: Clone { - let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); //~ ERROR + let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map).into_values().collect(); //~ ERROR } pub fn make_map() -> HashMap<String, i64, Hash128_1> diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr index 403daf8ff7c..755bbc5c21b 100644 --- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr @@ -10,8 +10,8 @@ note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied | -LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); - | ++++++++++++++++++++++++++++++++++++++++++++ + +LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map).into_values().collect(); + | ++++++++++++++++++++++++++++++++++++++++++++ ~ help: consider annotating `Hash128_1` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/moves/suggest-clone.fixed b/tests/ui/moves/suggest-clone.fixed index 59276a7b96d..59a162e72c1 100644 --- a/tests/ui/moves/suggest-clone.fixed +++ b/tests/ui/moves/suggest-clone.fixed @@ -7,5 +7,5 @@ impl Foo { } fn main() { let foo = &Foo; - <Foo as Clone>::clone(&foo).foo(); //~ ERROR cannot move out + <Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out } diff --git a/tests/ui/moves/suggest-clone.stderr b/tests/ui/moves/suggest-clone.stderr index 25e89a58955..f8e0ccdfcef 100644 --- a/tests/ui/moves/suggest-clone.stderr +++ b/tests/ui/moves/suggest-clone.stderr @@ -15,6 +15,10 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | <Foo as Clone>::clone(&foo).foo(); | +++++++++++++++++++++++ + +help: consider cloning the value if the performance cost is acceptable + | +LL | foo.clone().foo(); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs index c988d423373..0af28fc3d8e 100644 --- a/tests/ui/nested-cfg-attrs.rs +++ b/tests/ui/nested-cfg-attrs.rs @@ -1,4 +1,4 @@ -#[cfg_attr(all(), cfg_attr(all(), cfg(foo)))] +#[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))] fn f() {} fn main() { f() } //~ ERROR cannot find function `f` in this scope diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr index bab47064f6c..02cb9cb22a3 100644 --- a/tests/ui/never_type/issue-52443.stderr +++ b/tests/ui/never_type/issue-52443.stderr @@ -36,7 +36,7 @@ error[E0308]: mismatched types LL | [(); loop { break }]; | ^^^^^ expected `usize`, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | [(); loop { break 42 }]; | ++ diff --git a/tests/ui/nll/cannot-move-block-spans.stderr b/tests/ui/nll/cannot-move-block-spans.stderr index 0dc5c08ea5f..d96773e1edf 100644 --- a/tests/ui/nll/cannot-move-block-spans.stderr +++ b/tests/ui/nll/cannot-move-block-spans.stderr @@ -9,6 +9,11 @@ help: consider removing the dereference here LL - let x = { *r }; LL + let x = { r }; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let x = { *r }; +LL + let x = { r.clone() }; + | error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:6:22 @@ -21,6 +26,11 @@ help: consider removing the dereference here LL - let y = unsafe { *r }; LL + let y = unsafe { r }; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = unsafe { *r }; +LL + let y = unsafe { r.clone() }; + | error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:7:26 @@ -33,6 +43,11 @@ help: consider removing the dereference here LL - let z = loop { break *r; }; LL + let z = loop { break r; }; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let z = loop { break *r; }; +LL + let z = loop { break r.clone(); }; + | error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:11:15 @@ -47,6 +62,10 @@ help: consider borrowing here | LL | let x = { &arr[0] }; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let x = { arr[0].clone() }; + | ++++++++ error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:12:22 @@ -61,6 +80,10 @@ help: consider borrowing here | LL | let y = unsafe { &arr[0] }; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let y = unsafe { arr[0].clone() }; + | ++++++++ error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:13:26 @@ -75,6 +98,10 @@ help: consider borrowing here | LL | let z = loop { break &arr[0]; }; | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let z = loop { break arr[0].clone(); }; + | ++++++++ error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:17:38 @@ -87,6 +114,11 @@ help: consider removing the dereference here LL - let x = { let mut u = 0; u += 1; *r }; LL + let x = { let mut u = 0; u += 1; r }; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let x = { let mut u = 0; u += 1; *r }; +LL + let x = { let mut u = 0; u += 1; r.clone() }; + | error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:18:45 @@ -99,6 +131,11 @@ help: consider removing the dereference here LL - let y = unsafe { let mut u = 0; u += 1; *r }; LL + let y = unsafe { let mut u = 0; u += 1; r }; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = unsafe { let mut u = 0; u += 1; *r }; +LL + let y = unsafe { let mut u = 0; u += 1; r.clone() }; + | error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:19:49 @@ -111,6 +148,11 @@ help: consider removing the dereference here LL - let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; LL + let z = loop { let mut u = 0; u += 1; break r; u += 2; }; | +help: consider cloning the value if the performance cost is acceptable + | +LL - let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; +LL + let z = loop { let mut u = 0; u += 1; break r.clone(); u += 2; }; + | error: aborting due to 9 previous errors diff --git a/tests/ui/nll/closure-access-spans.stderr b/tests/ui/nll/closure-access-spans.stderr index 3e98fbd5e1d..f789e5e9f95 100644 --- a/tests/ui/nll/closure-access-spans.stderr +++ b/tests/ui/nll/closure-access-spans.stderr @@ -57,6 +57,12 @@ LL | || x; | move out of `x` occurs here LL | r.use_ref(); | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let r = &x; +LL + let r = x.clone(); + | error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:35:5 @@ -103,6 +109,11 @@ LL | || *x = String::new(); | ^^ -- borrow occurs due to use in closure | | | value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let r = x.clone(); + | ++++++++ error[E0382]: use of moved value: `x` --> $DIR/closure-access-spans.rs:50:5 @@ -115,6 +126,11 @@ LL | || x; | ^^ - use occurs due to use in closure | | | value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let r = x.clone(); + | ++++++++ error: aborting due to 9 previous errors diff --git a/tests/ui/nll/closure-move-spans.fixed b/tests/ui/nll/closure-move-spans.fixed new file mode 100644 index 00000000000..edd74e434e0 --- /dev/null +++ b/tests/ui/nll/closure-move-spans.fixed @@ -0,0 +1,23 @@ +// check that moves due to a closure capture give a special note +//@ run-rustfix +#![allow(unused_variables, unused_must_use, dead_code)] + +fn move_after_move(x: String) { + || x.clone(); + let y = x; //~ ERROR +} + +fn borrow_after_move(x: String) { + || x.clone(); + let y = &x; //~ ERROR +} + +fn borrow_mut_after_move(mut x: String) { + || x.clone(); + let y = &mut x; //~ ERROR +} + +fn fn_ref<F: Fn()>(f: F) -> F { f } +fn fn_mut<F: FnMut()>(f: F) -> F { f } + +fn main() {} diff --git a/tests/ui/nll/closure-move-spans.rs b/tests/ui/nll/closure-move-spans.rs index bf2431870a9..bba5c3776e6 100644 --- a/tests/ui/nll/closure-move-spans.rs +++ b/tests/ui/nll/closure-move-spans.rs @@ -1,4 +1,6 @@ // check that moves due to a closure capture give a special note +//@ run-rustfix +#![allow(unused_variables, unused_must_use, dead_code)] fn move_after_move(x: String) { || x; diff --git a/tests/ui/nll/closure-move-spans.stderr b/tests/ui/nll/closure-move-spans.stderr index 0446ef7b066..0b1da57605c 100644 --- a/tests/ui/nll/closure-move-spans.stderr +++ b/tests/ui/nll/closure-move-spans.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/closure-move-spans.rs:5:13 + --> $DIR/closure-move-spans.rs:7:13 | LL | fn move_after_move(x: String) { | - move occurs because `x` has type `String`, which does not implement the `Copy` trait @@ -9,9 +9,14 @@ LL | || x; | value moved into closure here LL | let y = x; | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | || x.clone(); + | ++++++++ error[E0382]: borrow of moved value: `x` - --> $DIR/closure-move-spans.rs:10:13 + --> $DIR/closure-move-spans.rs:12:13 | LL | fn borrow_after_move(x: String) { | - move occurs because `x` has type `String`, which does not implement the `Copy` trait @@ -21,9 +26,14 @@ LL | || x; | value moved into closure here LL | let y = &x; | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | || x.clone(); + | ++++++++ error[E0382]: borrow of moved value: `x` - --> $DIR/closure-move-spans.rs:15:13 + --> $DIR/closure-move-spans.rs:17:13 | LL | fn borrow_mut_after_move(mut x: String) { | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait @@ -33,6 +43,11 @@ LL | || x; | value moved into closure here LL | let y = &mut x; | ^^^^^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | || x.clone(); + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/nll/closures-in-loops.stderr b/tests/ui/nll/closures-in-loops.stderr index 2c1008c516c..050b220e626 100644 --- a/tests/ui/nll/closures-in-loops.stderr +++ b/tests/ui/nll/closures-in-loops.stderr @@ -4,10 +4,16 @@ error[E0382]: use of moved value: `x` LL | fn repreated_move(x: String) { | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | for i in 0..10 { + | -------------- inside of this loop LL | || x; | ^^ - use occurs due to use in closure | | | value moved into closure here, in previous iteration of loop + | +help: consider cloning the value if the performance cost is acceptable + | +LL | || x.clone(); + | ++++++++ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/closures-in-loops.rs:13:16 diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr index 97ed414b1ec..2aff375f0a7 100644 --- a/tests/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr @@ -27,6 +27,12 @@ LL | let mut s: S<B> = S::new(); drop(s); | move occurs because `s` has type `S<Box<u32>>`, which does not implement the `Copy` trait LL | s.x = 10; s.y = Box::new(20); | ^^^^^^^^ value partially assigned here after move + | +note: if `S<Box<u32>>` implemented `Clone`, you could clone the value + --> $DIR/issue-21232-partial-init-and-use.rs:15:1 + | +LL | struct S<Y> { + | ^^^^^^^^^^^ error[E0382]: assign to part of moved value: `t` --> $DIR/issue-21232-partial-init-and-use.rs:116:5 @@ -72,6 +78,12 @@ LL | let mut s: S<B> = S::new(); drop(s); | move occurs because `s` has type `S<Box<u32>>`, which does not implement the `Copy` trait LL | s.x = 10; | ^^^^^^^^ value partially assigned here after move + | +note: if `S<Box<u32>>` implemented `Clone`, you could clone the value + --> $DIR/issue-21232-partial-init-and-use.rs:15:1 + | +LL | struct S<Y> { + | ^^^^^^^^^^^ error[E0382]: assign to part of moved value: `t` --> $DIR/issue-21232-partial-init-and-use.rs:142:5 diff --git a/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr b/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr index ae797800457..39ec45b20ea 100644 --- a/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr +++ b/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr @@ -10,6 +10,11 @@ LL | _ if { (|| { let bar = b; *bar = false; })(); | -- - variable moved due to use in closure | | | value moved into closure here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | _ if { (|| { let bar = b.clone(); *bar = false; })(); + | ++++++++ error[E0382]: use of moved value: `b` --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5 @@ -23,6 +28,11 @@ LL | (|| { let bar = b; *bar = false; })(); | -- - variable moved due to use in closure | | | value moved into closure here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let bar = b.clone(); *bar = false; })(); + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs b/tests/ui/nll/issue-40510-1.rs index ca53dcd9b41..ca53dcd9b41 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs +++ b/tests/ui/nll/issue-40510-1.rs diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr b/tests/ui/nll/issue-40510-1.stderr index 81fed1305cb..81fed1305cb 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr +++ b/tests/ui/nll/issue-40510-1.stderr diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs b/tests/ui/nll/issue-40510-2.rs index 9ce54862265..9ce54862265 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs +++ b/tests/ui/nll/issue-40510-2.rs diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs b/tests/ui/nll/issue-40510-3.rs index 181263adcbf..181263adcbf 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs +++ b/tests/ui/nll/issue-40510-3.rs diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr b/tests/ui/nll/issue-40510-3.stderr index 43e8a73b819..43e8a73b819 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr +++ b/tests/ui/nll/issue-40510-3.stderr diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs b/tests/ui/nll/issue-40510-4.rs index 771502894f1..771502894f1 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs +++ b/tests/ui/nll/issue-40510-4.rs diff --git a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr index 7f9cbc3c30a..f4e7869bf00 100644 --- a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr +++ b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr @@ -41,6 +41,10 @@ help: consider borrowing here | LL | let p = &s.url; p | + +help: consider cloning the value if the performance cost is acceptable + | +LL | let p = s.url.clone(); p + | ++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/nll/issue-52086.stderr b/tests/ui/nll/issue-52086.stderr index 3b2dae9b72b..e4f0c49e557 100644 --- a/tests/ui/nll/issue-52086.stderr +++ b/tests/ui/nll/issue-52086.stderr @@ -3,12 +3,22 @@ error[E0507]: cannot move out of an `Rc` | LL | drop(x.field); | ^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x.field.clone()); + | ++++++++ error[E0507]: cannot move out of an `Arc` --> $DIR/issue-52086.rs:12:10 | LL | drop(y.field); | ^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(y.field.clone()); + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr index 587f3071027..fbaec8a6008 100644 --- a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -7,6 +7,11 @@ LL | expect_fn(|| drop(x.0)); | -- ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait | | | captured by this `Fn` closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | expect_fn(|| drop(x.0.clone())); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr index d692ded36fa..066e77b17fc 100644 --- a/tests/ui/nll/match-cfg-fake-edges.stderr +++ b/tests/ui/nll/match-cfg-fake-edges.stderr @@ -126,8 +126,8 @@ LL | _ if { x; false } => 2, | help: consider assigning a value | -LL | let x = 0; - | +++ +LL | let x = 42; + | ++++ error[E0381]: used binding `x` isn't initialized --> $DIR/match-cfg-fake-edges.rs:86:31 @@ -142,8 +142,8 @@ LL | _ if let Some(()) = { x; None } => 2, | help: consider assigning a value | -LL | let x = 0; - | +++ +LL | let x = 42; + | ++++ error[E0382]: use of moved value: `x` --> $DIR/match-cfg-fake-edges.rs:99:22 diff --git a/tests/ui/nll/match-on-borrowed.stderr b/tests/ui/nll/match-on-borrowed.stderr index 9273484565a..4e0b048fb4b 100644 --- a/tests/ui/nll/match-on-borrowed.stderr +++ b/tests/ui/nll/match-on-borrowed.stderr @@ -43,8 +43,8 @@ LL | match n {} | help: consider assigning a value | -LL | let n: Never = todo!(); - | +++++++++ +LL | let n: Never = value; + | +++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr index 0d994ef29ba..842ecaf524b 100644 --- a/tests/ui/nll/move-errors.stderr +++ b/tests/ui/nll/move-errors.stderr @@ -4,6 +4,11 @@ error[E0507]: cannot move out of `*a` which is behind a shared reference LL | let b = *a; | ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-errors.rs:1:1 + | +LL | struct A(String); + | ^^^^^^^^ help: consider removing the dereference here | LL - let b = *a; @@ -19,6 +24,11 @@ LL | let b = a[0]; | cannot move out of here | move occurs because `a[_]` has type `A`, which does not implement the `Copy` trait | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-errors.rs:1:1 + | +LL | struct A(String); + | ^^^^^^^^ help: consider borrowing here | LL | let b = &a[0]; @@ -30,6 +40,11 @@ error[E0507]: cannot move out of `**r` which is behind a shared reference LL | let s = **r; | ^^^ move occurs because `**r` has type `A`, which does not implement the `Copy` trait | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-errors.rs:1:1 + | +LL | struct A(String); + | ^^^^^^^^ help: consider removing the dereference here | LL - let s = **r; @@ -42,6 +57,11 @@ error[E0507]: cannot move out of an `Rc` LL | let s = *r; | ^^ move occurs because value has type `A`, which does not implement the `Copy` trait | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-errors.rs:1:1 + | +LL | struct A(String); + | ^^^^^^^^ help: consider removing the dereference here | LL - let s = *r; @@ -57,6 +77,11 @@ LL | let a = [A("".to_string())][0]; | cannot move out of here | move occurs because value has type `A`, which does not implement the `Copy` trait | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-errors.rs:1:1 + | +LL | struct A(String); + | ^^^^^^^^ help: consider borrowing here | LL | let a = &[A("".to_string())][0]; @@ -96,6 +121,12 @@ error[E0507]: cannot move out of `*a` which is behind a shared reference | LL | b = *a; | ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait + | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/move-errors.rs:1:1 + | +LL | struct A(String); + | ^^^^^^^^ error[E0508]: cannot move out of type `[B; 1]`, a non-copy array --> $DIR/move-errors.rs:74:11 diff --git a/tests/ui/non-copyable-void.rs b/tests/ui/non-copyable-void.rs index 58668147801..55bad82bc33 100644 --- a/tests/ui/non-copyable-void.rs +++ b/tests/ui/non-copyable-void.rs @@ -1,10 +1,8 @@ -#![feature(rustc_private)] - -extern crate libc; +use std::ffi::c_void; fn main() { let x : *const Vec<isize> = &vec![1,2,3]; - let y : *const libc::c_void = x as *const libc::c_void; + let y : *const c_void = x as *const c_void; unsafe { let _z = (*y).clone(); //~^ ERROR no method named `clone` found diff --git a/tests/ui/non-copyable-void.stderr b/tests/ui/non-copyable-void.stderr index d25bb8c17ee..373557fa01a 100644 --- a/tests/ui/non-copyable-void.stderr +++ b/tests/ui/non-copyable-void.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `clone` found for enum `c_void` in the current scope - --> $DIR/non-copyable-void.rs:9:23 + --> $DIR/non-copyable-void.rs:7:23 | LL | let _z = (*y).clone(); | ^^^^^ method not found in `c_void` 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 index aee05f5e512..4f5310082e1 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed @@ -2,8 +2,6 @@ //@[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 diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr index 52db31d620c..efddab6dff6 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.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:8:33 + --> $DIR/bare-trait-dont-suggest-dyn.rs:6: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 index f795e910d21..0545a1afcc1 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr @@ -1,5 +1,5 @@ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 + --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 | LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ @@ -7,7 +7,7 @@ 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> note: the lint level is defined here - --> $DIR/bare-trait-dont-suggest-dyn.rs:7:9 + --> $DIR/bare-trait-dont-suggest-dyn.rs:5:9 | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ 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 + --> $DIR/bare-trait-dont-suggest-dyn.rs:6: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.rs b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs index e927b510b9d..cb5a305eab0 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs @@ -2,8 +2,6 @@ //@[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 diff --git a/tests/ui/once-cant-call-twice-on-heap.stderr b/tests/ui/once-cant-call-twice-on-heap.stderr index 33dd840dbc2..42697374115 100644 --- a/tests/ui/once-cant-call-twice-on-heap.stderr +++ b/tests/ui/once-cant-call-twice-on-heap.stderr @@ -8,15 +8,13 @@ LL | blk(); LL | blk(); | ^^^ value used here after move | -note: this value implements `FnOnce`, which causes it to be moved when called - --> $DIR/once-cant-call-twice-on-heap.rs:7:5 +note: `FnOnce` closures can only be called once + --> $DIR/once-cant-call-twice-on-heap.rs:6:10 | +LL | fn foo<F:FnOnce()>(blk: F) { + | ^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | blk(); - | ^^^ -help: consider further restricting this bound - | -LL | fn foo<F:FnOnce() + Copy>(blk: F) { - | ++++++ + | ----- this value implements `FnOnce`, which causes it to be moved when called error: aborting due to 1 previous error diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index 82b61e43f44..23b863568bc 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -20,6 +20,8 @@ error: the compiler unexpectedly panicked. this is a bug. + + query stack during panic: #0 [resolver_for_lowering_raw] getting the resolver for lowering end of query stack diff --git a/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr b/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr index 8178bd22373..cc21df77353 100644 --- a/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr +++ b/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr @@ -138,7 +138,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/assoc-static-semantic-fail.rs:32:5 | LL | pub(crate) default static TD: u8; - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -162,7 +162,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/assoc-static-semantic-fail.rs:47:5 | LL | pub default static TD: u8; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs index d97f24a3d29..33671df9492 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs @@ -1,9 +1,9 @@ #![feature(stmt_expr_attributes)] fn foo() -> String { - #[cfg(feature = "validation")] + #[cfg(FALSE)] [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() //~ ERROR expected `;`, found `#` - #[cfg(not(feature = "validation"))] + #[cfg(not(FALSE))] String::new() } diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr index a71253a5e42..6266718162f 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr @@ -1,11 +1,11 @@ error: expected `;`, found `#` --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64 | -LL | #[cfg(feature = "validation")] - | ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute +LL | #[cfg(FALSE)] + | ------------- only `;` terminated statements or tail expressions are allowed after this attribute LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() | ^ expected `;` here -LL | #[cfg(not(feature = "validation"))] +LL | #[cfg(not(FALSE))] | - unexpected token | help: add `;` here @@ -18,9 +18,9 @@ LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() } | + + help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)` | -LL ~ if cfg!(feature = "validation") { +LL ~ if cfg!(FALSE) { LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() -LL ~ } else if cfg!(not(feature = "validation")) { +LL ~ } else if cfg!(not(FALSE)) { LL ~ String::new() LL + } | diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs index ad9e7ad707b..e2a62922bcc 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs @@ -5,7 +5,7 @@ macro_rules! the_macro { #[cfg()] $foo //~ ERROR expected `;`, found `#` - #[cfg(bar)] + #[cfg(FALSE)] $bar }; } diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr index 7b9b8319674..fa4409f73fa 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr @@ -6,7 +6,7 @@ LL | #[cfg()] LL | $foo | ^ expected `;` here LL | -LL | #[cfg(bar)] +LL | #[cfg(FALSE)] | - unexpected token ... LL | the_macro!( (); (); ); diff --git a/tests/ui/parser/default.stderr b/tests/ui/parser/default.stderr index e6330f368d9..c420e5a774d 100644 --- a/tests/ui/parser/default.stderr +++ b/tests/ui/parser/default.stderr @@ -21,7 +21,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/default.rs:17:5 | LL | pub default fn foo<T: Default>() -> T { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/parser/issues/issue-103381.fixed b/tests/ui/parser/issues/issue-103381.fixed index 9b63bf206a0..87c308789a1 100644 --- a/tests/ui/parser/issues/issue-103381.fixed +++ b/tests/ui/parser/issues/issue-103381.fixed @@ -37,21 +37,6 @@ fn should_ok_3() { if true && if true { true } else { false } {} } -fn shoule_match_ok() { - #[cfg(feature = "full")] - { - let a = 1; - let b = 2; - if match a { - 1 if b == 1 => true, - _ => false, - } && if a > 1 { true } else { false } - { - true - } - } -} - fn should_ok_in_nested() { if true && if true { true } else { false } { true } else { false }; } diff --git a/tests/ui/parser/issues/issue-103381.rs b/tests/ui/parser/issues/issue-103381.rs index a44a7410aaf..ccbc40e5d02 100644 --- a/tests/ui/parser/issues/issue-103381.rs +++ b/tests/ui/parser/issues/issue-103381.rs @@ -37,21 +37,6 @@ fn should_ok_3() { if true && if true { true } else { false } {} } -fn shoule_match_ok() { - #[cfg(feature = "full")] - { - let a = 1; - let b = 2; - if match a { - 1 if b == 1 => true, - _ => false, - } && if a > 1 { true } else { false } - { - true - } - } -} - fn should_ok_in_nested() { if true && if true { true } else { false } { true } else { false }; } diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr index 7c5cc4777b6..2c0baf7e5f8 100644 --- a/tests/ui/parser/recover/recover-range-pats.stderr +++ b/tests/ui/parser/recover/recover-range-pats.stderr @@ -491,10 +491,6 @@ LL | mac2!(0, 1); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let $e1..$e2; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:138:17 @@ -509,10 +505,6 @@ LL | mac2!(0, 1); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let $e1...$e2; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:142:17 @@ -527,10 +519,6 @@ LL | mac2!(0, 1); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let $e1..=$e2; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:151:17 @@ -545,10 +533,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ..$e; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:153:17 @@ -563,10 +547,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ...$e; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:156:17 @@ -581,10 +561,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ..=$e; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:158:17 @@ -599,10 +575,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e..; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:160:17 @@ -617,10 +589,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e...; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:162:17 @@ -635,10 +603,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e..=; { todo!() } - | ++ +++++++++++ error: aborting due to 69 previous errors diff --git a/tests/ui/parser/trait-pub-assoc-const.stderr b/tests/ui/parser/trait-pub-assoc-const.stderr index 436f6a3909c..1bace786b21 100644 --- a/tests/ui/parser/trait-pub-assoc-const.stderr +++ b/tests/ui/parser/trait-pub-assoc-const.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/trait-pub-assoc-const.rs:2:5 | LL | pub const Foo: u32; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/parser/trait-pub-assoc-ty.stderr b/tests/ui/parser/trait-pub-assoc-ty.stderr index 279e3a95354..28e05bdc630 100644 --- a/tests/ui/parser/trait-pub-assoc-ty.stderr +++ b/tests/ui/parser/trait-pub-assoc-ty.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/trait-pub-assoc-ty.rs:2:5 | LL | pub type Foo; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/parser/trait-pub-method.stderr b/tests/ui/parser/trait-pub-method.stderr index ee8b6f7cb62..cc1ba0eaaea 100644 --- a/tests/ui/parser/trait-pub-method.stderr +++ b/tests/ui/parser/trait-pub-method.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/trait-pub-method.rs:2:5 | LL | pub fn foo(); - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 9359244c6eb..00964cb8336 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -333,6 +333,11 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +note: if `U` implemented `Clone`, you could clone the value + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5 + | +LL | struct U; + | ^^^^^^^^ error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 @@ -341,6 +346,11 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +note: if `U` implemented `Clone`, you could clone the value + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5 + | +LL | struct U; + | ^^^^^^^^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0507]: cannot move out of `a` in pattern guard diff --git a/tests/ui/precondition-checks/cfg-ub-checks-default.rs b/tests/ui/precondition-checks/cfg-ub-checks-default.rs new file mode 100644 index 00000000000..b672589d02a --- /dev/null +++ b/tests/ui/precondition-checks/cfg-ub-checks-default.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ revisions: YES NO +//@ [YES] compile-flags: -Cdebug-assertions=yes +//@ [NO] compile-flags: -Cdebug-assertions=no + +#![feature(cfg_ub_checks)] + +fn main() { + assert_eq!(cfg!(ub_checks), cfg!(debug_assertions)); +} diff --git a/tests/ui/precondition-checks/cfg-ub-checks-no.rs b/tests/ui/precondition-checks/cfg-ub-checks-no.rs new file mode 100644 index 00000000000..73705a7e632 --- /dev/null +++ b/tests/ui/precondition-checks/cfg-ub-checks-no.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zub-checks=no + +#![feature(cfg_ub_checks)] + +fn main() { + assert!(!cfg!(ub_checks)); + assert!(compiles_differently()); +} + +#[cfg(ub_checks)] +fn compiles_differently() -> bool { + false +} + +#[cfg(not(ub_checks))] +fn compiles_differently() -> bool { + true +} diff --git a/tests/ui/precondition-checks/cfg-ub-checks-yes.rs b/tests/ui/precondition-checks/cfg-ub-checks-yes.rs new file mode 100644 index 00000000000..410ab1fe4ec --- /dev/null +++ b/tests/ui/precondition-checks/cfg-ub-checks-yes.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zub-checks=yes + +#![feature(cfg_ub_checks)] + +fn main() { + assert!(cfg!(ub_checks)); + assert!(compiles_differently()); +} + +#[cfg(ub_checks)] +fn compiles_differently() -> bool { + true +} + +#[cfg(not(ub_checks))] +fn compiles_differently() -> bool { + false +} diff --git a/tests/ui/precondition-checks/misaligned-slice.rs b/tests/ui/precondition-checks/misaligned-slice.rs index 52c149b594e..2963a0b5e63 100644 --- a/tests/ui/precondition-checks/misaligned-slice.rs +++ b/tests/ui/precondition-checks/misaligned-slice.rs @@ -1,5 +1,5 @@ //@ run-fail -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts //@ ignore-debug diff --git a/tests/ui/precondition-checks/null-slice.rs b/tests/ui/precondition-checks/null-slice.rs index 61c7d467649..280960358b7 100644 --- a/tests/ui/precondition-checks/null-slice.rs +++ b/tests/ui/precondition-checks/null-slice.rs @@ -1,5 +1,5 @@ //@ run-fail -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts //@ ignore-debug diff --git a/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs b/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs index ba02c3da7b2..011e92183fa 100644 --- a/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs +++ b/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs @@ -1,5 +1,5 @@ //@ run-fail -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: slice::get_unchecked requires //@ ignore-debug diff --git a/tests/ui/privacy/issue-113860-1.stderr b/tests/ui/privacy/issue-113860-1.stderr index c33ce26f0f6..c05452fb51c 100644 --- a/tests/ui/privacy/issue-113860-1.stderr +++ b/tests/ui/privacy/issue-113860-1.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-113860-1.rs:12:5 | LL | pub(self) fn fun() {} - | ^^^^^^^^^ + | ^^^^^^^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/privacy/issue-113860-2.stderr b/tests/ui/privacy/issue-113860-2.stderr index 6748bc27668..c53c490ca1e 100644 --- a/tests/ui/privacy/issue-113860-2.stderr +++ b/tests/ui/privacy/issue-113860-2.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-113860-2.rs:12:5 | LL | pub(self) type X = Self; - | ^^^^^^^^^ + | ^^^^^^^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/privacy/issue-113860.stderr b/tests/ui/privacy/issue-113860.stderr index 3204f4ff916..d813b740ac5 100644 --- a/tests/ui/privacy/issue-113860.stderr +++ b/tests/ui/privacy/issue-113860.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-113860.rs:12:5 | LL | pub(self) const X: u32 = 3; - | ^^^^^^^^^ + | ^^^^^^^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/privacy/issue-29161.stderr b/tests/ui/privacy/issue-29161.stderr index 1a6c80499a1..f8911cb09c1 100644 --- a/tests/ui/privacy/issue-29161.stderr +++ b/tests/ui/privacy/issue-29161.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-29161.rs:5:9 | LL | pub fn default() -> A { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/privacy/priv-in-bad-locations.stderr b/tests/ui/privacy/priv-in-bad-locations.stderr index 70dab5bfe13..93a0eabb914 100644 --- a/tests/ui/privacy/priv-in-bad-locations.stderr +++ b/tests/ui/privacy/priv-in-bad-locations.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:1:1 | LL | pub extern "C" { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual foreign items instead @@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:11:1 | LL | pub impl B {} - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual impl items instead @@ -18,7 +18,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:13:1 | LL | pub impl A for B { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -26,7 +26,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:14:5 | LL | pub fn foo(&self) {} - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait diff --git a/tests/ui/privacy/privacy-sanity.stderr b/tests/ui/privacy/privacy-sanity.stderr index a537f8c1901..0acb05cbaba 100644 --- a/tests/ui/privacy/privacy-sanity.stderr +++ b/tests/ui/privacy/privacy-sanity.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:13:1 | LL | pub impl Tr for S { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:14:5 | LL | pub fn f() {} - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -18,7 +18,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:15:5 | LL | pub const C: u8 = 0; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -26,7 +26,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:16:5 | LL | pub type T = u8; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -34,7 +34,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:18:1 | LL | pub impl S { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual impl items instead @@ -42,7 +42,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:23:1 | LL | pub extern "C" { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual foreign items instead @@ -50,7 +50,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:39:5 | LL | pub impl Tr for S { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -58,7 +58,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:40:9 | LL | pub fn f() {} - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -66,7 +66,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:41:9 | LL | pub const C: u8 = 0; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -74,7 +74,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:42:9 | LL | pub type T = u8; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -82,7 +82,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:44:5 | LL | pub impl S { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual impl items instead @@ -90,7 +90,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:49:5 | LL | pub extern "C" { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual foreign items instead @@ -98,7 +98,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:68:5 | LL | pub impl Tr for S { - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -106,7 +106,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:69:9 | LL | pub fn f() {} - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -114,7 +114,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:70:9 | LL | pub const C: u8 = 0; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -122,7 +122,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:71:9 | LL | pub type T = u8; - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -130,7 +130,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:73:5 | LL | pub impl S { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual impl items instead @@ -138,7 +138,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:78:5 | LL | pub extern "C" { - | ^^^ + | ^^^ help: remove the qualifier | = note: place qualifiers on individual foreign items instead diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs index c6c5561c3c4..e82bfd0477f 100644 --- a/tests/ui/privacy/unnameable_types.rs +++ b/tests/ui/privacy/unnameable_types.rs @@ -1,4 +1,3 @@ -#![feature(type_privacy_lints)] #![deny(unnameable_types)] mod m { diff --git a/tests/ui/privacy/unnameable_types.stderr b/tests/ui/privacy/unnameable_types.stderr index d68a11c9728..a1bc60ef9c2 100644 --- a/tests/ui/privacy/unnameable_types.stderr +++ b/tests/ui/privacy/unnameable_types.stderr @@ -1,23 +1,23 @@ error: struct `PubStruct` is reachable but cannot be named - --> $DIR/unnameable_types.rs:5:5 + --> $DIR/unnameable_types.rs:4:5 | LL | pub struct PubStruct(pub i32); | ^^^^^^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` | note: the lint level is defined here - --> $DIR/unnameable_types.rs:2:9 + --> $DIR/unnameable_types.rs:1:9 | LL | #![deny(unnameable_types)] | ^^^^^^^^^^^^^^^^ error: enum `PubE` is reachable but cannot be named - --> $DIR/unnameable_types.rs:7:5 + --> $DIR/unnameable_types.rs:6:5 | LL | pub enum PubE { | ^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` error: trait `PubTr` is reachable but cannot be named - --> $DIR/unnameable_types.rs:11:5 + --> $DIR/unnameable_types.rs:10:5 | LL | pub trait PubTr { | ^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` diff --git a/tests/ui/privacy/useless-pub.stderr b/tests/ui/privacy/useless-pub.stderr index 73497e3fed5..7d064c12a09 100644 --- a/tests/ui/privacy/useless-pub.stderr +++ b/tests/ui/privacy/useless-pub.stderr @@ -2,7 +2,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/useless-pub.rs:8:5 | LL | pub fn foo(&self) {} - | ^^^ + | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait @@ -10,7 +10,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/useless-pub.rs:12:10 | LL | V1 { pub f: i32 }, - | ^^^ + | ^^^ help: remove the qualifier | = note: enum variants and their fields always share the visibility of the enum they are in @@ -18,7 +18,7 @@ error[E0449]: visibility qualifiers are not permitted here --> $DIR/useless-pub.rs:13:8 | LL | V2(pub i32), - | ^^^ + | ^^^ help: remove the qualifier | = note: enum variants and their fields always share the visibility of the enum they are in diff --git a/tests/ui/proc-macro/derive-helper-configured.rs b/tests/ui/proc-macro/derive-helper-configured.rs index 74d5d827f16..45e6e64d392 100644 --- a/tests/ui/proc-macro/derive-helper-configured.rs +++ b/tests/ui/proc-macro/derive-helper-configured.rs @@ -1,17 +1,15 @@ // Derive helpers are resolved successfully inside `cfg_attr`. //@ check-pass -// compile-flats:--cfg TRUE //@ aux-build:test-macros.rs #[macro_use] extern crate test_macros; -#[cfg_attr(TRUE, empty_helper)] #[derive(Empty)] -#[cfg_attr(TRUE, empty_helper)] +#[cfg_attr(all(), empty_helper)] struct S { - #[cfg_attr(TRUE, empty_helper)] + #[cfg_attr(all(), empty_helper)] field: u8, } diff --git a/tests/ui/proc-macro/modify-ast.rs b/tests/ui/proc-macro/modify-ast.rs index 86a7d6a7772..4c125c1c6e8 100644 --- a/tests/ui/proc-macro/modify-ast.rs +++ b/tests/ui/proc-macro/modify-ast.rs @@ -7,7 +7,7 @@ use modify_ast::*; #[derive(Foo)] pub struct MyStructc { - #[cfg_attr(my_cfg, foo)] + #[cfg_attr(FALSE, foo)] _a: i32, } diff --git a/tests/ui/process/core-run-destroy.rs b/tests/ui/process/core-run-destroy.rs index 338203657bd..3f2ea0e8441 100644 --- a/tests/ui/process/core-run-destroy.rs +++ b/tests/ui/process/core-run-destroy.rs @@ -14,10 +14,6 @@ // memory, which makes for some *confusing* logs. That's why these are here // instead of in std. -#![feature(rustc_private, duration)] - -extern crate libc; - use std::process::{self, Command, Child, Output, Stdio}; use std::str; use std::sync::mpsc::channel; diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs index bae121576bd..afb1b721182 100644 --- a/tests/ui/process/process-panic-after-fork.rs +++ b/tests/ui/process/process-panic-after-fork.rs @@ -14,14 +14,13 @@ extern crate libc; use std::alloc::{GlobalAlloc, Layout}; +use std::ffi::c_int; use std::fmt; use std::panic::{self, panic_any}; use std::os::unix::process::{CommandExt, ExitStatusExt}; use std::process::{self, Command, ExitStatus}; use std::sync::atomic::{AtomicU32, Ordering}; -use libc::c_int; - /// This stunt allocator allows us to spot heap allocations in the child. struct PidChecking<A> { parent: A, diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs b/tests/ui/recursion/issue-23302-1.rs index 24e79dc5811..24e79dc5811 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs +++ b/tests/ui/recursion/issue-23302-1.rs diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr b/tests/ui/recursion/issue-23302-1.stderr index 234060ab5c8..234060ab5c8 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr +++ b/tests/ui/recursion/issue-23302-1.stderr diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs b/tests/ui/recursion/issue-23302-2.rs index e89c7eab503..e89c7eab503 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs +++ b/tests/ui/recursion/issue-23302-2.rs diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr b/tests/ui/recursion/issue-23302-2.stderr index 9bd95239c83..9bd95239c83 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr +++ b/tests/ui/recursion/issue-23302-2.stderr diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs b/tests/ui/recursion/issue-23302-3.rs index da75f330798..da75f330798 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs +++ b/tests/ui/recursion/issue-23302-3.rs diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr b/tests/ui/recursion/issue-23302-3.stderr index 8a152f58966..8a152f58966 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr +++ b/tests/ui/recursion/issue-23302-3.stderr diff --git a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs index f6a628e97f5..bef0d70c776 100644 --- a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs +++ b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs @@ -8,10 +8,10 @@ // // 'a : 'b -#![warn(unused_lifetimes)] +#![warn(redundant_lifetimes)] -fn test<'a,'b>(x: &'a i32) -> &'b i32 - where 'a: 'static //~ WARN unnecessary lifetime parameter `'a` +fn test<'a,'b>(x: &'a i32) -> &'b i32 //~ WARN unnecessary lifetime parameter `'a` + where 'a: 'static { x } diff --git a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr index 9f03a6553ba..d97cfd59f2b 100644 --- a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr +++ b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr @@ -1,15 +1,15 @@ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:14:11 + --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:13:9 | -LL | where 'a: 'static - | ^^ +LL | fn test<'a,'b>(x: &'a i32) -> &'b i32 + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` note: the lint level is defined here --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:11:9 | -LL | #![warn(unused_lifetimes)] - | ^^^^^^^^^^^^^^^^ +LL | #![warn(redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/regions/regions-static-bound-rpass.rs b/tests/ui/regions/regions-static-bound-rpass.rs index 27da42882f3..f4177f835b1 100644 --- a/tests/ui/regions/regions-static-bound-rpass.rs +++ b/tests/ui/regions/regions-static-bound-rpass.rs @@ -1,18 +1,19 @@ //@ run-pass -#![warn(unused_lifetimes)] +#![warn(redundant_lifetimes)] fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () - where 'a: 'static { t } //~^ WARN unnecessary lifetime parameter `'a` + where 'a: 'static { t } fn static_id<'a>(t: &'a ()) -> &'static () - where 'a: 'static { t } //~^ WARN unnecessary lifetime parameter `'a` + where 'a: 'static { t } fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () +//~^ WARN unnecessary lifetime parameter `'a` +//~| WARN unnecessary lifetime parameter `'b` where 'a: 'b, 'b: 'static { t } -//~^ WARN unnecessary lifetime parameter `'b` fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } diff --git a/tests/ui/regions/regions-static-bound-rpass.stderr b/tests/ui/regions/regions-static-bound-rpass.stderr index f0f3a4c5261..4199ac7bb3d 100644 --- a/tests/ui/regions/regions-static-bound-rpass.stderr +++ b/tests/ui/regions/regions-static-bound-rpass.stderr @@ -1,31 +1,39 @@ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-static-bound-rpass.rs:6:11 + --> $DIR/regions-static-bound-rpass.rs:5:17 | -LL | where 'a: 'static { t } - | ^^ +LL | fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` note: the lint level is defined here --> $DIR/regions-static-bound-rpass.rs:3:9 | -LL | #![warn(unused_lifetimes)] - | ^^^^^^^^^^^^^^^^ +LL | #![warn(redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-static-bound-rpass.rs:10:11 + --> $DIR/regions-static-bound-rpass.rs:9:14 | -LL | where 'a: 'static { t } - | ^^ +LL | fn static_id<'a>(t: &'a ()) -> &'static () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound-rpass.rs:13:23 + | +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` warning: unnecessary lifetime parameter `'b` - --> $DIR/regions-static-bound-rpass.rs:14:19 + --> $DIR/regions-static-bound-rpass.rs:13:26 | -LL | where 'a: 'b, 'b: 'static { t } - | ^^ +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'b` + = note: you can use the `'static` lifetime directly, in place of `'b` -warning: 3 warnings emitted +warning: 4 warnings emitted diff --git a/tests/ui/regions/regions-static-bound.rs b/tests/ui/regions/regions-static-bound.rs index e7aa8795f01..32fa2536533 100644 --- a/tests/ui/regions/regions-static-bound.rs +++ b/tests/ui/regions/regions-static-bound.rs @@ -1,12 +1,13 @@ -#![warn(unused_lifetimes)] +#![warn(unused_lifetimes, redundant_lifetimes)] fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } -//~^ WARN lifetime parameter `'b` never used -//~| WARN unnecessary lifetime parameter `'a` +//~^ WARN unnecessary lifetime parameter `'a` +//~| WARN lifetime parameter `'b` never used fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () +//~^ WARN unnecessary lifetime parameter `'a` +//~| WARN unnecessary lifetime parameter `'b` where 'a: 'b, 'b: 'static { t } -//~^ WARN unnecessary lifetime parameter `'b` fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { t diff --git a/tests/ui/regions/regions-static-bound.stderr b/tests/ui/regions/regions-static-bound.stderr index b314e9fe85d..48aa8f32329 100644 --- a/tests/ui/regions/regions-static-bound.stderr +++ b/tests/ui/regions/regions-static-bound.stderr @@ -9,27 +9,40 @@ LL | fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } note: the lint level is defined here --> $DIR/regions-static-bound.rs:1:9 | -LL | #![warn(unused_lifetimes)] +LL | #![warn(unused_lifetimes, redundant_lifetimes)] | ^^^^^^^^^^^^^^^^ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-static-bound.rs:3:53 + --> $DIR/regions-static-bound.rs:3:14 | LL | fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } - | ^^ + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` +note: the lint level is defined here + --> $DIR/regions-static-bound.rs:1:27 + | +LL | #![warn(unused_lifetimes, redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound.rs:7:23 + | +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` warning: unnecessary lifetime parameter `'b` - --> $DIR/regions-static-bound.rs:8:19 + --> $DIR/regions-static-bound.rs:7:26 | -LL | where 'a: 'b, 'b: 'static { t } - | ^^ +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'b` + = note: you can use the `'static` lifetime directly, in place of `'b` error: lifetime may not live long enough - --> $DIR/regions-static-bound.rs:12:5 + --> $DIR/regions-static-bound.rs:13:5 | LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | -- lifetime `'a` defined here @@ -37,7 +50,7 @@ LL | t | ^ returning this value requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/regions-static-bound.rs:17:5 + --> $DIR/regions-static-bound.rs:18:5 | LL | fn error(u: &(), v: &()) { | - - let's call the lifetime of this reference `'1` @@ -50,7 +63,7 @@ LL | static_id(&u); | argument requires that `'1` must outlive `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/regions-static-bound.rs:19:5 + --> $DIR/regions-static-bound.rs:20:5 | LL | fn error(u: &(), v: &()) { | - - let's call the lifetime of this reference `'2` @@ -63,6 +76,6 @@ LL | static_id_indirect(&v); | `v` escapes the function body here | argument requires that `'2` must outlive `'static` -error: aborting due to 3 previous errors; 3 warnings emitted +error: aborting due to 3 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/regions/transitively-redundant-lifetimes.rs b/tests/ui/regions/transitively-redundant-lifetimes.rs new file mode 100644 index 00000000000..9c29f66e54c --- /dev/null +++ b/tests/ui/regions/transitively-redundant-lifetimes.rs @@ -0,0 +1,20 @@ +#![deny(redundant_lifetimes)] + +fn a<'a, 'b>(x: &'a &'b &'a ()) {} //~ ERROR unnecessary lifetime parameter `'b` + +fn b<'a: 'b, 'b: 'a>() {} //~ ERROR unnecessary lifetime parameter `'b` + +struct Foo<T: 'static>(T); +fn c<'a>(_: Foo<&'a ()>) {} //~ ERROR unnecessary lifetime parameter `'a` + +struct Bar<'a>(&'a ()); +impl<'a> Bar<'a> { + fn d<'b: 'a>(&'b self) {} //~ ERROR unnecessary lifetime parameter `'b` +} + +fn ok(x: &'static &()) {} + +trait Tr<'a> {} +impl<'a: 'static> Tr<'a> for () {} //~ ERROR unnecessary lifetime parameter `'a` + +fn main() {} diff --git a/tests/ui/regions/transitively-redundant-lifetimes.stderr b/tests/ui/regions/transitively-redundant-lifetimes.stderr new file mode 100644 index 00000000000..2d8fc433b24 --- /dev/null +++ b/tests/ui/regions/transitively-redundant-lifetimes.stderr @@ -0,0 +1,47 @@ +error: unnecessary lifetime parameter `'b` + --> $DIR/transitively-redundant-lifetimes.rs:3:10 + | +LL | fn a<'a, 'b>(x: &'a &'b &'a ()) {} + | ^^ + | + = note: you can use the `'a` lifetime directly, in place of `'b` +note: the lint level is defined here + --> $DIR/transitively-redundant-lifetimes.rs:1:9 + | +LL | #![deny(redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unnecessary lifetime parameter `'b` + --> $DIR/transitively-redundant-lifetimes.rs:5:14 + | +LL | fn b<'a: 'b, 'b: 'a>() {} + | ^^ + | + = note: you can use the `'a` lifetime directly, in place of `'b` + +error: unnecessary lifetime parameter `'a` + --> $DIR/transitively-redundant-lifetimes.rs:8:6 + | +LL | fn c<'a>(_: Foo<&'a ()>) {} + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` + +error: unnecessary lifetime parameter `'a` + --> $DIR/transitively-redundant-lifetimes.rs:18:6 + | +LL | impl<'a: 'static> Tr<'a> for () {} + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` + +error: unnecessary lifetime parameter `'b` + --> $DIR/transitively-redundant-lifetimes.rs:12:10 + | +LL | fn d<'b: 'a>(&'b self) {} + | ^^ + | + = note: you can use the `'a` lifetime directly, in place of `'b` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/resolve/incorrect-self-res.rs b/tests/ui/resolve/incorrect-self-res.rs new file mode 100644 index 00000000000..ca97e698994 --- /dev/null +++ b/tests/ui/resolve/incorrect-self-res.rs @@ -0,0 +1,17 @@ +fn module() { + fn test(&mut self) { + //~^ ERROR `self` parameter is only allowed in associated functions + } + mod Self {} + //~^ ERROR expected identifier, found keyword `Self` +} + +fn trait_() { + fn test(&mut self) { + //~^ ERROR `self` parameter is only allowed in associated functions + } + trait Self {} + //~^ ERROR expected identifier, found keyword `Self` +} + +fn main() {} diff --git a/tests/ui/resolve/incorrect-self-res.stderr b/tests/ui/resolve/incorrect-self-res.stderr new file mode 100644 index 00000000000..406bfb98011 --- /dev/null +++ b/tests/ui/resolve/incorrect-self-res.stderr @@ -0,0 +1,30 @@ +error: expected identifier, found keyword `Self` + --> $DIR/incorrect-self-res.rs:5:9 + | +LL | mod Self {} + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `Self` + --> $DIR/incorrect-self-res.rs:13:11 + | +LL | trait Self {} + | ^^^^ expected identifier, found keyword + +error: `self` parameter is only allowed in associated functions + --> $DIR/incorrect-self-res.rs:2:13 + | +LL | fn test(&mut self) { + | ^^^^^^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error: `self` parameter is only allowed in associated functions + --> $DIR/incorrect-self-res.rs:10:13 + | +LL | fn test(&mut self) { + | ^^^^^^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error: aborting due to 4 previous errors + diff --git a/tests/ui/ret-non-nil.stderr b/tests/ui/ret-non-nil.stderr index 17567c6016a..802900e61a3 100644 --- a/tests/ui/ret-non-nil.stderr +++ b/tests/ui/ret-non-nil.stderr @@ -5,6 +5,11 @@ LL | fn g() -> isize { return; } | ----- ^^^^^^ return type is not `()` | | | expected `isize` because of this return type + | +help: give the `return` a value of the expected type + | +LL | fn g() -> isize { return 42; } + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/return/suggest-a-value.rs b/tests/ui/return/suggest-a-value.rs new file mode 100644 index 00000000000..7d23c0c44b7 --- /dev/null +++ b/tests/ui/return/suggest-a-value.rs @@ -0,0 +1,6 @@ +fn test() -> (i32,) { + return; + //~^ ERROR `return;` in a function whose return type is not `()` +} + +fn main() {} diff --git a/tests/ui/return/suggest-a-value.stderr b/tests/ui/return/suggest-a-value.stderr new file mode 100644 index 00000000000..573ade7b712 --- /dev/null +++ b/tests/ui/return/suggest-a-value.stderr @@ -0,0 +1,16 @@ +error[E0069]: `return;` in a function whose return type is not `()` + --> $DIR/suggest-a-value.rs:2:5 + | +LL | fn test() -> (i32,) { + | ------ expected `(i32,)` because of this return type +LL | return; + | ^^^^^^ return type is not `()` + | +help: give the `return` a value of the expected type + | +LL | return (42,); + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0069`. diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr index a749361bf30..0ab70c5ae8a 100644 --- a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr @@ -5,6 +5,10 @@ LL | VecWrapper::A(v) if { drop(v); false } => 1, | ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | VecWrapper::A(v) if { drop(v.clone()); false } => 1, + | ++++++++ error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-across-arms.rs:15:51 @@ -13,6 +17,10 @@ LL | VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1, | ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | VecWrapper::A(v) if let Some(()) = { drop(v.clone()); None } => 1, + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr index 9285492b224..c261f994283 100644 --- a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr @@ -5,6 +5,10 @@ LL | A { a: v } if { drop(v); true } => v, | ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | A { a: v } if { drop(v.clone()); true } => v, + | ++++++++ error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45 @@ -13,6 +17,10 @@ LL | A { a: v } if let Some(()) = { drop(v); Some(()) } => v, | ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | A { a: v } if let Some(()) = { drop(v.clone()); Some(()) } => v, + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs index 2ae8eb9c56d..ef970ebd14b 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -6,7 +6,7 @@ //@ run-pass //@ compile-flags: -Z unleash-the-miri-inside-of-you -#![feature(core_intrinsics, const_caller_location)] +#![feature(core_intrinsics)] type L = &'static std::panic::Location<'static>; diff --git a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs index 2c699437c83..c4e1f3ae48a 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs @@ -2,15 +2,13 @@ //@ revisions: default mir-opt //@[mir-opt] compile-flags: -Zmir-opt-level=4 -#![feature(const_caller_location)] - use std::panic::Location; const LOCATION: &Location = Location::caller(); const TRACKED: &Location = tracked(); #[track_caller] -const fn tracked() -> &'static Location <'static> { +const fn tracked() -> &'static Location<'static> { Location::caller() } @@ -26,18 +24,18 @@ const fn contained() -> &'static Location<'static> { fn main() { assert_eq!(LOCATION.file(), file!()); - assert_eq!(LOCATION.line(), 9); + assert_eq!(LOCATION.line(), 7); assert_eq!(LOCATION.column(), 29); assert_eq!(TRACKED.file(), file!()); - assert_eq!(TRACKED.line(), 11); + assert_eq!(TRACKED.line(), 9); assert_eq!(TRACKED.column(), 28); assert_eq!(NESTED.file(), file!()); - assert_eq!(NESTED.line(), 19); + assert_eq!(NESTED.line(), 17); assert_eq!(NESTED.column(), 5); assert_eq!(CONTAINED.file(), file!()); - assert_eq!(CONTAINED.line(), 24); + assert_eq!(CONTAINED.line(), 22); assert_eq!(CONTAINED.column(), 5); } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs index 17817a460d7..cd5fa609947 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs @@ -1,7 +1,7 @@ //@ known-bug: #110395 #![feature(const_trait_impl)] #![feature(const_mut_refs)] -#![cfg_attr(precise, feature(const_precise_live_drops))] +// #![cfg_attr(precise, feature(const_precise_live_drops))] use std::marker::{Destruct, PhantomData}; diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed index 75b3918be1d..f4506dd929e 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed @@ -1,6 +1,6 @@ //@ aux-build:edition-lint-paths.rs //@ run-rustfix -//@ compile-flags:--extern edition_lint_paths --cfg blandiloquence +//@ compile-flags:--extern edition_lint_paths //@ edition:2018 #![deny(rust_2018_idioms)] diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs index eff03c6fbe6..4f1cb71dc51 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs @@ -1,6 +1,6 @@ //@ aux-build:edition-lint-paths.rs //@ run-rustfix -//@ compile-flags:--extern edition_lint_paths --cfg blandiloquence +//@ compile-flags:--extern edition_lint_paths //@ edition:2018 #![deny(rust_2018_idioms)] @@ -8,7 +8,7 @@ // The suggestion span should include the attribute. -#[cfg(blandiloquence)] //~ HELP remove it +#[cfg(not(FALSE))] //~ HELP remove it extern crate edition_lint_paths; //~^ ERROR unused extern crate diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr index 801d16af82d..038a9dd967b 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr @@ -1,7 +1,7 @@ error: unused extern crate --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:12:1 | -LL | / #[cfg(blandiloquence)] +LL | / #[cfg(not(FALSE))] LL | | extern crate edition_lint_paths; | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | |________________________________| diff --git a/tests/ui/sanitizer/cfg-kasan.rs b/tests/ui/sanitizer/cfg-kasan.rs index 394bf216581..491eaf3acc1 100644 --- a/tests/ui/sanitizer/cfg-kasan.rs +++ b/tests/ui/sanitizer/cfg-kasan.rs @@ -2,7 +2,7 @@ // the `#[cfg(sanitize = "address")]` attribute is configured. //@ check-pass -//@ compile-flags: -Zsanitizer=kernel-address --cfg kernel_address +//@ compile-flags: -Zsanitizer=kernel-address //@ revisions: aarch64 riscv64imac riscv64gc x86_64 //@[aarch64] compile-flags: --target aarch64-unknown-none //@[aarch64] needs-llvm-components: aarch64 @@ -22,5 +22,5 @@ trait Sized {} const _: fn() -> () = main; -#[cfg(all(sanitize = "address", kernel_address))] +#[cfg(sanitize = "address")] fn main() {} diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-fn-ptr.rs index 8f79de11748..505b4b8e7f0 100644 --- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-fn-ptr.rs @@ -1,4 +1,4 @@ -// Verifies that casting a method to a function pointer works. +// Verifies that casting to a function pointer works. //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work @@ -46,6 +46,8 @@ impl Trait1 for Type1 { fn foo(&self) {} } +fn foo<T>(_: &T) {} + fn main() { let type1 = Type1 {}; let f = <Type1 as Trait1>::foo; @@ -53,5 +55,7 @@ fn main() { // Check again with different optimization barriers S2 { f: <S as Foo>::foo }.foo(&S); // Check mismatched #[track_caller] - S2 { f: <S as Foo>::bar }.foo(&S) + S2 { f: <S as Foo>::bar }.foo(&S); + // Check non-method functions + S2 { f: foo }.foo(&S) } diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs new file mode 100644 index 00000000000..fde7b5451b6 --- /dev/null +++ b/tests/ui/sanitizer/kcfi-mangling.rs @@ -0,0 +1,30 @@ +// Check KCFI extra mangling works correctly on v0 + +//@ needs-sanitizer-kcfi +//@ no-prefer-dynamic +//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0 +//@ build-pass + +trait Foo { + fn foo(&self); +} + +struct Bar; +impl Foo for Bar { + fn foo(&self) {} +} + +struct Baz; +impl Foo for Baz { + #[track_caller] + fn foo(&self) {} +} + +fn main() { + // Produces `ReifyShim(_, ReifyReason::FnPtr)` + let f: fn(&Bar) = Bar::foo; + f(&Bar); + // Produces `ReifyShim(_, ReifyReason::Vtable)` + let v: &dyn Foo = &Baz as _; + v.foo(); +} diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 29a606c4f01..f37dc320fa3 100644 --- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -43,6 +43,11 @@ LL | f(Box::new(|a| { LL | LL | foo(f); | ^ move occurs because `f` has type `{closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58}`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | foo(f.clone()); + | ++++++++ error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 @@ -57,6 +62,11 @@ LL | f(Box::new(|a| { LL | LL | foo(f); | - move occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | f.clone()(Box::new(|a| { + | ++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/span/send-is-not-static-std-sync.stderr b/tests/ui/span/send-is-not-static-std-sync.stderr index 46534b39168..50b8ffe0114 100644 --- a/tests/ui/span/send-is-not-static-std-sync.stderr +++ b/tests/ui/span/send-is-not-static-std-sync.stderr @@ -11,6 +11,12 @@ LL | drop(y); ... LL | *lock.lock().unwrap() = &z; | ---- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *lock.lock().unwrap() = &*y; +LL + *lock.lock().unwrap() = y.clone(); + | error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:16:33 @@ -38,6 +44,12 @@ LL | drop(y); ... LL | *lock.write().unwrap() = &z; | ---- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *lock.write().unwrap() = &*y; +LL + *lock.write().unwrap() = y.clone(); + | error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:30:34 @@ -65,6 +77,12 @@ LL | drop(y); ... LL | tx.send(&z).unwrap(); | -- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - tx.send(&*y); +LL + tx.send(y.clone()); + | error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:46:17 diff --git a/tests/ui/std/windows-bat-args.rs b/tests/ui/std/windows-bat-args.rs new file mode 100644 index 00000000000..a9b6252b78c --- /dev/null +++ b/tests/ui/std/windows-bat-args.rs @@ -0,0 +1,90 @@ +//@ only-windows +//@ run-pass +//@ run-flags:--parent-process + +use std::env; +use std::io::ErrorKind::{self, InvalidInput}; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn main() { + if env::args().nth(1).as_deref() == Some("--parent-process") { + parent(); + } else { + child(); + } +} + +fn child() { + if env::args().len() == 1 { + panic!("something went wrong :/"); + } + for arg in env::args().skip(1) { + print!("{arg}\0"); + } +} + +fn parent() { + let mut bat = PathBuf::from(file!()); + bat.set_file_name("windows-bat-args1.bat"); + let bat1 = String::from(bat.to_str().unwrap()); + bat.set_file_name("windows-bat-args2.bat"); + let bat2 = String::from(bat.to_str().unwrap()); + bat.set_file_name("windows-bat-args3.bat"); + let bat3 = String::from(bat.to_str().unwrap()); + let bat = [bat1.as_str(), bat2.as_str(), bat3.as_str()]; + + check_args(&bat, &["a", "b"]).unwrap(); + check_args(&bat, &["c is for cat", "d is for dog"]).unwrap(); + check_args(&bat, &["\"", " \""]).unwrap(); + check_args(&bat, &["\\", "\\"]).unwrap(); + check_args(&bat, &[">file.txt"]).unwrap(); + check_args(&bat, &["whoami.exe"]).unwrap(); + check_args(&bat, &["&a.exe"]).unwrap(); + check_args(&bat, &["&echo hello "]).unwrap(); + check_args(&bat, &["&echo hello", "&whoami", ">file.txt"]).unwrap(); + check_args(&bat, &["!TMP!"]).unwrap(); + check_args(&bat, &["key=value"]).unwrap(); + check_args(&bat, &["\"key=value\""]).unwrap(); + check_args(&bat, &["key = value"]).unwrap(); + check_args(&bat, &["key=[\"value\"]"]).unwrap(); + check_args(&bat, &["", "a=b"]).unwrap(); + check_args(&bat, &["key=\"foo bar\""]).unwrap(); + check_args(&bat, &["key=[\"my_value]"]).unwrap(); + check_args(&bat, &["key=[\"my_value\",\"other-value\"]"]).unwrap(); + check_args(&bat, &["key\\=value"]).unwrap(); + check_args(&bat, &["key=\"&whoami\""]).unwrap(); + check_args(&bat, &["key=\"value\"=5"]).unwrap(); + check_args(&bat, &["key=[\">file.txt\"]"]).unwrap(); + assert_eq!(check_args(&bat, &["\n"]), Err(InvalidInput)); + assert_eq!(check_args(&bat, &["\r"]), Err(InvalidInput)); + check_args(&bat, &["%hello"]).unwrap(); + check_args(&bat, &["%PATH%"]).unwrap(); + check_args(&bat, &["%%cd:~,%"]).unwrap(); + check_args(&bat, &["%PATH%PATH%"]).unwrap(); + check_args(&bat, &["\">file.txt"]).unwrap(); + check_args(&bat, &["abc\"&echo hello"]).unwrap(); + check_args(&bat, &["123\">file.txt"]).unwrap(); + check_args(&bat, &["\"&echo hello&whoami.exe"]).unwrap(); + check_args(&bat, &[r#"hello^"world"#, "hello &echo oh no >file.txt"]).unwrap(); +} + +// Check if the arguments roundtrip through a bat file and back into a Rust process. +// Our Rust process outptuts the arguments as null terminated strings. +#[track_caller] +fn check_args(bats: &[&str], args: &[&str]) -> Result<(), ErrorKind> { + for bat in bats { + let output = Command::new(&bat).args(args).output().map_err(|e| e.kind())?; + assert!(output.status.success()); + let child_args = String::from_utf8(output.stdout).unwrap(); + let mut child_args: Vec<&str> = + child_args.strip_suffix('\0').unwrap().split('\0').collect(); + // args3.bat can append spurious empty arguments, so trim them here. + child_args.truncate( + child_args.iter().rposition(|s| !s.is_empty()).unwrap_or(child_args.len() - 1) + 1, + ); + assert_eq!(&child_args, &args); + assert!(!Path::new("file.txt").exists()); + } + Ok(()) +} diff --git a/tests/ui/std/windows-bat-args1.bat b/tests/ui/std/windows-bat-args1.bat new file mode 100644 index 00000000000..edd36bd5530 --- /dev/null +++ b/tests/ui/std/windows-bat-args1.bat @@ -0,0 +1 @@ +@a.exe %* diff --git a/tests/ui/std/windows-bat-args2.bat b/tests/ui/std/windows-bat-args2.bat new file mode 100644 index 00000000000..8d5a7dd8a9e --- /dev/null +++ b/tests/ui/std/windows-bat-args2.bat @@ -0,0 +1 @@ +@a.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/tests/ui/std/windows-bat-args3.bat b/tests/ui/std/windows-bat-args3.bat new file mode 100644 index 00000000000..7fe360a6d36 --- /dev/null +++ b/tests/ui/std/windows-bat-args3.bat @@ -0,0 +1 @@ +@a.exe "%~1" "%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9" diff --git a/tests/ui/stmt_expr_attrs_no_feature.rs b/tests/ui/stmt_expr_attrs_no_feature.rs index 627c97da008..a160a9bb082 100644 --- a/tests/ui/stmt_expr_attrs_no_feature.rs +++ b/tests/ui/stmt_expr_attrs_no_feature.rs @@ -25,25 +25,25 @@ fn main() { // Check that cfg works right -#[cfg(unset)] +#[cfg(FALSE)] fn c() { #[rustc_dummy] 5; } -#[cfg(not(unset))] +#[cfg(not(FALSE))] fn j() { #[rustc_dummy] 5; } -#[cfg_attr(not(unset), cfg(unset))] +#[cfg_attr(not(FALSE), cfg(FALSE))] fn d() { #[rustc_dummy] 8; } -#[cfg_attr(not(unset), cfg(not(unset)))] +#[cfg_attr(not(FALSE), cfg(not(FALSE)))] fn i() { #[rustc_dummy] 8; @@ -57,25 +57,25 @@ macro_rules! item_mac { #[rustc_dummy] 42; - #[cfg(unset)] + #[cfg(FALSE)] fn f() { #[rustc_dummy] 5; } - #[cfg(not(unset))] + #[cfg(not(FALSE))] fn k() { #[rustc_dummy] 5; } - #[cfg_attr(not(unset), cfg(unset))] + #[cfg_attr(not(FALSE), cfg(FALSE))] fn g() { #[rustc_dummy] 8; } - #[cfg_attr(not(unset), cfg(not(unset)))] + #[cfg_attr(not(FALSE), cfg(not(FALSE)))] fn h() { #[rustc_dummy] 8; @@ -90,42 +90,42 @@ item_mac!(e); // check that the gate visitor works right: extern "C" { - #[cfg(unset)] + #[cfg(FALSE)] fn x(a: [u8; #[rustc_dummy] 5]); fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental } struct Foo; impl Foo { - #[cfg(unset)] + #[cfg(FALSE)] const X: u8 = #[rustc_dummy] 5; const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental } trait Bar { - #[cfg(unset)] + #[cfg(FALSE)] const X: [u8; #[rustc_dummy] 5]; const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental } struct Joyce { - #[cfg(unset)] + #[cfg(FALSE)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } struct Walky( - #[cfg(unset)] [u8; #[rustc_dummy] 5], + #[cfg(FALSE)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ); enum Mike { Happy( - #[cfg(unset)] [u8; #[rustc_dummy] 5], + #[cfg(FALSE)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ), Angry { - #[cfg(unset)] + #[cfg(FALSE)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } @@ -133,7 +133,7 @@ enum Mike { fn pat() { match 5 { - #[cfg(unset)] + #[cfg(FALSE)] 5 => #[rustc_dummy] (), 6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental _ => (), diff --git a/tests/ui/suggestions/borrow-for-loop-head.stderr b/tests/ui/suggestions/borrow-for-loop-head.stderr index 0f179438a12..a8de9986c31 100644 --- a/tests/ui/suggestions/borrow-for-loop-head.stderr +++ b/tests/ui/suggestions/borrow-for-loop-head.stderr @@ -7,6 +7,12 @@ LL | for i in &a { | -- borrow of `a` occurs here LL | for j in a { | ^ move out of `a` occurs here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - for i in &a { +LL + for i in a.clone() { + | error[E0382]: use of moved value: `a` --> $DIR/borrow-for-loop-head.rs:4:18 diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index b27d9aef066..bfcc2307fd7 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll Vec::<T>::with_capacity Vec::<T>::try_with_capacity Vec::<T>::from_raw_parts - and 4 others + and 6 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: the function `contains` is implemented on `[_]` | diff --git a/tests/ui/suggestions/for-i-in-vec.fixed b/tests/ui/suggestions/for-i-in-vec.fixed index f266e80bcfa..17ae6fb5ab7 100644 --- a/tests/ui/suggestions/for-i-in-vec.fixed +++ b/tests/ui/suggestions/for-i-in-vec.fixed @@ -8,9 +8,9 @@ struct Foo { impl Foo { fn bar(&self) { - for _ in &self.v { //~ ERROR cannot move out of `self.v` which is behind a shared reference + for _ in &self.v.clone() { //~ ERROR cannot move out of `self.v` which is behind a shared reference } - for _ in &self.h { //~ ERROR cannot move out of `self.h` which is behind a shared reference + for _ in &self.h.clone() { //~ ERROR cannot move out of `self.h` which is behind a shared reference } } } @@ -18,7 +18,7 @@ impl Foo { const LOADERS: &Vec<&'static u8> = &Vec::new(); pub fn break_code() -> Option<&'static u8> { - for loader in &*LOADERS { //~ ERROR cannot move out of a shared reference + for loader in &LOADERS.clone() { //~ ERROR cannot move out of a shared reference return Some(loader); } None diff --git a/tests/ui/suggestions/for-i-in-vec.stderr b/tests/ui/suggestions/for-i-in-vec.stderr index c5b81e6b871..64eb4f8bd23 100644 --- a/tests/ui/suggestions/for-i-in-vec.stderr +++ b/tests/ui/suggestions/for-i-in-vec.stderr @@ -13,6 +13,10 @@ help: consider iterating over a slice of the `Vec<u32>`'s content to avoid movin | LL | for _ in &self.v { | + +help: consider cloning the value if the performance cost is acceptable + | +LL | for _ in self.v.clone() { + | ++++++++ error[E0507]: cannot move out of `self.h` which is behind a shared reference --> $DIR/for-i-in-vec.rs:13:18 @@ -27,6 +31,10 @@ help: consider iterating over a slice of the `HashMap<i32, i32>`'s content to av | LL | for _ in &self.h { | + +help: consider cloning the value if the performance cost is acceptable + | +LL | for _ in self.h.clone() { + | ++++++++ error[E0507]: cannot move out of a shared reference --> $DIR/for-i-in-vec.rs:21:19 @@ -43,6 +51,11 @@ help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid movin | LL | for loader in &*LOADERS { | + +help: consider cloning the value if the performance cost is acceptable + | +LL - for loader in *LOADERS { +LL + for loader in LOADERS.clone() { + | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/issue-68049-1.stderr b/tests/ui/suggestions/issue-68049-1.stderr index 760f83d548f..4e683b75c48 100644 --- a/tests/ui/suggestions/issue-68049-1.stderr +++ b/tests/ui/suggestions/issue-68049-1.stderr @@ -1,6 +1,8 @@ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference --> $DIR/issue-68049-1.rs:7:9 | +LL | unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + | ----- this is an immutable reference LL | self.0 += 1; | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written diff --git a/tests/ui/suggestions/issue-68049-2.rs b/tests/ui/suggestions/issue-68049-2.rs index 1c3430c14e9..496a1299dcf 100644 --- a/tests/ui/suggestions/issue-68049-2.rs +++ b/tests/ui/suggestions/issue-68049-2.rs @@ -1,11 +1,11 @@ trait Hello { - fn example(&self, input: &i32); // should suggest here + fn example(&self, input: &i32); } struct Test1(i32); impl Hello for Test1 { - fn example(&self, input: &i32) { // should not suggest here + fn example(&self, input: &i32) { *input = self.0; //~ ERROR cannot assign } } @@ -13,7 +13,7 @@ impl Hello for Test1 { struct Test2(i32); impl Hello for Test2 { - fn example(&self, input: &i32) { // should not suggest here + fn example(&self, input: &i32) { self.0 += *input; //~ ERROR cannot assign } } diff --git a/tests/ui/suggestions/issue-68049-2.stderr b/tests/ui/suggestions/issue-68049-2.stderr index 6f3c78443f8..449ecabeb7f 100644 --- a/tests/ui/suggestions/issue-68049-2.stderr +++ b/tests/ui/suggestions/issue-68049-2.stderr @@ -4,9 +4,9 @@ error[E0594]: cannot assign to `*input`, which is behind a `&` reference LL | *input = self.0; | ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written | -help: consider changing this to be a mutable reference +help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition | -LL | fn example(&self, input: &mut i32) { // should not suggest here +LL | fn example(&self, input: &mut i32) { | +++ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference @@ -15,10 +15,14 @@ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference LL | self.0 += *input; | ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written | -help: consider changing this to be a mutable reference +help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition + | +LL ~ fn example(&mut self, input: &i32); +LL | } + ... +LL | impl Hello for Test2 { +LL ~ fn example(&mut self, input: &i32) { | -LL | fn example(&mut self, input: &i32); // should suggest here - | ~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed index fbed486cef7..4a5a9483c20 100644 --- a/tests/ui/suggestions/option-content-move.fixed +++ b/tests/ui/suggestions/option-content-move.fixed @@ -7,7 +7,7 @@ impl LipogramCorpora { pub fn validate_all(&mut self) -> Result<(), char> { for selection in &self.selections { if selection.1.is_some() { - if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { + if <Option<String> as Clone>::clone(&selection.1.clone()).unwrap().contains(selection.0) { //~^ ERROR cannot move out of `selection.1` return Err(selection.0); } @@ -25,7 +25,7 @@ impl LipogramCorpora2 { pub fn validate_all(&mut self) -> Result<(), char> { for selection in &self.selections { if selection.1.is_ok() { - if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { + if <Result<String, String> as Clone>::clone(&selection.1.clone()).unwrap().contains(selection.0) { //~^ ERROR cannot move out of `selection.1` return Err(selection.0); } diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr index e5de150275d..a382a04344a 100644 --- a/tests/ui/suggestions/option-content-move.stderr +++ b/tests/ui/suggestions/option-content-move.stderr @@ -13,6 +13,10 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { | ++++++++++++++++++++++++++++++++++ + +help: consider cloning the value if the performance cost is acceptable + | +LL | if selection.1.clone().unwrap().contains(selection.0) { + | ++++++++ error[E0507]: cannot move out of `selection.1` which is behind a shared reference --> $DIR/option-content-move.rs:28:20 @@ -29,6 +33,10 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { | ++++++++++++++++++++++++++++++++++++++++++ + +help: consider cloning the value if the performance cost is acceptable + | +LL | if selection.1.clone().unwrap().contains(selection.0) { + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/option-to-bool.rs b/tests/ui/suggestions/option-to-bool.rs index 2a1823b15f5..bbc5d1d71cb 100644 --- a/tests/ui/suggestions/option-to-bool.rs +++ b/tests/ui/suggestions/option-to-bool.rs @@ -1,5 +1,3 @@ -#![cfg_attr(let_chains, feature(let_chains))] - fn foo(x: Option<i32>) { if true && x {} //~^ ERROR mismatched types diff --git a/tests/ui/suggestions/option-to-bool.stderr b/tests/ui/suggestions/option-to-bool.stderr index e16d829ca7a..ab97eae6c5c 100644 --- a/tests/ui/suggestions/option-to-bool.stderr +++ b/tests/ui/suggestions/option-to-bool.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/option-to-bool.rs:4:16 + --> $DIR/option-to-bool.rs:2:16 | LL | if true && x {} | ---- ^ expected `bool`, found `Option<i32>` diff --git a/tests/ui/suggestions/return-closures.stderr b/tests/ui/suggestions/return-closures.stderr index 97c13200ac3..ef1f50b8a6c 100644 --- a/tests/ui/suggestions/return-closures.stderr +++ b/tests/ui/suggestions/return-closures.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/return-closures.rs:3:5 | LL | fn foo() { - | - help: try adding a return type: `-> impl for<'a> Fn(&'a i32) -> i32` + | - help: try adding a return type: `-> impl FnOnce(&i32) -> i32` LL | LL | |x: &i32| 1i32 | ^^^^^^^^^^^^^^ expected `()`, found closure diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index c1cbefac828..6ce0ae09195 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE) +error: symbol-name(_ZN5basic4main17had874e876c8b1028E) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h6fc0c8d27b1a289f) +error: demangling(basic::main::had874e876c8b1028) --> $DIR/basic.rs:8:1 | 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 7dd68e6e3a8..cc4eec470fb 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$3foo17hab58a402db4ebf3aE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17haf0d0ad2255e29c6E) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hab58a402db4ebf3a) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::haf0d0ad2255e29c6) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr index 54b1ea2764a..436f9ecf93d 100644 --- a/tests/ui/track-diagnostics/track.stderr +++ b/tests/ui/track-diagnostics/track.stderr @@ -30,6 +30,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md +note: please make sure that you have updated to the latest nightly + note: rustc $VERSION running on $TARGET note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics diff --git a/tests/ui/traits/copy-guessing.rs b/tests/ui/traits/copy-guessing.rs index af25010e3bd..0ffa8249789 100644 --- a/tests/ui/traits/copy-guessing.rs +++ b/tests/ui/traits/copy-guessing.rs @@ -18,7 +18,7 @@ fn assert_impls_fn<R,T: Fn()->R>(_: &T){} fn main() { let n = None; - //~^ ERROR type annotations needed for `Option<T>` + //~^ ERROR type annotations needed for `Option<_>` let e = S(&n); let f = || { // S being copy is critical for this to work diff --git a/tests/ui/traits/copy-guessing.stderr b/tests/ui/traits/copy-guessing.stderr index 750140c017c..cae91579ee0 100644 --- a/tests/ui/traits/copy-guessing.stderr +++ b/tests/ui/traits/copy-guessing.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Option<T>` +error[E0282]: type annotations needed for `Option<_>` --> $DIR/copy-guessing.rs:20:9 | LL | let n = None; diff --git a/tests/ui/issues/issue-2611-3.rs b/tests/ui/traits/issue-2611-3.rs index c95ebae33fa..c95ebae33fa 100644 --- a/tests/ui/issues/issue-2611-3.rs +++ b/tests/ui/traits/issue-2611-3.rs diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index 5be8d2f4b32..0f4b3c3c877 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -55,7 +55,7 @@ help: try using a fully qualified path to specify the expected types LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect(); | +++++++++++++++++++++++ ~ -error[E0283]: type annotations needed for `Box<T>` +error[E0283]: type annotations needed for `Box<_>` --> $DIR/issue-77982.rs:37:9 | LL | let _ = ().foo(); @@ -73,7 +73,7 @@ help: consider giving this pattern a type, where the type for type parameter `T` LL | let _: Box<T> = ().foo(); | ++++++++ -error[E0283]: type annotations needed for `Box<T>` +error[E0283]: type annotations needed for `Box<_>` --> $DIR/issue-77982.rs:41:9 | LL | let _ = (&()).bar(); diff --git a/tests/ui/traits/make-sure-to-filter-projections-by-def-id.rs b/tests/ui/traits/make-sure-to-filter-projections-by-def-id.rs new file mode 100644 index 00000000000..27a3aad733c --- /dev/null +++ b/tests/ui/traits/make-sure-to-filter-projections-by-def-id.rs @@ -0,0 +1,38 @@ +//@ check-pass + +#![recursion_limit = "1024"] +// Really high recursion limit ^ + +// Test that ensures we're filtering projections by def id before matching +// them in `match_projection_projections`. + +use std::ops::{Add, Sub}; + +pub trait Scalar {} + +pub trait VectorCommon: Sized { + type T: Scalar; +} + +pub trait VectorOpsByValue<Rhs = Self, Output = Self>: + VectorCommon + Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> +{ +} + +pub trait VectorView<'a>: + VectorOpsByValue<Self, Self::Owned> + VectorOpsByValue<Self::Owned, Self::Owned> +{ + type Owned; +} + +pub trait Vector: VectorOpsByValue<Self> + for<'a> VectorOpsByValue<Self::View<'a>> { + type View<'a>: VectorView<'a, T = Self::T, Owned = Self> + where + Self: 'a; +} + +pub trait MatrixCommon { + type V: Vector; +} + +fn main() {} diff --git a/tests/ui/traits/overflow-computing-ambiguity.rs b/tests/ui/traits/overflow-computing-ambiguity.rs new file mode 100644 index 00000000000..b8f11efeda2 --- /dev/null +++ b/tests/ui/traits/overflow-computing-ambiguity.rs @@ -0,0 +1,14 @@ +trait Hello {} + +struct Foo<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Hello for Foo<'a, &'a T> where Foo<'a, T>: Hello {} + +impl Hello for Foo<'static, i32> {} + +fn hello<T: ?Sized + Hello>() {} + +fn main() { + hello(); + //~^ ERROR type annotations needed +} diff --git a/tests/ui/traits/overflow-computing-ambiguity.stderr b/tests/ui/traits/overflow-computing-ambiguity.stderr new file mode 100644 index 00000000000..a2e255865bf --- /dev/null +++ b/tests/ui/traits/overflow-computing-ambiguity.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed + --> $DIR/overflow-computing-ambiguity.rs:12:5 + | +LL | hello(); + | ^^^^^ cannot infer type of the type parameter `T` declared on the function `hello` + | + = note: cannot satisfy `_: Hello` + = help: the following types implement trait `Hello`: + Foo<'a, &'a T> + Foo<'static, i32> +note: required by a bound in `hello` + --> $DIR/overflow-computing-ambiguity.rs:9:22 + | +LL | fn hello<T: ?Sized + Hello>() {} + | ^^^^^ required by this bound in `hello` +help: consider specifying the generic argument + | +LL | hello::<T>(); + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs b/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs new file mode 100644 index 00000000000..4e8c19d600d --- /dev/null +++ b/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs @@ -0,0 +1,244 @@ +// This is a non-regression test for issues #108721 and its duplicate #123275 (hopefully, because +// the test is still convoluted and the ICE is fiddly). +// +// `pred_known_to_hold_modulo_regions` prevented "unexpected unsized tail" ICEs with warp/hyper but +// was unknowingly removed in #120463. + +//@ build-pass: the ICE happened in codegen + +use std::future::Future; +trait TryFuture: Future { + type Ok; +} +impl<F, T> TryFuture for F +where + F: ?Sized + Future<Output = Option<T>>, +{ + type Ok = T; +} +trait Executor {} +struct Exec {} +trait HttpBody { + type Data; +} +trait ConnStreamExec<F> {} +impl<F> ConnStreamExec<F> for Exec where H2Stream<F>: Send {} +impl<E, F> ConnStreamExec<F> for E where E: Executor {} +struct H2Stream<F> { + _fut: F, +} +trait NewSvcExec<S, E, W: Watcher<S, E>> { + fn execute_new_svc(&mut self, _fut: NewSvcTask<S, E, W>) { + unimplemented!() + } +} +impl<S, E, W> NewSvcExec<S, E, W> for Exec where W: Watcher<S, E> {} +trait Watcher<S, E> { + type Future; +} +struct NoopWatcher; +impl<S, E> Watcher<S, E> for NoopWatcher +where + S: HttpService, + E: ConnStreamExec<S::Future>, +{ + type Future = Option<<<S as HttpService>::ResBody as HttpBody>::Data>; +} +trait Service<Request> { + type Response; + type Future; +} +trait HttpService { + type ResBody: HttpBody; + type Future; +} +struct Body {} +impl HttpBody for Body { + type Data = String; +} +impl<S> HttpService for S +where + S: Service<(), Response = ()>, +{ + type ResBody = Body; + type Future = S::Future; +} +trait MakeServiceRef<Target> { + type ResBody; + type Service: HttpService<ResBody = Self::ResBody>; +} +impl<T, Target, S, F> MakeServiceRef<Target> for T +where + T: for<'a> Service<&'a Target, Response = S, Future = F>, + S: HttpService, +{ + type Service = S; + type ResBody = S::ResBody; +} +fn make_service_fn<F, Target, Ret>(_f: F) -> MakeServiceFn<F> +where + F: FnMut(&Target) -> Ret, + Ret: Future, +{ + unimplemented!() +} +struct MakeServiceFn<F> { + _func: F, +} +impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F> +where + F: FnMut(&Target) -> Ret, + Ret: Future<Output = Option<Svc>>, +{ + type Response = Svc; + type Future = Option<()>; +} +struct AddrIncoming {} +struct Server<I, S, E> { + _incoming: I, + _make_service: S, + _protocol: E, +} +impl<I, S, E, B> Server<I, S, E> +where + S: MakeServiceRef<(), ResBody = B>, + B: HttpBody, + E: ConnStreamExec<<S::Service as HttpService>::Future>, + E: NewSvcExec<S::Service, E, NoopWatcher>, +{ + fn serve(&mut self) { + let fut = NewSvcTask::new(); + self._protocol.execute_new_svc(fut); + } +} +fn serve<S>(_make_service: S) -> Server<AddrIncoming, S, Exec> { + unimplemented!() +} +struct NewSvcTask<S, E, W: Watcher<S, E>> { + _state: State<S, E, W>, +} +struct State<S, E, W: Watcher<S, E>> { + _fut: W::Future, +} +impl<S, E, W: Watcher<S, E>> NewSvcTask<S, E, W> { + fn new() -> Self { + unimplemented!() + } +} +trait Filter { + type Extract; + type Future; + fn map<F>(self, _fun: F) -> MapFilter<Self, F> + where + Self: Sized, + { + unimplemented!() + } + fn wrap_with<W>(self, _wrapper: W) -> W::Wrapped + where + Self: Sized, + W: Wrap<Self>, + { + unimplemented!() + } +} +fn service<F>(_filter: F) -> FilteredService<F> +where + F: Filter, +{ + unimplemented!() +} +struct FilteredService<F> { + _filter: F, +} +impl<F> Service<()> for FilteredService<F> +where + F: Filter, +{ + type Response = (); + type Future = FilteredFuture<F::Future>; +} +struct FilteredFuture<F> { + _fut: F, +} +struct MapFilter<T, F> { + _filter: T, + _func: F, +} +impl<T, F> Filter for MapFilter<T, F> +where + T: Filter, + F: Func<T::Extract>, +{ + type Extract = F::Output; + type Future = MapFilterFuture<T, F>; +} +struct MapFilterFuture<T: Filter, F> { + _extract: T::Future, + _func: F, +} +trait Wrap<F> { + type Wrapped; +} +fn make_filter_fn<F, U>(_func: F) -> FilterFn<F> +where + F: Fn() -> U, +{ + unimplemented!() +} +struct FilterFn<F> { + _func: F, +} +impl<F, U> Filter for FilterFn<F> +where + F: Fn() -> U, + U: TryFuture, + U::Ok: Send, +{ + type Extract = U::Ok; + type Future = Option<U>; +} +fn trace<F>(_func: F) -> Trace<F> +where + F: Fn(), +{ + unimplemented!() +} +struct Trace<F> { + _func: F, +} +impl<FN, F> Wrap<F> for Trace<FN> { + type Wrapped = WithTrace<FN, F>; +} +struct WithTrace<FN, F> { + _filter: F, + _trace: FN, +} +impl<FN, F> Filter for WithTrace<FN, F> +where + F: Filter, +{ + type Extract = (); + type Future = (F::Future, fn(F::Extract)); +} +trait Func<Args> { + type Output; +} +impl<F, R> Func<()> for F +where + F: Fn() -> R, +{ + type Output = R; +} +fn main() { + let make_service = make_service_fn(|_| { + let tracer = trace(|| unimplemented!()); + let filter = make_filter_fn(|| std::future::ready(Some(()))) + .map(|| "Hello, world") + .wrap_with(tracer); + let svc = service(filter); + std::future::ready(Some(svc)) + }); + let mut server = serve(make_service); + server.serve(); +} diff --git a/tests/ui/transmutability/arrays/huge-len.stderr b/tests/ui/transmutability/arrays/huge-len.stderr index 37160c5c959..3fc652f47c1 100644 --- a/tests/ui/transmutability/arrays/huge-len.stderr +++ b/tests/ui/transmutability/arrays/huge-len.stderr @@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `ExplicitlyPadded` --> $DIR/huge-len.rs:21:41 | LL | assert::is_maybe_transmutable::<(), ExplicitlyPadded>(); - | ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | ^^^^^^^^^^^^^^^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 @@ -17,7 +17,7 @@ error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` --> $DIR/huge-len.rs:24:55 | LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); - | ^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 diff --git a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr index e486928a445..b4cd70142c4 100644 --- a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -2,7 +2,7 @@ error[E0277]: `[String; 0]` cannot be safely transmuted into `()` --> $DIR/should_require_well_defined_layout.rs:25:52 | LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `[String; 0]` is not yet supported. + | ^^ analyzing the transmutability of `[String; 0]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -23,7 +23,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` --> $DIR/should_require_well_defined_layout.rs:26:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported. + | ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -44,7 +44,7 @@ error[E0277]: `[String; 1]` cannot be safely transmuted into `()` --> $DIR/should_require_well_defined_layout.rs:31:52 | LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `[String; 1]` is not yet supported. + | ^^ analyzing the transmutability of `[String; 1]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -65,7 +65,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` --> $DIR/should_require_well_defined_layout.rs:32:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported. + | ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -86,7 +86,7 @@ error[E0277]: `[String; 2]` cannot be safely transmuted into `()` --> $DIR/should_require_well_defined_layout.rs:37:52 | LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `[String; 2]` is not yet supported. + | ^^ analyzing the transmutability of `[String; 2]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -107,7 +107,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` --> $DIR/should_require_well_defined_layout.rs:38:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported. + | ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 diff --git a/tests/ui/transmutability/enums/niche_optimization.rs b/tests/ui/transmutability/enums/niche_optimization.rs new file mode 100644 index 00000000000..23f57ecad75 --- /dev/null +++ b/tests/ui/transmutability/enums/niche_optimization.rs @@ -0,0 +1,156 @@ +//@ check-pass +//! Checks that niche optimizations are encoded correctly. +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: true, + } + }> + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } +#[repr(u8)] enum V2 { V = 2 } +#[repr(u8)] enum V253 { V = 253 } +#[repr(u8)] enum V254 { V = 254 } +#[repr(u8)] enum V255 { V = 255 } + +fn bool() { + enum OptionLike { + A(bool), + B, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + + assert::is_transmutable::<bool, OptionLike>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V1, OptionLike>(); + assert::is_transmutable::<V2, OptionLike>(); +} + +fn one_niche() { + #[repr(u8)] + enum N1 { + S = 0, + E = 255 - 1, + } + + enum OptionLike { + A(N1), + B, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V254, OptionLike>(); + assert::is_transmutable::<V255, OptionLike>(); +} + +fn one_niche_alt() { + #[repr(u8)] + enum N1 { + S = 1, + E = 255 - 1, + } + + enum OptionLike { + A(N1), + B, + C, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V254, OptionLike>(); + assert::is_transmutable::<V255, OptionLike>(); +} + +fn two_niche() { + #[repr(u8)] + enum Niche { + S = 0, + E = 255 - 2, + } + + enum OptionLike { + A(Niche), + B, + C, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V253, OptionLike>(); + assert::is_transmutable::<V254, OptionLike>(); + assert::is_transmutable::<V255, OptionLike>(); +} + +fn no_niche() { + use std::mem::MaybeUninit; + + #[repr(u8)] + enum Niche { + S = 0, + E = 255 - 1, + } + + enum OptionLike { + A(Niche), + B, + C, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 2); + }; + + #[repr(C)] + struct Pair<T, U>(T, U); + + assert::is_transmutable::<V0, Niche>(); + assert::is_transmutable::<V254, Niche>(); + assert::is_transmutable::<Pair<V0, Niche>, OptionLike>(); + assert::is_transmutable::<Pair<V1, MaybeUninit<u8>>, OptionLike>(); + assert::is_transmutable::<Pair<V2, MaybeUninit<u8>>, OptionLike>(); +} diff --git a/tests/ui/transmutability/enums/repr/padding_differences.rs b/tests/ui/transmutability/enums/repr/padding_differences.rs new file mode 100644 index 00000000000..d0e1502b5e2 --- /dev/null +++ b/tests/ui/transmutability/enums/repr/padding_differences.rs @@ -0,0 +1,80 @@ +//@ check-pass +//! Adapted from https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html#explicit-repr-annotation-without-c-compatibility +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +use std::mem::MaybeUninit; + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: true, + } + }> + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } + +fn repr_u8() { + #[repr(u8)] + enum TwoCases { + A(u8, u16), // 0x00 INIT INIT INIT + B(u16), // 0x01 PADD INIT INIT + } + + const _: () = { + assert!(std::mem::size_of::<TwoCases>() == 4); + }; + + #[repr(C)] struct TwoCasesA(V0, u8, u8, u8); + #[repr(C)] struct TwoCasesB(V1, MaybeUninit<u8>, u8, u8); + + assert::is_transmutable::<TwoCasesA, TwoCases>(); + assert::is_transmutable::<TwoCasesB, TwoCases>(); + + assert::is_maybe_transmutable::<TwoCases, TwoCasesA>(); + assert::is_maybe_transmutable::<TwoCases, TwoCasesB>(); +} + +fn repr_c_u8() { + #[repr(C, u8)] + enum TwoCases { + A(u8, u16), // 0x00 PADD INIT PADD INIT INIT + B(u16), // 0x01 PADD INIT INIT PADD PADD + } + + const _: () = { + assert!(std::mem::size_of::<TwoCases>() == 6); + }; + + #[repr(C)] struct TwoCasesA(V0, MaybeUninit<u8>, u8, MaybeUninit<u8>, u8, u8); + #[repr(C)] struct TwoCasesB(V1, MaybeUninit<u8>, u8, u8, MaybeUninit<u8>, MaybeUninit<u8>); + + assert::is_transmutable::<TwoCasesA, TwoCases>(); + assert::is_transmutable::<TwoCasesB, TwoCases>(); + + assert::is_maybe_transmutable::<TwoCases, TwoCasesA>(); + assert::is_maybe_transmutable::<TwoCases, TwoCasesB>(); +} diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/enums/repr/should_handle_all.rs index 630e662b926..a8ec86fa40d 100644 --- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs +++ b/tests/ui/transmutability/enums/repr/should_handle_all.rs @@ -1,5 +1,4 @@ -//! An enum must have a well-defined layout to participate in a transmutation. - +//@ check-pass #![crate_type = "lib"] #![feature(repr128)] #![feature(transmutability)] @@ -21,23 +20,17 @@ mod assert { {} } -fn should_reject_repr_rust() { - fn void() { - enum repr_rust {} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted - } - +fn should_accept_repr_rust() { fn singleton() { enum repr_rust { V } - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn duplex() { enum repr_rust { A, B } - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } } @@ -116,7 +109,7 @@ fn should_accept_primitive_reprs() } } -fn should_accept_repr_C() { +fn should_accept_repr_c() { #[repr(C)] enum repr_c { V } assert::is_maybe_transmutable::<repr_c, ()>(); assert::is_maybe_transmutable::<i128, repr_c>(); diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr deleted file mode 100644 index 2a683de6a65..00000000000 --- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr +++ /dev/null @@ -1,135 +0,0 @@ -error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:27:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `void::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:28:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `void::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:33:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:34:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:39:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:40:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr index eeed8a62a2a..cabc7bcfef7 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr @@ -8,7 +8,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst` --> $DIR/unknown_src_field.rs:19:36 | LL | assert::is_transmutable::<Src, Dst>(); - | ^^^ `Dst` has an unknown layout + | ^^^ analyzing the transmutability of `Dst` is not yet supported | note: required by a bound in `is_transmutable` --> $DIR/unknown_src_field.rs:12:14 diff --git a/tests/ui/transmutability/maybeuninit.rs b/tests/ui/transmutability/maybeuninit.rs new file mode 100644 index 00000000000..77c3381c774 --- /dev/null +++ b/tests/ui/transmutability/maybeuninit.rs @@ -0,0 +1,43 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +use std::mem::MaybeUninit; + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + {} +} + +fn validity() { + // An initialized byte is a valid uninitialized byte. + assert::is_maybe_transmutable::<u8, MaybeUninit<u8>>(); + + // An uninitialized byte is never a valid initialized byte. + assert::is_maybe_transmutable::<MaybeUninit<u8>, u8>(); //~ ERROR: cannot be safely transmuted +} + +fn padding() { + #[repr(align(8))] + struct Align8; + + #[repr(u8)] + enum ImplicitlyPadded { + A(Align8), + } + + #[repr(u8)] + enum V0 { + V0 = 0, + } + + #[repr(C)] + struct ExplicitlyPadded(V0, MaybeUninit<[u8; 7]>); + + assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>(); + assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>(); +} diff --git a/tests/ui/transmutability/maybeuninit.stderr b/tests/ui/transmutability/maybeuninit.stderr new file mode 100644 index 00000000000..be7dcaf35ea --- /dev/null +++ b/tests/ui/transmutability/maybeuninit.stderr @@ -0,0 +1,18 @@ +error[E0277]: `MaybeUninit<u8>` cannot be safely transmuted into `u8` + --> $DIR/maybeuninit.rs:21:54 + | +LL | assert::is_maybe_transmutable::<MaybeUninit<u8>, u8>(); + | ^^ at least one value of `MaybeUninit<u8>` isn't a bit-valid value of `u8` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/maybeuninit.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/references/unsafecell.rs b/tests/ui/transmutability/references/unsafecell.rs new file mode 100644 index 00000000000..a8a1f969fb4 --- /dev/null +++ b/tests/ui/transmutability/references/unsafecell.rs @@ -0,0 +1,47 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +use std::cell::UnsafeCell; + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + {} +} + +fn value_to_value() { + // We accept value-to-value transmutations of `UnsafeCell`-containing types, + // because owning a value implies exclusive access. + assert::is_maybe_transmutable::<UnsafeCell<u8>, u8>(); + assert::is_maybe_transmutable::<u8, UnsafeCell<u8>>(); + assert::is_maybe_transmutable::<UnsafeCell<u8>, UnsafeCell<u8>>(); +} + +fn ref_to_ref() { + // We forbid `UnsafeCell`-containing ref-to-ref transmutations, because the + // two types may use different, incompatible synchronization strategies. + assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted + + assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted +} + +fn mut_to_mut() { + // `UnsafeCell` does't matter for `&mut T` to `&mut U`, since exclusive + // borrows can't be used for shared access. + assert::is_maybe_transmutable::<&'static mut u8, &'static mut UnsafeCell<u8>>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static mut u8>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static mut UnsafeCell<u8>>(); +} + +fn mut_to_ref() { + // We don't care about `UnsafeCell` for transmutations in the form `&mut T + // -> &U`, because downgrading a `&mut T` to a `&U` deactivates `&mut T` for + // the lifetime of `&U`. + assert::is_maybe_transmutable::<&'static mut u8, &'static UnsafeCell<u8>>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static u8>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static UnsafeCell<u8>>(); +} diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr new file mode 100644 index 00000000000..651eb8ceb26 --- /dev/null +++ b/tests/ui/transmutability/references/unsafecell.stderr @@ -0,0 +1,33 @@ +error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell<u8>` + --> $DIR/unsafecell.rs:27:50 + | +LL | assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/unsafecell.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `&UnsafeCell<u8>` cannot be safely transmuted into `&UnsafeCell<u8>` + --> $DIR/unsafecell.rs:29:62 + | +LL | assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/unsafecell.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/structs/repr/should_handle_all.rs index 2e673601baf..52c24eecf12 100644 --- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs +++ b/tests/ui/transmutability/structs/repr/should_handle_all.rs @@ -1,3 +1,4 @@ +//@ check-pass //! A struct must have a well-defined layout to participate in a transmutation. #![crate_type = "lib"] @@ -20,47 +21,47 @@ mod assert { {} } -fn should_reject_repr_rust() +fn should_accept_repr_rust() { fn unit() { struct repr_rust; - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn tuple() { struct repr_rust(); - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn braces() { struct repr_rust{} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn aligned() { #[repr(align(1))] struct repr_rust{} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn packed() { #[repr(packed)] struct repr_rust{} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn nested() { struct repr_rust; #[repr(C)] struct repr_c(repr_rust); - assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_c, ()>(); + assert::is_maybe_transmutable::<u128, repr_c>(); } } -fn should_accept_repr_C() +fn should_accept_repr_c() { fn unit() { #[repr(C)] struct repr_c; diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr deleted file mode 100644 index 77788f72c21..00000000000 --- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr +++ /dev/null @@ -1,267 +0,0 @@ -error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:27:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:28:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:33:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:34:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:39:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:40:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:45:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:46:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:51:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `packed::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:52:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `packed::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:58:49 - | -LL | assert::is_maybe_transmutable::<repr_c, ()>(); - | ^^ analyzing the transmutability of `nested::repr_c` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` - --> $DIR/should_require_well_defined_layout.rs:59:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_c>(); - | ^^^^^^ analyzing the transmutability of `nested::repr_c` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error: aborting due to 12 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs index 4c285a616b3..64110753832 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -22,4 +22,5 @@ fn should_pad_explicitly_packed_field() { //~^ ERROR: recursive type assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); + //~^ ERROR: cannot be safely transmuted } diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index 7fb051f6625..ebfb5361143 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -15,7 +15,22 @@ error[E0391]: cycle detected when computing layout of `should_pad_explicitly_pac = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::BikeshedIntrinsicFrom<should_pad_explicitly_packed_field::ExplicitlyPadded, core::mem::transmutability::Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` = 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 +error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` + --> $DIR/transmute_infinitely_recursive_type.rs:24:55 + | +LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); + | ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/transmute_infinitely_recursive_type.rs:14:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0072, E0391. +Some errors have detailed explanations: E0072, E0277, E0391. For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/transmutability/transmute-padding-ice.rs b/tests/ui/transmutability/transmute-padding-ice.rs index 3f3f75bc086..f5935a0009e 100644 --- a/tests/ui/transmutability/transmute-padding-ice.rs +++ b/tests/ui/transmutability/transmute-padding-ice.rs @@ -1,7 +1,13 @@ +//@ check-pass +//! This UI test was introduced as check-fail by a buggy bug-fix for an ICE. In +//! fact, this transmutation should be valid. + #![crate_type = "lib"] #![feature(transmutability)] #![allow(dead_code)] +use std::mem::size_of; + mod assert { use std::mem::{Assume, BikeshedIntrinsicFrom}; @@ -22,6 +28,7 @@ fn test() { #[repr(C)] struct B(u8, u8); + assert_eq!(size_of::<A>(), size_of::<B>()); + assert::is_maybe_transmutable::<B, A>(); - //~^ ERROR cannot be safely transmuted } diff --git a/tests/ui/transmutability/transmute-padding-ice.stderr b/tests/ui/transmutability/transmute-padding-ice.stderr deleted file mode 100644 index 4c121d463c6..00000000000 --- a/tests/ui/transmutability/transmute-padding-ice.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: `B` cannot be safely transmuted into `A` - --> $DIR/transmute-padding-ice.rs:25:40 - | -LL | assert::is_maybe_transmutable::<B, A>(); - | ^ the size of `B` is smaller than the size of `A` - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/transmute-padding-ice.rs:10:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom< - | ______________^ -LL | | Src, -LL | | { Assume { alignment: true, lifetimes: true, safety: true, validity: true } }, -LL | | >, - | |_________^ required by this bound in `is_maybe_transmutable` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/uninhabited.rs b/tests/ui/transmutability/uninhabited.rs new file mode 100644 index 00000000000..b61b110f6a1 --- /dev/null +++ b/tests/ui/transmutability/uninhabited.rs @@ -0,0 +1,71 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: true, + lifetimes: true, + safety: true, + validity: true, + } + }> + {} +} + +fn void() { + enum Void {} + + // This transmutation is vacuously acceptable; since one cannot construct a + // `Void`, unsoundness cannot directly arise from transmuting a void into + // anything else. + assert::is_maybe_transmutable::<Void, u128>(); + + assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted +} + +// Non-ZST uninhabited types are, nonetheless, uninhabited. +fn yawning_void() { + enum Void {} + + struct YawningVoid(Void, u128); + + const _: () = { + assert!(std::mem::size_of::<YawningVoid>() == std::mem::size_of::<u128>()); + // Just to be sure the above constant actually evaluated: + assert!(false); //~ ERROR: evaluation of constant value failed + }; + + // This transmutation is vacuously acceptable; since one cannot construct a + // `Void`, unsoundness cannot directly arise from transmuting a void into + // anything else. + assert::is_maybe_transmutable::<YawningVoid, u128>(); + + assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted +} + +// References to uninhabited types are, logically, uninhabited, but for layout +// purposes are not ZSTs, and aren't treated as uninhabited when they appear in +// enum variants. +fn distant_void() { + enum Void {} + + enum DistantVoid { + A(&'static Void) + } + + const _: () = { + assert!(std::mem::size_of::<DistantVoid>() == std::mem::size_of::<usize>()); + // Just to be sure the above constant actually evaluated: + assert!(false); //~ ERROR: evaluation of constant value failed + }; + + assert::is_maybe_transmutable::<DistantVoid, ()>(); + assert::is_maybe_transmutable::<DistantVoid, &'static Void>(); + assert::is_maybe_transmutable::<u128, DistantVoid>(); //~ ERROR: cannot be safely transmuted +} diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr new file mode 100644 index 00000000000..60219b0f263 --- /dev/null +++ b/tests/ui/transmutability/uninhabited.stderr @@ -0,0 +1,86 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/uninhabited.rs:41:9 + | +LL | assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:41:9 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/uninhabited.rs:65:9 + | +LL | assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:65:9 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `()` cannot be safely transmuted into `void::Void` + --> $DIR/uninhabited.rs:29:41 + | +LL | assert::is_maybe_transmutable::<(), Void>(); + | ^^^^ `void::Void` is uninhabited + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/uninhabited.rs:10:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { + | ______________^ +LL | | Assume { +LL | | alignment: true, +LL | | lifetimes: true, +... | +LL | | } +LL | | }> + | |__________^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `()` cannot be safely transmuted into `yawning_void::Void` + --> $DIR/uninhabited.rs:49:41 + | +LL | assert::is_maybe_transmutable::<(), Void>(); + | ^^^^ `yawning_void::Void` is uninhabited + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/uninhabited.rs:10:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { + | ______________^ +LL | | Assume { +LL | | alignment: true, +LL | | lifetimes: true, +... | +LL | | } +LL | | }> + | |__________^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` + --> $DIR/uninhabited.rs:70:43 + | +LL | assert::is_maybe_transmutable::<u128, DistantVoid>(); + | ^^^^^^^^^^^ at least one value of `u128` isn't a bit-valid value of `DistantVoid` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/uninhabited.rs:10:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { + | ______________^ +LL | | Assume { +LL | | alignment: true, +LL | | lifetimes: true, +... | +LL | | } +LL | | }> + | |__________^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0080, E0277. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/transmutability/unions/repr/should_handle_align.rs b/tests/ui/transmutability/unions/repr/should_handle_align.rs index 8668cca3cb5..ba4e904e161 100644 --- a/tests/ui/transmutability/unions/repr/should_handle_align.rs +++ b/tests/ui/transmutability/unions/repr/should_handle_align.rs @@ -25,13 +25,13 @@ fn should_pad_explicitly_aligned_field() { #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 } - #[repr(C)] + #[repr(align(1))] pub union Uninit { a: (), b: V1u8, } - #[repr(C, align(2))] + #[repr(align(2))] pub union align_2 { a: V0u8, } diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/unions/repr/should_handle_all.rs index 8495b0ea88f..85d48dd9b7f 100644 --- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs +++ b/tests/ui/transmutability/unions/repr/should_handle_all.rs @@ -1,7 +1,7 @@ -//! A struct must have a well-defined layout to participate in a transmutation. +//@ check-pass #![crate_type = "lib"] -#![feature(transmutability)] +#![feature(transmutability, transparent_unions)] #![allow(dead_code, incomplete_features, non_camel_case_types)] mod assert { @@ -20,17 +20,17 @@ mod assert { {} } -fn should_reject_repr_rust() +fn should_accept_repr_rust() { union repr_rust { a: u8 } - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } -fn should_accept_repr_C() +fn should_accept_repr_c() { #[repr(C)] union repr_c { @@ -41,3 +41,15 @@ fn should_accept_repr_C() assert::is_maybe_transmutable::<repr_c, ()>(); assert::is_maybe_transmutable::<u128, repr_c>(); } + + +fn should_accept_transparent() +{ + #[repr(transparent)] + union repr_transparent { + a: u8 + } + + assert::is_maybe_transmutable::<repr_transparent, ()>(); + assert::is_maybe_transmutable::<u128, repr_transparent>(); +} diff --git a/tests/ui/transmutability/unions/repr/should_handle_packed.rs b/tests/ui/transmutability/unions/repr/should_handle_packed.rs index 4af6c1d3a61..fc06eba4353 100644 --- a/tests/ui/transmutability/unions/repr/should_handle_packed.rs +++ b/tests/ui/transmutability/unions/repr/should_handle_packed.rs @@ -27,7 +27,6 @@ fn should_pad_explicitly_packed_field() { #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 } #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 } - #[repr(C)] pub union Uninit { a: (), b: V1u8, diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr deleted file mode 100644 index bec07f13103..00000000000 --- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:29:48 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:30:43 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, { - | ______________^ -LL | | Assume { -LL | | alignment: true, -LL | | lifetimes: true, -... | -LL | | } -LL | | }> - | |__________^ required by this bound in `is_maybe_transmutable` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr b/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr index e48d48a7271..4efb883ac74 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr +++ b/tests/ui/trivial-bounds/trivial-bounds-leak-copy.stderr @@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*t` which is behind a shared reference | LL | *t | ^^ move occurs because `*t` has type `String`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL - *t +LL + t.clone() + | error: aborting due to 1 previous error diff --git a/tests/ui/try-block/try-block-bad-lifetime.stderr b/tests/ui/try-block/try-block-bad-lifetime.stderr index 28941cb0a9e..6f693295357 100644 --- a/tests/ui/try-block/try-block-bad-lifetime.stderr +++ b/tests/ui/try-block/try-block-bad-lifetime.stderr @@ -34,6 +34,11 @@ LL | Err(k) ?; ... LL | ::std::mem::drop(k); | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Err(k.clone()) ?; + | ++++++++ error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-bad-lifetime.rs:32:9 diff --git a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs deleted file mode 100644 index ae463b6ef5b..00000000000 --- a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(type_alias_impl_trait)] - -//@ check-pass - -type Foo = impl Fn() -> Foo; - -fn foo() -> Foo { - foo -} - -fn main() {} 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 deleted file mode 100644 index 1c36fda4ae1..00000000000 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ /dev/null @@ -1,23 +0,0 @@ -note: no errors encountered even though delayed bugs were created - -note: those delayed bugs will now be shown as internal compiler errors - -error: internal compiler error: {OpaqueTypeKey { def_id: DefId(get_rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }) } }} - | - = - - -error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(get_rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }))), bound_vars: [] } } } - --> $DIR/rpit_tait_equality_in_canonical_query.rs:32:5 - | -LL | query(get_rpit); - | ^^^^^^^^^^^^^^^ - | - - --> $DIR/rpit_tait_equality_in_canonical_query.rs:32:5 - | -LL | query(get_rpit); - | ^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs index 7524cebf9e6..6f50703aca2 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs @@ -8,17 +8,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass - -//@[current] known-bug: #108498 -//@[current] failure-status: 101 -//@[current] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId(" -//@[current] normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> "" -//@[current] normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> "" -//@[current] normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> "" -//@[current] normalize-stderr-test: "(?m)note: delayed at.*$" -> "" -//@[current] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> "" -//@[current] normalize-stderr-test: "(?m)^ *at .*\n" -> "" +//@ check-pass #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs index e5e7fb677ed..19986247d40 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs @@ -1,12 +1,10 @@ #![feature(type_alias_impl_trait)] +//@ known-bug: #109268 type Foo = impl Fn() -> Foo; -//~^ ERROR: unconstrained opaque type fn crash(x: Foo) -> Foo { x } -fn main() { - -} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr new file mode 100644 index 00000000000..ee8922b673e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `<Foo as FnOnce<()>>::Output == Foo` + --> $DIR/type-alias-impl-trait-with-cycle-error-1.rs:6:21 + | +LL | fn crash(x: Foo) -> Foo { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs index 7c7a1b405bc..761cc83af51 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs @@ -1,11 +1,11 @@ #![feature(type_alias_impl_trait)] +//@ known-bug: #109268 pub trait Bar<T> { type Item; } type Foo = impl Bar<Foo, Item = Foo>; -//~^ ERROR: unconstrained opaque type fn crash(x: Foo) -> Foo { x diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr new file mode 100644 index 00000000000..3d0f1d30ca2 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `<Foo as Bar<Foo>>::Item == Foo` + --> $DIR/type-alias-impl-trait-with-cycle-error-2.rs:10:21 + | +LL | fn crash(x: Foo) -> Foo { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs new file mode 100644 index 00000000000..52942afd639 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] +//@ known-bug: #109268 + +type Foo<'a> = impl Fn() -> Foo<'a>; + +fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> { + x +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr new file mode 100644 index 00000000000..675689bac42 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `<Foo<'_> as FnOnce<()>>::Output == Foo<'a>` + --> $DIR/type-alias-impl-trait-with-cycle-error-3.rs:6:40 + | +LL | fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> { + | ^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs new file mode 100644 index 00000000000..e866b45a8e6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] +//@ known-bug: trait-system-refactor-initiative#43 + +trait Id { + type Assoc; +} +impl<T> Id for T { + type Assoc = T; +} + +type Ty +where + Ty: Id<Assoc = Ty>, += impl Sized; +fn define() -> Ty {} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr new file mode 100644 index 00000000000..aedb78bf5e7 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr @@ -0,0 +1,39 @@ +error[E0275]: overflow evaluating the requirement `Ty: Id` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:11:1 + | +LL | type Ty + | ^^^^^^^ + | +note: required by a bound on the type alias `Ty` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 + | +LL | Ty: Id<Assoc = Ty>, + | ^^^^^^^^^^^^^^ required by this bound + +error[E0275]: overflow evaluating the requirement `Ty: Id` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:19 + | +LL | fn define() -> Ty {} + | ^^ + | +note: required by a bound on the type alias `Ty` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 + | +LL | Ty: Id<Assoc = Ty>, + | ^^^^^^^^^^^^^^ required by this bound + +error[E0275]: overflow evaluating the requirement `Ty: Id` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16 + | +LL | fn define() -> Ty {} + | ^^ + | +note: required by a bound on the type alias `Ty` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 + | +LL | Ty: Id<Assoc = Ty>, + | ^^^^^^^^^^^^^^ required by this bound + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr deleted file mode 100644 index 3d43fbe0dbc..00000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:12 - | -LL | type Foo = impl Fn() -> Foo; - | ^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - -error: aborting due to 1 previous error - diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr deleted file mode 100644 index e2dc887989b..00000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:12 - | -LL | type Foo = impl Bar<Foo, Item = Foo>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - -error: aborting due to 1 previous error - diff --git a/tests/ui/type-inference/or_else-multiple-type-params.stderr b/tests/ui/type-inference/or_else-multiple-type-params.stderr index d1bbe308ed3..3176a2d490e 100644 --- a/tests/ui/type-inference/or_else-multiple-type-params.stderr +++ b/tests/ui/type-inference/or_else-multiple-type-params.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Result<Child, F>` +error[E0282]: type annotations needed for `Result<Child, _>` --> $DIR/or_else-multiple-type-params.rs:7:18 | LL | .or_else(|err| { diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs new file mode 100644 index 00000000000..8ad042eeba6 --- /dev/null +++ b/tests/ui/type/pattern_types/bad_pat.rs @@ -0,0 +1,14 @@ +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +type NonNullU32_2 = pattern_type!(u32 is 1..=); +//~^ ERROR: inclusive range with no end +type Positive2 = pattern_type!(i32 is 0..=); +//~^ ERROR: inclusive range with no end +type Wild = pattern_type!(() is _); +//~^ ERROR: wildcard patterns are not permitted for pattern types + +fn main() {} diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr new file mode 100644 index 00000000000..4f0f0bc9742 --- /dev/null +++ b/tests/ui/type/pattern_types/bad_pat.stderr @@ -0,0 +1,25 @@ +error[E0586]: inclusive range with no end + --> $DIR/bad_pat.rs:7:43 + | +LL | type NonNullU32_2 = pattern_type!(u32 is 1..=); + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error[E0586]: inclusive range with no end + --> $DIR/bad_pat.rs:9:40 + | +LL | type Positive2 = pattern_type!(i32 is 0..=); + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error: "wildcard patterns are not permitted for pattern types" + --> $DIR/bad_pat.rs:11:33 + | +LL | type Wild = pattern_type!(() is _); + | ^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0586`. diff --git a/tests/ui/type/pattern_types/const_generics.rs b/tests/ui/type/pattern_types/const_generics.rs new file mode 100644 index 00000000000..5bc6fd54e0f --- /dev/null +++ b/tests/ui/type/pattern_types/const_generics.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +trait Foo {} + +impl<const START: u32, const END: u32> Foo for pattern_type!(u32 is START..=END) {} + +fn main() {} diff --git a/tests/ui/type/pattern_types/derives.noimpl.stderr b/tests/ui/type/pattern_types/derives.noimpl.stderr new file mode 100644 index 00000000000..9450e575344 --- /dev/null +++ b/tests/ui/type/pattern_types/derives.noimpl.stderr @@ -0,0 +1,14 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives.rs:14:20 + | +LL | #[derive(Clone, Copy, PartialEq)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + | + = note: this error originates in the derive macro `PartialEq` (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 E0369`. diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs new file mode 100644 index 00000000000..b8b53e61102 --- /dev/null +++ b/tests/ui/type/pattern_types/derives.rs @@ -0,0 +1,20 @@ +//! Check that pattern types don't implement traits of their base automatically + +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +#[derive(Clone, Copy, PartialEq)] +#[repr(transparent)] +struct Nanoseconds(NanoI32); +//~^ ERROR: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + +type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999); + +fn main() { + let x = Nanoseconds(unsafe { std::mem::transmute(42) }); + let y = x.clone(); + if y == x {} +} diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr new file mode 100644 index 00000000000..1d4d3fc55c3 --- /dev/null +++ b/tests/ui/type/pattern_types/derives.stderr @@ -0,0 +1,14 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + | + = note: this error originates in the derive macro `PartialEq` (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 E0369`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs new file mode 100644 index 00000000000..3c507a9669d --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Zno-analysis + +use std::pat::pattern_type; + +type NonNullU32 = pattern_type!(u32 is 1..); +//~^ use of unstable library feature 'core_pattern_type' +type Percent = pattern_type!(u32 is 0..=100); +//~^ use of unstable library feature 'core_pattern_type' +type Negative = pattern_type!(i32 is ..=0); +//~^ use of unstable library feature 'core_pattern_type' +type Positive = pattern_type!(i32 is 0..); +//~^ use of unstable library feature 'core_pattern_type' +type Always = pattern_type!(Option<u32> is Some(_)); +//~^ use of unstable library feature 'core_pattern_type' diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr new file mode 100644 index 00000000000..6f74b89d224 --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr @@ -0,0 +1,48 @@ +error[E0658]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:5:19 + | +LL | type NonNullU32 = pattern_type!(u32 is 1..); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_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]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:7:16 + | +LL | type Percent = pattern_type!(u32 is 0..=100); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_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]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:9:17 + | +LL | type Negative = pattern_type!(i32 is ..=0); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_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]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:11:17 + | +LL | type Positive = pattern_type!(i32 is 0..); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_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]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:13:15 + | +LL | type Always = pattern_type!(Option<u32> is Some(_)); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_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 + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs new file mode 100644 index 00000000000..d7b3ea58e02 --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Zno-analysis +//@ check-pass + +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +type NonNullU32 = pattern_type!(u32 is 1..); +type Percent = pattern_type!(u32 is 0..=100); +type Negative = pattern_type!(i32 is ..=0); +type Positive = pattern_type!(i32 is 0..); +type Always = pattern_type!(Option<u32> is Some(_)); diff --git a/tests/ui/type/pattern_types/macros.active.stderr b/tests/ui/type/pattern_types/macros.active.stderr new file mode 100644 index 00000000000..002e944fe2e --- /dev/null +++ b/tests/ui/type/pattern_types/macros.active.stderr @@ -0,0 +1,10 @@ +error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments + --> $DIR/macros.rs:10:12 + | +LL | ($t:ty is $p:pat) => {}; + | ^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 1 previous error + diff --git a/tests/ui/type/pattern_types/macros.gated.stderr b/tests/ui/type/pattern_types/macros.gated.stderr new file mode 100644 index 00000000000..002e944fe2e --- /dev/null +++ b/tests/ui/type/pattern_types/macros.gated.stderr @@ -0,0 +1,10 @@ +error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments + --> $DIR/macros.rs:10:12 + | +LL | ($t:ty is $p:pat) => {}; + | ^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 1 previous error + diff --git a/tests/ui/type/pattern_types/macros.rs b/tests/ui/type/pattern_types/macros.rs new file mode 100644 index 00000000000..fd5fe257e8e --- /dev/null +++ b/tests/ui/type/pattern_types/macros.rs @@ -0,0 +1,15 @@ +//@ revisions: gated active + +#![cfg_attr(active, feature(pattern_types))] +#![allow(incomplete_features)] + +// Check that pattern types do not affect existing macros. +// They don't, because pattern types don't have surface syntax. + +macro_rules! foo { + ($t:ty is $p:pat) => {}; //~ ERROR `$t:ty` is followed by `is`, which is not allowed for `ty` fragments +} + +fn main() { + foo!(u32 is 1..) +} diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs new file mode 100644 index 00000000000..d1fd055dbab --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns.rs @@ -0,0 +1,23 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" + +use std::pat::pattern_type; + +#[rustc_layout(debug)] +type X = std::num::NonZeroU32; //~ ERROR layout_of +#[rustc_layout(debug)] +type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of +#[rustc_layout(debug)] +type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of +#[rustc_layout(debug)] +type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of +#[rustc_layout(debug)] +struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of + +fn main() { + let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(42_u32) }; +} diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr new file mode 100644 index 00000000000..8465e1b7ff2 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -0,0 +1,343 @@ +error: layout_of(NonZero<u32>) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:11:1 + | +LL | type X = std::num::NonZeroU32; + | ^^^^^^ + +error: layout_of((u32) is 1..=) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:13:1 + | +LL | type Y = pattern_type!(u32 is 1..); + | ^^^^^^ + +error: layout_of(Option<(u32) is 1..=>) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + tag_encoding: Niche { + untagged_variant: 1, + niche_variants: 0..=0, + niche_start: 0, + }, + tag_field: 0, + variants: [ + Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:15:1 + | +LL | type Z = Option<pattern_type!(u32 is 1..)>; + | ^^^^^^ + +error: layout_of(Option<NonZero<u32>>) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + tag_encoding: Niche { + untagged_variant: 1, + niche_variants: 0..=0, + niche_start: 0, + }, + tag_field: 0, + variants: [ + Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:17:1 + | +LL | type A = Option<std::num::NonZeroU32>; + | ^^^^^^ + +error: layout_of(NonZeroU32New) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:19:1 + | +LL | struct NonZeroU32New(pattern_type!(u32 is 1..)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs new file mode 100644 index 00000000000..9653a744c41 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs @@ -0,0 +1,30 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types can have traits implemented for them if +//! their base type is a local type. + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); + +impl Y { + //~^ ERROR cannot define inherent `impl` + fn foo() {} +} + +struct MyStruct<T>(T); + +impl MyStruct<Y> { + fn foo() {} +} + +struct Wrapper(Y); + +impl Wrapper { + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr new file mode 100644 index 00000000000..784ebb0c9f0 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr @@ -0,0 +1,16 @@ +error[E0390]: cannot define inherent `impl` for primitive types outside of `core` + --> $DIR/range_patterns_inherent_impls.rs:13:1 + | +LL | impl Y { + | ^^^^^^ + | + = help: consider moving this inherent impl into `core` if possible +help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items + --> $DIR/range_patterns_inherent_impls.rs:15:5 + | +LL | fn foo() {} + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0390`. diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs new file mode 100644 index 00000000000..f8c9af86281 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs @@ -0,0 +1,19 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types can have local traits +//! implemented for them. + +//@ check-pass + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); + +trait Trait {} + +impl Trait for Y {} + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs new file mode 100644 index 00000000000..acde4580c1b --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs @@ -0,0 +1,16 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types can have local traits +//! implemented for them. + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); + +impl Eq for Y {} +//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr new file mode 100644 index 00000000000..41f42455bde --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr @@ -0,0 +1,14 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/range_patterns_trait_impls2.rs:13:1 + | +LL | impl Eq for Y {} + | ^^^^^^^^^^^^- + | | | + | | `(u32) is 1..=` is not defined in the current crate + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.rs b/tests/ui/type/pattern_types/range_patterns_unusable.rs new file mode 100644 index 00000000000..7cde44f4133 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable.rs @@ -0,0 +1,15 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! Some practical niche checks. + +use std::pat::pattern_type; + +type Z = Option<pattern_type!(u32 is 1..)>; + +fn main() { + let z: Z = Some(unsafe { std::mem::transmute(42_u32) }); + let _: Option<u32> = unsafe { std::mem::transmute(z) }; //~ ERROR: different sizes +} diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.stderr b/tests/ui/type/pattern_types/range_patterns_unusable.stderr new file mode 100644 index 00000000000..aa0e592684b --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/range_patterns_unusable.rs:14:35 + | +LL | let _: Option<u32> = unsafe { std::mem::transmute(z) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<(u32) is 1..=>` (32 bits) + = note: target type: `Option<u32>` (64 bits) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.rs b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs new file mode 100644 index 00000000000..bc1ab75429d --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs @@ -0,0 +1,16 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types don't have an `Add` impl. + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); +type Z = Option<pattern_type!(u32 is 1..)>; + +fn main() { + let x: Y = unsafe { std::mem::transmute(42_u32) }; + let x = x + 1_u32; //~ ERROR cannot add `u32` to `(u32) is 1..=` +} diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr new file mode 100644 index 00000000000..e52d899a703 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr @@ -0,0 +1,11 @@ +error[E0369]: cannot add `u32` to `(u32) is 1..=` + --> $DIR/range_patterns_unusable_math.rs:15:15 + | +LL | let x = x + 1_u32; + | - ^ ----- u32 + | | + | (u32) is 1..= + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs new file mode 100644 index 00000000000..7fe50423c51 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_usage.rs @@ -0,0 +1,26 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] +//@ check-pass + +//! check that pattern types can actually be part of code that compiles successfully. + +use std::pat::pattern_type; + +type X = std::num::NonZeroU32; +type Y = pattern_type!(u32 is 1..); +type Z = Option<pattern_type!(u32 is 1..)>; +struct NonZeroU32New(pattern_type!(u32 is 1..)); + +fn main() { + let x: Y = unsafe { std::mem::transmute(42_u32) }; + let z: Z = Some(unsafe { std::mem::transmute(42_u32) }); + match z { + Some(y) => { + let _: Y = y; + } + None => {} + } + let x: X = unsafe { std::mem::transmute(x) }; +} diff --git a/tests/ui/type/pattern_types/unimplemented_pat.rs b/tests/ui/type/pattern_types/unimplemented_pat.rs new file mode 100644 index 00000000000..c02160ff58a --- /dev/null +++ b/tests/ui/type/pattern_types/unimplemented_pat.rs @@ -0,0 +1,15 @@ +//! This test ensures we do not ICE for unimplemented +//! patterns unless the feature gate is enabled. + +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] + +use std::pat::pattern_type; + +type Always = pattern_type!(Option<u32> is Some(_)); +//~^ ERROR: pattern types are unstable + +type Binding = pattern_type!(Option<u32> is x); +//~^ ERROR: pattern types are unstable + +fn main() {} diff --git a/tests/ui/type/pattern_types/unimplemented_pat.stderr b/tests/ui/type/pattern_types/unimplemented_pat.stderr new file mode 100644 index 00000000000..481c6017dcc --- /dev/null +++ b/tests/ui/type/pattern_types/unimplemented_pat.stderr @@ -0,0 +1,23 @@ +error[E0658]: pattern types are unstable + --> $DIR/unimplemented_pat.rs:9:15 + | +LL | type Always = pattern_type!(Option<u32> is Some(_)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information + = help: add `#![feature(pattern_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[E0658]: pattern types are unstable + --> $DIR/unimplemented_pat.rs:12:16 + | +LL | type Binding = pattern_type!(Option<u32> is x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information + = help: add `#![feature(pattern_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: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/type/type-error-break-tail.stderr b/tests/ui/type/type-error-break-tail.stderr index 5ef522fee2a..81f8f52428d 100644 --- a/tests/ui/type/type-error-break-tail.stderr +++ b/tests/ui/type/type-error-break-tail.stderr @@ -8,7 +8,7 @@ LL | loop { LL | if false { break; } | ^^^^^ expected `i32`, found `()` | -help: give it a value of the expected type +help: give the `break` a value of the expected type | LL | if false { break 42; } | ++ diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed deleted file mode 100644 index dcb256de18f..00000000000 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed +++ /dev/null @@ -1,37 +0,0 @@ -//@ run-rustfix -#![allow(dead_code)] - -// https://github.com/rust-lang/rust/issues/112007 -fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { - if true { - writeln!(w, "`;?` here ->")?; - } else { - return writeln!(w, "but not here"); - //~^ ERROR mismatched types - }; - Ok(()) -} - -macro_rules! baz { - ($w: expr) => { - bar!($w) - } -} - -macro_rules! bar { - ($w: expr) => { - writeln!($w, "but not here") - //~^ ERROR mismatched types - } -} - -fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { - if true { - writeln!(w, "`;?` here ->")?; - } else { - return baz!(w); - }; - Ok(()) -} - -fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs index 58cd6cbf20c..7ec9f0d4cdb 100644 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs @@ -1,8 +1,16 @@ -//@ run-rustfix -#![allow(dead_code)] +// Check that we don't leak stdlib implementation details through suggestions. +// Also check that the suggestion provided tries as hard as it can to see through local macros. +// +// FIXME(jieyouxu): this test is NOT run-rustfix because this test contains conflicting +// MaybeIncorrect suggestions: +// +// 1. `return ... ;` +// 2. `?` +// +// when the suggestions are applied to the same file, it becomes uncompilable. // https://github.com/rust-lang/rust/issues/112007 -fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { +pub fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { @@ -25,7 +33,7 @@ macro_rules! bar { } } -fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { +pub fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { @@ -34,4 +42,4 @@ fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { Ok(()) } -fn main() {} +pub fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr index df2e06e8f3b..889d2c94d0c 100644 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:9:9 + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:17:9 | LL | / if true { LL | | writeln!(w, "`;?` here ->")?; @@ -21,9 +21,13 @@ help: you might have meant to return this value | LL | return writeln!(w, "but not here"); | ++++++ + +help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller + | +LL | writeln!(w, "but not here")? + | + error[E0308]: mismatched types - --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:32:9 + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:40:9 | LL | / if true { LL | | writeln!(w, "`;?` here ->")?; @@ -44,6 +48,10 @@ help: you might have meant to return this value | LL | return baz!(w); | ++++++ + +help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller + | +LL | writeln!($w, "but not here")? + | + error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/question-mark-operator-suggestion-span.rs b/tests/ui/typeck/question-mark-operator-suggestion-span.rs new file mode 100644 index 00000000000..7aea6e63dd1 --- /dev/null +++ b/tests/ui/typeck/question-mark-operator-suggestion-span.rs @@ -0,0 +1,22 @@ +// Check that we don't construct a span for `?` suggestions that point into non-local macros +// like into the stdlib where the user has no control over. +// +// FIXME(jieyouxu): this test is currently NOT run-rustfix because there are conflicting +// MaybeIncorrect suggestions: +// +// 1. adding `return ... ;`, and +// 2. adding `?`. +// +// When rustfix puts those together, the fixed file now contains uncompilable code. + +#![crate_type = "lib"] + +pub fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + writeln!(w, "but not here") + //~^ ERROR mismatched types + } + Ok(()) +} diff --git a/tests/ui/typeck/question-mark-operator-suggestion-span.stderr b/tests/ui/typeck/question-mark-operator-suggestion-span.stderr new file mode 100644 index 00000000000..089b3bcd198 --- /dev/null +++ b/tests/ui/typeck/question-mark-operator-suggestion-span.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/question-mark-operator-suggestion-span.rs:18:9 + | +LL | / if true { +LL | | writeln!(w, "`;?` here ->")?; +LL | | } else { +LL | | writeln!(w, "but not here") + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` +LL | | +LL | | } + | |_____- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result<(), std::fmt::Error>` + = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using a semicolon here + | +LL | }; + | + +help: you might have meant to return this value + | +LL | return writeln!(w, "but not here"); + | ++++++ + +help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller + | +LL | writeln!(w, "but not here")? + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/remove-semi-but-confused-char.rs b/tests/ui/typeck/remove-semi-but-confused-char.rs new file mode 100644 index 00000000000..ccc6f59344c --- /dev/null +++ b/tests/ui/typeck/remove-semi-but-confused-char.rs @@ -0,0 +1,11 @@ +// Ensures our "remove semicolon" suggestion isn't hardcoded with a character width, +// in case it was accidentally mixed up with a greek question mark. +// issue: rust-lang/rust#123607 + +pub fn square(num: i32) -> i32 { + //~^ ERROR mismatched types + num * num; + //~^ ERROR unknown start of token +} + +fn main() {} diff --git a/tests/ui/typeck/remove-semi-but-confused-char.stderr b/tests/ui/typeck/remove-semi-but-confused-char.stderr new file mode 100644 index 00000000000..2d0b53a60ce --- /dev/null +++ b/tests/ui/typeck/remove-semi-but-confused-char.stderr @@ -0,0 +1,25 @@ +error: unknown start of token: \u{37e} + --> $DIR/remove-semi-but-confused-char.rs:7:14 + | +LL | num * num; + | ^ + | +help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not + | +LL | num * num; + | ~ + +error[E0308]: mismatched types + --> $DIR/remove-semi-but-confused-char.rs:5:28 + | +LL | pub fn square(num: i32) -> i32 { + | ------ ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +LL | +LL | num * num; + | - help: remove this semicolon to return this value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/return_type_containing_closure.rs b/tests/ui/typeck/return_type_containing_closure.rs index 8b826daeede..b81cac0a58a 100644 --- a/tests/ui/typeck/return_type_containing_closure.rs +++ b/tests/ui/typeck/return_type_containing_closure.rs @@ -1,5 +1,5 @@ #[allow(unused)] -fn foo() { //~ HELP a return type might be missing here +fn foo() { //~ HELP try adding a return type vec!['a'].iter().map(|c| c) //~^ ERROR mismatched types [E0308] //~| NOTE expected `()`, found `Map<Iter<'_, char>, ...>` diff --git a/tests/ui/typeck/return_type_containing_closure.stderr b/tests/ui/typeck/return_type_containing_closure.stderr index ea9c74be362..3f14650a82c 100644 --- a/tests/ui/typeck/return_type_containing_closure.stderr +++ b/tests/ui/typeck/return_type_containing_closure.stderr @@ -10,10 +10,10 @@ help: consider using a semicolon here | LL | vec!['a'].iter().map(|c| c); | + -help: a return type might be missing here +help: try adding a return type | -LL | fn foo() -> _ { - | ++++ +LL | fn foo() -> impl Iterator<Item = &char> { + | ++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr index 9cfeb7a5d09..e466f94d0d8 100644 --- a/tests/ui/ufcs/bad-builder.stderr +++ b/tests/ui/ufcs/bad-builder.stderr @@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<Q>` consider using one of the followi Vec::<T>::with_capacity Vec::<T>::try_with_capacity Vec::<T>::from_raw_parts - and 4 others + and 6 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: there is an associated function `new` with a similar name | diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index bfa3061de08..cf4391311d0 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -7,6 +7,11 @@ LL | let f = to_fn(|| drop(x)); | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait | | | captured by this `Fn` closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let f = to_fn(|| drop(x.clone())); + | ++++++++ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:19:35 @@ -17,6 +22,11 @@ LL | let f = to_fn_mut(|| drop(x)); | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait | | | captured by this `FnMut` closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let f = to_fn_mut(|| drop(x.clone())); + | ++++++++ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:28:36 diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index 5a76ef3e875..058dbb1e220 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Option<T>` +error[E0282]: type annotations needed for `Option<_>` --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:8:9 | LL | let mut closure0 = None; diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed b/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed new file mode 100644 index 00000000000..76f4251daef --- /dev/null +++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed @@ -0,0 +1,31 @@ +// Verifies that MIR building for a call expression respects +// privacy when checking if a call return type is uninhabited. +//@ run-rustfix +#![allow(unreachable_code, unused_variables)] + +pub mod widget { + enum Unimplemented {} + pub struct Widget(Unimplemented); + + impl Widget { + pub fn new() -> Widget { + todo!(); + } + } + + pub fn f() { + let x: &mut u32; + Widget::new(); + // Ok. Widget type returned from new is known to be uninhabited + // and the following code is considered unreachable. + *x = 1; + } +} + +fn main() { + let y: &mut u32 = &mut 42; + widget::Widget::new(); + // Error. Widget type is not known to be uninhabited here, + // so the following code is considered reachable. + *y = 2; //~ ERROR E0381 +} diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.rs b/tests/ui/uninhabited/privately-uninhabited-mir-call.rs index 2764bb563d3..1eec57ae046 100644 --- a/tests/ui/uninhabited/privately-uninhabited-mir-call.rs +++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.rs @@ -1,5 +1,7 @@ // Verifies that MIR building for a call expression respects // privacy when checking if a call return type is uninhabited. +//@ run-rustfix +#![allow(unreachable_code, unused_variables)] pub mod widget { enum Unimplemented {} diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr b/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr index 5f2f02c99fb..9d0771ad79e 100644 --- a/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr +++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr @@ -1,5 +1,5 @@ error[E0381]: used binding `y` isn't initialized - --> $DIR/privately-uninhabited-mir-call.rs:28:5 + --> $DIR/privately-uninhabited-mir-call.rs:30:5 | LL | let y: &mut u32; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | *y = 2; | help: consider assigning a value | -LL | let y: &mut u32 = todo!(); +LL | let y: &mut u32 = &mut 42; | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr index c9a440a66cc..782fa63280e 100644 --- a/tests/ui/union/union-borrow-move-parent-sibling.stderr +++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr @@ -50,6 +50,11 @@ error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, Moc LL | let a = (u.x.0).0; | ^^^^^^^^^ move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait | +note: if `MockVec<u8>` implemented `Clone`, you could clone the value + --> $DIR/union-borrow-move-parent-sibling.rs:25:1 + | +LL | struct MockVec<T> { + | ^^^^^^^^^^^^^^^^^ help: consider borrowing here | LL | let a = &(u.x.0).0; diff --git a/tests/ui/union/union-move.stderr b/tests/ui/union/union-move.stderr index 47fb801a50e..5ebb2716e5a 100644 --- a/tests/ui/union/union-move.stderr +++ b/tests/ui/union/union-move.stderr @@ -16,6 +16,11 @@ LL | fn move_out<T>(x: T) {} | -------- ^ this parameter takes ownership of the value | | | in this function +note: if `U1` implemented `Clone`, you could clone the value + --> $DIR/union-move.rs:9:1 + | +LL | union U1 { + | ^^^^^^^^ error[E0382]: use of moved value: `x` --> $DIR/union-move.rs:42:18 @@ -35,6 +40,11 @@ LL | fn move_out<T>(x: T) {} | -------- ^ this parameter takes ownership of the value | | | in this function +note: if `U1` implemented `Clone`, you could clone the value + --> $DIR/union-move.rs:9:1 + | +LL | union U1 { + | ^^^^^^^^ error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait --> $DIR/union-move.rs:49:18 @@ -44,6 +54,11 @@ LL | move_out(x.f1_nocopy); | | | cannot move out of here | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait + | +help: consider cloning the value if the performance cost is acceptable + | +LL | move_out(x.f1_nocopy.clone()); + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-23649-1.rs b/tests/ui/unsized/issue-23649-1.rs index 1c4252b40c6..1c4252b40c6 100644 --- a/tests/ui/issues/issue-23649-1.rs +++ b/tests/ui/unsized/issue-23649-1.rs diff --git a/tests/ui/issues/issue-23649-2.rs b/tests/ui/unsized/issue-23649-2.rs index 4a953de1768..4a953de1768 100644 --- a/tests/ui/issues/issue-23649-2.rs +++ b/tests/ui/unsized/issue-23649-2.rs diff --git a/tests/ui/issues/issue-23649-3.rs b/tests/ui/unsized/issue-23649-3.rs index 524055d99b4..524055d99b4 100644 --- a/tests/ui/issues/issue-23649-3.rs +++ b/tests/ui/unsized/issue-23649-3.rs diff --git a/tests/ui/unused-crate-deps/deny-cmdline-json-silent.rs b/tests/ui/unused-crate-deps/deny-cmdline-json-silent.rs index f0f6d5b704d..d8c4382dfc5 100644 --- a/tests/ui/unused-crate-deps/deny-cmdline-json-silent.rs +++ b/tests/ui/unused-crate-deps/deny-cmdline-json-silent.rs @@ -2,7 +2,7 @@ //@ edition:2018 //@ check-pass -//@ compile-flags: -Dunused-crate-dependencies -Zunstable-options --json unused-externs-silent --error-format=json +//@ compile-flags: -Dunused-crate-dependencies --json unused-externs-silent --error-format=json //@ aux-crate:bar=bar.rs fn main() {} diff --git a/tests/ui/unused-crate-deps/deny-cmdline-json.rs b/tests/ui/unused-crate-deps/deny-cmdline-json.rs index aab53eb3775..1f5a2f08e6d 100644 --- a/tests/ui/unused-crate-deps/deny-cmdline-json.rs +++ b/tests/ui/unused-crate-deps/deny-cmdline-json.rs @@ -1,7 +1,7 @@ // Check for unused crate dep, json event, deny, expect compile failure //@ edition:2018 -//@ compile-flags: -Dunused-crate-dependencies -Zunstable-options --json unused-externs --error-format=json +//@ compile-flags: -Dunused-crate-dependencies --json unused-externs --error-format=json //@ aux-crate:bar=bar.rs fn main() {} diff --git a/tests/ui/unused-crate-deps/warn-cmdline-json.rs b/tests/ui/unused-crate-deps/warn-cmdline-json.rs index b23a9c8d5fb..68c4d873d67 100644 --- a/tests/ui/unused-crate-deps/warn-cmdline-json.rs +++ b/tests/ui/unused-crate-deps/warn-cmdline-json.rs @@ -2,7 +2,7 @@ //@ edition:2018 //@ check-pass -//@ compile-flags: -Wunused-crate-dependencies -Zunstable-options --json unused-externs --error-format=json +//@ compile-flags: -Wunused-crate-dependencies --json unused-externs --error-format=json //@ aux-crate:bar=bar.rs fn main() {} diff --git a/tests/ui/variance/leaking-unnameables.rs b/tests/ui/variance/leaking-unnameables.rs new file mode 100644 index 00000000000..e51d3779d34 --- /dev/null +++ b/tests/ui/variance/leaking-unnameables.rs @@ -0,0 +1,13 @@ +// Test variance computation doesn't explode when we leak unnameable +// types due to `-> _` recovery. + +pub struct Type<'a>(&'a ()); + +pub fn g() {} + +pub fn f<T>() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures + g +} + +fn main() {} diff --git a/tests/ui/variance/leaking-unnameables.stderr b/tests/ui/variance/leaking-unnameables.stderr new file mode 100644 index 00000000000..92afe952801 --- /dev/null +++ b/tests/ui/variance/leaking-unnameables.stderr @@ -0,0 +1,12 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/leaking-unnameables.rs:8:18 + | +LL | pub fn f<T>() -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `fn()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/variance/variance-issue-20533.rs b/tests/ui/variance/variance-issue-20533.rs index a2459f8730c..4c109608906 100644 --- a/tests/ui/variance/variance-issue-20533.rs +++ b/tests/ui/variance/variance-issue-20533.rs @@ -19,8 +19,15 @@ fn baz<'a, T>(_x: &'a T) -> Baked<'a> { Baked(PhantomData) } +fn bat(x: &AffineU32) -> &u32 { + &x.0 +} + struct AffineU32(u32); +#[derive(Clone)] +struct ClonableAffineU32(u32); + fn main() { { let a = AffineU32(1); @@ -40,4 +47,16 @@ fn main() { drop(a); //~ ERROR cannot move out of `a` drop(x); } + { + let a = AffineU32(1); + let x = bat(&a); + drop(a); //~ ERROR cannot move out of `a` + drop(x); + } + { + let a = ClonableAffineU32(1); + let x = foo(&a); + drop(a); //~ ERROR cannot move out of `a` + drop(x); + } } diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr index 258f67db5ce..4515d313ec0 100644 --- a/tests/ui/variance/variance-issue-20533.stderr +++ b/tests/ui/variance/variance-issue-20533.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/variance-issue-20533.rs:28:14 + --> $DIR/variance-issue-20533.rs:35:14 | LL | let a = AffineU32(1); | - binding `a` declared here @@ -9,9 +9,15 @@ LL | drop(a); | ^ move out of `a` occurs here LL | drop(x); | - borrow later used here + | +note: if `AffineU32` implemented `Clone`, you could clone the value + --> $DIR/variance-issue-20533.rs:26:1 + | +LL | struct AffineU32(u32); + | ^^^^^^^^^^^^^^^^ error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/variance-issue-20533.rs:34:14 + --> $DIR/variance-issue-20533.rs:41:14 | LL | let a = AffineU32(1); | - binding `a` declared here @@ -21,9 +27,15 @@ LL | drop(a); | ^ move out of `a` occurs here LL | drop(x); | - borrow later used here + | +note: if `AffineU32` implemented `Clone`, you could clone the value + --> $DIR/variance-issue-20533.rs:26:1 + | +LL | struct AffineU32(u32); + | ^^^^^^^^^^^^^^^^ error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/variance-issue-20533.rs:40:14 + --> $DIR/variance-issue-20533.rs:47:14 | LL | let a = AffineU32(1); | - binding `a` declared here @@ -33,7 +45,48 @@ LL | drop(a); | ^ move out of `a` occurs here LL | drop(x); | - borrow later used here + | +note: if `AffineU32` implemented `Clone`, you could clone the value + --> $DIR/variance-issue-20533.rs:26:1 + | +LL | struct AffineU32(u32); + | ^^^^^^^^^^^^^^^^ + +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/variance-issue-20533.rs:53:14 + | +LL | let a = AffineU32(1); + | - binding `a` declared here +LL | let x = bat(&a); + | -- borrow of `a` occurs here +LL | drop(a); + | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let x = bat(&a).clone(); + | ++++++++ + +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/variance-issue-20533.rs:59:14 + | +LL | let a = ClonableAffineU32(1); + | - binding `a` declared here +LL | let x = foo(&a); + | -- borrow of `a` occurs here +LL | drop(a); + | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let x = foo(&a); +LL + let x = foo(a.clone()); + | -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/version/version-info-flags.rs b/tests/ui/version/version-info-flags.rs new file mode 100644 index 00000000000..612113452c4 --- /dev/null +++ b/tests/ui/version/version-info-flags.rs @@ -0,0 +1,9 @@ +// Check that rustc accepts various version info flags. +//@ dont-check-compiler-stdout +//@ revisions: version verbose-version long-verbose-version +//@ check-pass +//@[version] compile-flags: -V +//@[verbose-version] compile-flags: -vV +//@[long-verbose-verison] compile-flags: --version --verbose + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 927852f0ca2..b96225c4520 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -536,7 +536,12 @@ cc = ["@Nadrieril"] message = "Some changes occurred in exhaustiveness checking" cc = ["@Nadrieril"] +[mentions."compiler/rustc_session/src/config/cfg.rs"] +message = "Some changes occurred in cfg and check-cfg configuration" +cc = ["@Urgau"] + [mentions."compiler/rustc_lint/src/context/diagnostics/check_cfg.rs"] +message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"] [mentions."library/core/src/intrinsics/simd.rs"] |
